Skip to contentSkip to conversation

pasemi_mac: Patches for 2.6.24

PATCH Applied Olof Johansson 2 participants 19 messages Oct 2, 2007 – Oct 3, 2007

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover pasemi_mac: Patches for 2.6.24

Hi,

This series of patches go on top of the previous fixes that were sent out and picked up.

It's a series of mostly feature-related changes, but also a couple of bugfixes:

[1/11] pasemi_mac: basic error checking
[2/11] pasemi_mac: fix bug in receive buffer dma mapping [3/11] pasemi_mac: rework ring management
[4/11] pasemi_mac: implement sg support
[5/11] pasemi_mac: workaround for erratum 5971 [6/11] pasemi_mac: add local skb alignment
[7/11] pasemi_mac: further performance tweaks [8/11] pasemi_mac: update todo list
[9/11] pasemi_mac: clear out old errors on interface open [10/11] pasemi_mac: use buffer index pointer in clean_rx() [11/11] pasemi_mac: enable iommu support

Thanks,

-Olof

#1 lore raw

PATCH 1/11 pasemi_mac: basic error checking

pasemi_mac: basic error checking

Add some rudimentary error checking to pasemi_mac.

drivers/net/pasemi_mac.c +41 -5
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -445,6 +445,38 @@ static void pasemi_mac_restart_tx_intr(s
 }
 
 
+static inline void pasemi_mac_rx_error(struct pasemi_mac *mac, u64 macrx)
+{
+	unsigned int rcmdsta, ccmdsta;
+
+	if (!netif_msg_rx_err(mac))
+		return;
+
+	rcmdsta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+	ccmdsta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+
+	printk(KERN_ERR "pasemi_mac: rx error. macrx %016lx, rx status %lx\n",
+		macrx, *mac->rx_status);
+
+	printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n",
+		rcmdsta, ccmdsta);
+}
+
+static inline void pasemi_mac_tx_error(struct pasemi_mac *mac, u64 mactx)
+{
+	unsigned int cmdsta;
+
+	if (!netif_msg_tx_err(mac))
+		return;
+
+	cmdsta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+
+	printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016lx, "\
+		"tx status 0x%016lx\n", mactx, *mac->tx_status);
+
+	printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta);
+}
+
 static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
 {
 	unsigned int n;
@@ -468,10 +500,13 @@ static int pasemi_mac_clean_rx(struct pa
 		prefetchw(dp);
 		macrx = dp->macrx;
 
+		if ((macrx & XCT_MACRX_E) ||
+		    (*mac->rx_status & PAS_STATUS_ERROR))
+			pasemi_mac_rx_error(mac, macrx);
+
 		if (!(macrx & XCT_MACRX_O))
 			break;
 
-
 		info = NULL;
 
 		/* We have to scan for our skb since there's no way
@@ -563,6 +598,10 @@ restart:
 	for (i = start; i < limit; i++) {
 		dp = &TX_DESC(mac, i);
 
+		if ((dp->mactx & XCT_MACTX_E) ||
+		    (*mac->tx_status & PAS_STATUS_ERROR))
+			pasemi_mac_tx_error(mac, dp->mactx);
+
 		if (unlikely(dp->mactx & XCT_MACTX_O))
 			/* Not yet transmitted */
 			break;
@@ -607,9 +646,6 @@ static irqreturn_t pasemi_mac_rx_intr(in
 	if (!(*mac->rx_status & PAS_STATUS_CAUSE_M))
 		return IRQ_NONE;
 
-	if (*mac->rx_status & PAS_STATUS_ERROR)
-		printk("rx_status reported error\n");
-
 	/* Don't reset packet count so it won't fire again but clear
 	 * all others.
 	 */
@@ -1230,7 +1266,7 @@ pasemi_mac_probe(struct pci_dev *pdev, c
 		dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
 			err);
 		goto out;
-	} else
+	} else if netif_msg_probe(mac)
 		printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
 		       "hw addr %s\n",
 		       dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
#2 lore raw

Re: [PATCH] [1/11] pasemi_mac: basic error checking

Quoted 5 lines · Olof Johansson

pasemi_mac: basic error checking

Add some rudimentary error checking to pasemi_mac.

applied 1-10

#3 lore raw

PATCH 2/11 pasemi_mac: fix bug in receive buffer dma mapping

In reply to Olof Johansson

pasemi_mac: fix bug in receive buffer dma mapping

skb->len isn't actually set to the size of the allocated skb, so don't try to use it when figuring out how much to map.

(This hasn't surfaced as a real bug because we effectively disable translation for the interface, but it still needs fixing for the future)

drivers/net/pasemi_mac.c +1 -1
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -396,7 +396,7 @@ static void pasemi_mac_replenish_rx_ring
 		if (unlikely(!skb))
 			break;
 
-		dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+		dma = pci_map_single(mac->dma_pdev, skb->data, BUF_SIZE,
 				     PCI_DMA_FROMDEVICE);
 
 		if (unlikely(dma_mapping_error(dma))) {
#4 lore raw

PATCH 3/11 pasemi_mac: rework ring management

In reply to Olof Johansson

pasemi_mac: rework ring management

Rework ring management, switching to an opaque ring format instead of the struct-based descriptor+pointer setup, since it will be needed for SG support.

drivers/net/pasemi_mac.c +102 -109
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -63,10 +63,10 @@
 	 NETIF_MSG_RX_ERR	| \
 	 NETIF_MSG_TX_ERR)
 
-#define TX_DESC(mac, num)	((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
-#define TX_DESC_INFO(mac, num)	((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
-#define RX_DESC(mac, num)	((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
-#define RX_DESC_INFO(mac, num)	((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define TX_RING(mac, num)	((mac)->tx->ring[(num) & (TX_RING_SIZE-1)])
+#define TX_RING_INFO(mac, num)	((mac)->tx->ring_info[(num) & (TX_RING_SIZE-1)])
+#define RX_RING(mac, num)	((mac)->rx->ring[(num) & (RX_RING_SIZE-1)])
+#define RX_RING_INFO(mac, num)	((mac)->rx->ring_info[(num) & (RX_RING_SIZE-1)])
 #define RX_BUFF(mac, num)	((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
 
 #define RING_USED(ring)		(((ring)->next_to_fill - (ring)->next_to_clean) \
@@ -174,22 +174,21 @@ static int pasemi_mac_setup_rx_resources
 	spin_lock_init(&ring->lock);
 
 	ring->size = RX_RING_SIZE;
-	ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+	ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
 				  RX_RING_SIZE, GFP_KERNEL);
 
-	if (!ring->desc_info)
-		goto out_desc_info;
+	if (!ring->ring_info)
+		goto out_ring_info;
 
 	/* Allocate descriptors */
-	ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
-					RX_RING_SIZE *
-					sizeof(struct pas_dma_xct_descr),
+	ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
+					RX_RING_SIZE * sizeof(u64),
 					&ring->dma, GFP_KERNEL);
 
-	if (!ring->desc)
-		goto out_desc;
+	if (!ring->ring)
+		goto out_ring_desc;
 
-	memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+	memset(ring->ring, 0, RX_RING_SIZE * sizeof(u64));
 
 	ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
 					   RX_RING_SIZE * sizeof(u64),
@@ -203,7 +202,7 @@ static int pasemi_mac_setup_rx_resources
 
 	write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id),
 			   PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
-			   PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+			   PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3));
 
 	write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id),
 			   PAS_DMA_RXCHAN_CFG_HBU(2));
@@ -229,11 +228,11 @@ static int pasemi_mac_setup_rx_resources
 
 out_buffers:
 	dma_free_coherent(&mac->dma_pdev->dev,
-			  RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
-			  mac->rx->desc, mac->rx->dma);
-out_desc:
-	kfree(ring->desc_info);
-out_desc_info:
+			  RX_RING_SIZE * sizeof(u64),
+			  mac->rx->ring, mac->rx->dma);
+out_ring_desc:
+	kfree(ring->ring_info);
+out_ring_info:
 	kfree(ring);
 out_ring:
 	return -ENOMEM;
@@ -254,25 +253,24 @@ static int pasemi_mac_setup_tx_resources
 	spin_lock_init(&ring->lock);
 
 	ring->size = TX_RING_SIZE;
-	ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+	ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
 				  TX_RING_SIZE, GFP_KERNEL);
-	if (!ring->desc_info)
-		goto out_desc_info;
+	if (!ring->ring_info)
+		goto out_ring_info;
 
 	/* Allocate descriptors */
-	ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
-					TX_RING_SIZE *
-					sizeof(struct pas_dma_xct_descr),
+	ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
+					TX_RING_SIZE * sizeof(u64),
 					&ring->dma, GFP_KERNEL);
-	if (!ring->desc)
-		goto out_desc;
+	if (!ring->ring)
+		goto out_ring_desc;
 
-	memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+	memset(ring->ring, 0, TX_RING_SIZE * sizeof(u64));
 
 	write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id),
 			   PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
 	val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
-	val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+	val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3);
 
 	write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val);
 
@@ -291,9 +289,9 @@ static int pasemi_mac_setup_tx_resources
 
 	return 0;
 
-out_desc:
-	kfree(ring->desc_info);
-out_desc_info:
+out_ring_desc:
+	kfree(ring->ring_info);
+out_ring_info:
 	kfree(ring);
 out_ring:
 	return -ENOMEM;
@@ -304,31 +302,27 @@ static void pasemi_mac_free_tx_resources
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int i;
 	struct pasemi_mac_buffer *info;
-	struct pas_dma_xct_descr *dp;
 
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		info = &TX_DESC_INFO(mac, i);
-		dp = &TX_DESC(mac, i);
-		if (info->dma) {
-			if (info->skb) {
-				pci_unmap_single(mac->dma_pdev,
-						 info->dma,
-						 info->skb->len,
-						 PCI_DMA_TODEVICE);
-				dev_kfree_skb_any(info->skb);
-			}
-			info->dma = 0;
-			info->skb = NULL;
-			dp->mactx = 0;
-			dp->ptr = 0;
+	for (i = 0; i < TX_RING_SIZE; i += 2) {
+		info = &TX_RING_INFO(mac, i+1);
+		if (info->dma && info->skb) {
+			pci_unmap_single(mac->dma_pdev,
+					 info->dma,
+					 info->skb->len,
+					 PCI_DMA_TODEVICE);
+			dev_kfree_skb_any(info->skb);
 		}
+		TX_RING(mac, i) = 0;
+		TX_RING(mac, i+1) = 0;
+		info->dma = 0;
+		info->skb = NULL;
 	}
 
 	dma_free_coherent(&mac->dma_pdev->dev,
-			  TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
-			  mac->tx->desc, mac->tx->dma);
+			  TX_RING_SIZE * sizeof(u64),
+			  mac->tx->ring, mac->tx->dma);
 
-	kfree(mac->tx->desc_info);
+	kfree(mac->tx->ring_info);
 	kfree(mac->tx);
 	mac->tx = NULL;
 }
@@ -338,34 +332,31 @@ static void pasemi_mac_free_rx_resources
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int i;
 	struct pasemi_mac_buffer *info;
-	struct pas_dma_xct_descr *dp;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		info = &RX_DESC_INFO(mac, i);
-		dp = &RX_DESC(mac, i);
-		if (info->skb) {
-			if (info->dma) {
-				pci_unmap_single(mac->dma_pdev,
-						 info->dma,
-						 info->skb->len,
-						 PCI_DMA_FROMDEVICE);
-				dev_kfree_skb_any(info->skb);
-			}
-			info->dma = 0;
-			info->skb = NULL;
-			dp->macrx = 0;
-			dp->ptr = 0;
+		info = &RX_RING_INFO(mac, i);
+		if (info->skb && info->dma) {
+			pci_unmap_single(mac->dma_pdev,
+					 info->dma,
+					 info->skb->len,
+					 PCI_DMA_FROMDEVICE);
+			dev_kfree_skb_any(info->skb);
 		}
+		info->dma = 0;
+		info->skb = NULL;
 	}
 
+	for (i = 0; i < RX_RING_SIZE; i++)
+		RX_RING(mac, i) = 0;
+
 	dma_free_coherent(&mac->dma_pdev->dev,
-			  RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
-			  mac->rx->desc, mac->rx->dma);
+			  RX_RING_SIZE * sizeof(u64),
+			  mac->rx->ring, mac->rx->dma);
 
 	dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
 			  mac->rx->buffers, mac->rx->buf_dma);
 
-	kfree(mac->rx->desc_info);
+	kfree(mac->rx->ring_info);
 	kfree(mac->rx);
 	mac->rx = NULL;
 }
@@ -373,20 +364,22 @@ static void pasemi_mac_free_rx_resources
 static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	unsigned int i;
 	int start = mac->rx->next_to_fill;
-	int count;
+	unsigned int fill, count;
 
 	if (limit <= 0)
 		return;
 
-	i = start;
+	fill = start;
 	for (count = 0; count < limit; count++) {
-		struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
-		u64 *buff = &RX_BUFF(mac, i);
+		struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill);
+		u64 *buff = &RX_BUFF(mac, fill);
 		struct sk_buff *skb;
 		dma_addr_t dma;
 
+		/* Entry in use? */
+		WARN_ON(*buff);
+
 		/* skb might still be in there for recycle on short receives */
 		if (info->skb)
 			skb = info->skb;
@@ -407,7 +400,7 @@ static void pasemi_mac_replenish_rx_ring
 		info->skb = skb;
 		info->dma = dma;
 		*buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
-		i++;
+		fill++;
 	}
 
 	wmb();
@@ -481,7 +474,6 @@ static int pasemi_mac_clean_rx(struct pa
 {
 	unsigned int n;
 	int count;
-	struct pas_dma_xct_descr *dp;
 	struct pasemi_mac_buffer *info;
 	struct sk_buff *skb;
 	unsigned int i, len;
@@ -496,9 +488,7 @@ static int pasemi_mac_clean_rx(struct pa
 
 		rmb();
 
-		dp = &RX_DESC(mac, n);
-		prefetchw(dp);
-		macrx = dp->macrx;
+		macrx = RX_RING(mac, n);
 
 		if ((macrx & XCT_MACRX_E) ||
 		    (*mac->rx_status & PAS_STATUS_ERROR))
@@ -516,12 +506,15 @@ static int pasemi_mac_clean_rx(struct pa
 		 * interface ring.
 		 */
 
-		dma = (dp->ptr & XCT_PTR_ADDR_M);
-		for (i = n; i < (n + RX_RING_SIZE); i++) {
-			info = &RX_DESC_INFO(mac, i);
+		dma = (RX_RING(mac, n+1) & XCT_PTR_ADDR_M);
+		for (i = mac->rx->next_to_fill;
+		     i < (mac->rx->next_to_fill + RX_RING_SIZE);
+		     i++) {
+			info = &RX_RING_INFO(mac, i);
 			if (info->dma == dma)
 				break;
 		}
+
 		prefetchw(info);
 
 		skb = info->skb;
@@ -546,6 +539,11 @@ static int pasemi_mac_clean_rx(struct pa
 		} else
 			info->skb = NULL;
 
+		/* Need to zero it out since hardware doesn't, since the
+		 * replenish loop uses it to tell when it's done.
+		 */
+		RX_BUFF(mac, i) = 0;
+
 		skb_put(skb, len);
 
 		if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) {
@@ -561,13 +559,13 @@ static int pasemi_mac_clean_rx(struct pa
 		skb->protocol = eth_type_trans(skb, mac->netdev);
 		netif_receive_skb(skb);
 
-		dp->ptr = 0;
-		dp->macrx = 0;
+		RX_RING(mac, n) = 0;
+		RX_RING(mac, n+1) = 0;
 
-		n++;
+		n += 2;
 	}
 
-	mac->rx->next_to_clean += limit - count;
+	mac->rx->next_to_clean = n;
 	pasemi_mac_replenish_rx_ring(mac->netdev, limit-count);
 
 	spin_unlock(&mac->rx->lock);
@@ -579,7 +577,6 @@ static int pasemi_mac_clean_tx(struct pa
 {
 	int i;
 	struct pasemi_mac_buffer *info;
-	struct pas_dma_xct_descr *dp;
 	unsigned int start, count, limit;
 	unsigned int total_count;
 	unsigned long flags;
@@ -595,29 +592,28 @@ restart:
 
 	count = 0;
 
-	for (i = start; i < limit; i++) {
-		dp = &TX_DESC(mac, i);
-
-		if ((dp->mactx & XCT_MACTX_E) ||
+	for (i = start; i < limit; i += 2) {
+		u64 mactx = TX_RING(mac, i);
+		if ((mactx  & XCT_MACTX_E) ||
 		    (*mac->tx_status & PAS_STATUS_ERROR))
-			pasemi_mac_tx_error(mac, dp->mactx);
+			pasemi_mac_tx_error(mac, mactx);
 
-		if (unlikely(dp->mactx & XCT_MACTX_O))
+		if (unlikely(mactx & XCT_MACTX_O))
 			/* Not yet transmitted */
 			break;
 
-		info = &TX_DESC_INFO(mac, i);
+		info = &TX_RING_INFO(mac, i+1);
 		skbs[count] = info->skb;
 		dmas[count] = info->dma;
 
-		info->skb = NULL;
 		info->dma = 0;
-		dp->mactx = 0;
-		dp->ptr = 0;
+		TX_RING(mac, i) = 0;
+		TX_RING(mac, i+1) = 0;
+
 
 		count++;
 	}
-	mac->tx->next_to_clean += count;
+	mac->tx->next_to_clean += count * 2;
 	spin_unlock_irqrestore(&mac->tx->lock, flags);
 	netif_wake_queue(mac->netdev);
 
@@ -1001,8 +997,6 @@ static int pasemi_mac_start_tx(struct sk
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
 	struct pasemi_mac_txring *txring;
-	struct pasemi_mac_buffer *info;
-	struct pas_dma_xct_descr *dp;
 	u64 dflags, mactx, ptr;
 	dma_addr_t map;
 	unsigned long flags;
@@ -1038,13 +1032,13 @@ static int pasemi_mac_start_tx(struct sk
 
 	spin_lock_irqsave(&txring->lock, flags);
 
-	if (RING_AVAIL(txring) <= 1) {
+	if (RING_AVAIL(txring) <= 2) {
 		spin_unlock_irqrestore(&txring->lock, flags);
 		pasemi_mac_clean_tx(mac);
 		pasemi_mac_restart_tx_intr(mac);
 		spin_lock_irqsave(&txring->lock, flags);
 
-		if (RING_AVAIL(txring) <= 1) {
+		if (RING_AVAIL(txring) <= 2) {
 			/* Still no room -- stop the queue and wait for tx
 			 * intr when there's room.
 			 */
@@ -1053,15 +1047,14 @@ static int pasemi_mac_start_tx(struct sk
 		}
 	}
 
-	dp = &TX_DESC(mac, txring->next_to_fill);
-	info = &TX_DESC_INFO(mac, txring->next_to_fill);
+	TX_RING(mac, txring->next_to_fill) = mactx;
+	TX_RING(mac, txring->next_to_fill+1) = ptr;
+
+	TX_RING_INFO(mac, txring->next_to_fill+1).dma = map;
+	TX_RING_INFO(mac, txring->next_to_fill+1).skb = skb;
 
-	dp->mactx = mactx;
-	dp->ptr   = ptr;
-	info->dma = map;
-	info->skb = skb;
+	txring->next_to_fill += 2;
 
-	txring->next_to_fill++;
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += skb->len;
 
drivers/net/pasemi_mac.h +5 -18
Index: k.org/drivers/net/pasemi_mac.h
===================================================================
@@ -28,25 +28,25 @@
 
 struct pasemi_mac_txring {
 	spinlock_t	 lock;
-	struct pas_dma_xct_descr	*desc;
+	u64		*ring;
 	dma_addr_t	 dma;
 	unsigned int	 size;
 	unsigned int	 next_to_fill;
 	unsigned int	 next_to_clean;
-	struct pasemi_mac_buffer *desc_info;
+	struct pasemi_mac_buffer *ring_info;
 	char		 irq_name[10];  /* "eth%d tx" */
 };
 
 struct pasemi_mac_rxring {
 	spinlock_t	 lock;
-	struct pas_dma_xct_descr	*desc;	/* RX channel descriptor ring */
+	u64		*ring;	/* RX channel descriptor ring */
 	dma_addr_t	 dma;
 	u64		*buffers;	/* RX interface buffer ring */
 	dma_addr_t	 buf_dma;
 	unsigned int	 size;
 	unsigned int	 next_to_fill;
 	unsigned int	 next_to_clean;
-	struct pasemi_mac_buffer *desc_info;
+	struct pasemi_mac_buffer *ring_info;
 	char		 irq_name[10];  /* "eth%d rx" */
 };
 
@@ -88,7 +88,7 @@ struct pasemi_mac {
 	char	phy_id[BUS_ID_SIZE];
 };
 
-/* Software status descriptor (desc_info) */
+/* Software status descriptor (ring_info) */
 struct pasemi_mac_buffer {
 	struct sk_buff *skb;
 	dma_addr_t	dma;
@@ -101,20 +101,7 @@ struct pasdma_status {
 	u64 tx_sta[20];
 };
 
-/* descriptor structure */
-struct pas_dma_xct_descr {
-	union {
-		u64	mactx;
-		u64	macrx;
-	};
-	union {
-		u64	ptr;
-		u64	rxb;
-	};
-};
-
 /* MAC CFG register offsets */
-
 enum {
 	PAS_MAC_CFG_PCFG = 0x80,
 	PAS_MAC_CFG_TXP = 0x98,
#5 lore raw

PATCH 4/11 pasemi_mac: implement sg support

In reply to Olof Johansson

pasemi_mac: implement sg support

Implement SG support for pasemi_mac

drivers/net/pasemi_mac.c +117 -46
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -160,6 +160,30 @@ static int pasemi_get_mac_addr(struct pa
 	return 0;
 }
 
+static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
+				    struct sk_buff *skb,
+				    dma_addr_t *dmas)
+{
+	int f;
+	int nfrags = skb_shinfo(skb)->nr_frags;
+
+	pci_unmap_single(mac->dma_pdev, dmas[0], skb_headlen(skb),
+			 PCI_DMA_TODEVICE);
+
+	for (f = 0; f < nfrags; f++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
+
+		pci_unmap_page(mac->dma_pdev, dmas[f+1], frag->size,
+			       PCI_DMA_TODEVICE);
+	}
+	dev_kfree_skb_irq(skb);
+
+	/* Freed descriptor slot + main SKB ptr + nfrags additional ptrs,
+	 * aligned up to a power of 2
+	 */
+	return (nfrags + 3) & ~1;
+}
+
 static int pasemi_mac_setup_rx_resources(struct net_device *dev)
 {
 	struct pasemi_mac_rxring *ring;
@@ -300,24 +324,24 @@ out_ring:
 static void pasemi_mac_free_tx_resources(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	unsigned int i;
+	unsigned int i, j;
 	struct pasemi_mac_buffer *info;
+	dma_addr_t dmas[MAX_SKB_FRAGS+1];
+	int freed;
 
-	for (i = 0; i < TX_RING_SIZE; i += 2) {
+	for (i = 0; i < TX_RING_SIZE; i += freed) {
 		info = &TX_RING_INFO(mac, i+1);
 		if (info->dma && info->skb) {
-			pci_unmap_single(mac->dma_pdev,
-					 info->dma,
-					 info->skb->len,
-					 PCI_DMA_TODEVICE);
-			dev_kfree_skb_any(info->skb);
-		}
-		TX_RING(mac, i) = 0;
-		TX_RING(mac, i+1) = 0;
-		info->dma = 0;
-		info->skb = NULL;
+			for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++)
+				dmas[j] = TX_RING_INFO(mac, i+1+j).dma;
+			freed = pasemi_mac_unmap_tx_skb(mac, info->skb, dmas);
+		} else
+			freed = 2;
 	}
 
+	for (i = 0; i < TX_RING_SIZE; i++)
+		TX_RING(mac, i) = 0;
+
 	dma_free_coherent(&mac->dma_pdev->dev,
 			  TX_RING_SIZE * sizeof(u64),
 			  mac->tx->ring, mac->tx->dma);
@@ -573,27 +597,34 @@ static int pasemi_mac_clean_rx(struct pa
 	return count;
 }
 
+/* Can't make this too large or we blow the kernel stack limits */
+#define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS)
+
 static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
 {
-	int i;
+	int i, j;
 	struct pasemi_mac_buffer *info;
-	unsigned int start, count, limit;
+	unsigned int start, descr_count, buf_count, limit;
 	unsigned int total_count;
 	unsigned long flags;
-	struct sk_buff *skbs[32];
-	dma_addr_t dmas[32];
+	struct sk_buff *skbs[TX_CLEAN_BATCHSIZE];
+	dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1];
 
 	total_count = 0;
+	limit = TX_CLEAN_BATCHSIZE;
 restart:
 	spin_lock_irqsave(&mac->tx->lock, flags);
 
 	start = mac->tx->next_to_clean;
-	limit = min(mac->tx->next_to_fill, start+32);
 
-	count = 0;
+	buf_count = 0;
+	descr_count = 0;
 
-	for (i = start; i < limit; i += 2) {
+	for (i = start;
+	     descr_count < limit && i < mac->tx->next_to_fill;
+	     i += buf_count) {
 		u64 mactx = TX_RING(mac, i);
+
 		if ((mactx  & XCT_MACTX_E) ||
 		    (*mac->tx_status & PAS_STATUS_ERROR))
 			pasemi_mac_tx_error(mac, mactx);
@@ -603,30 +634,38 @@ restart:
 			break;
 
 		info = &TX_RING_INFO(mac, i+1);
-		skbs[count] = info->skb;
-		dmas[count] = info->dma;
+		skbs[descr_count] = info->skb;
+
+		buf_count = 2 + skb_shinfo(info->skb)->nr_frags;
+		for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++)
+			dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma;
+
 
 		info->dma = 0;
 		TX_RING(mac, i) = 0;
 		TX_RING(mac, i+1) = 0;
+		TX_RING_INFO(mac, i+1).skb = 0;
+		TX_RING_INFO(mac, i+1).dma = 0;
 
-
-		count++;
+		/* Since we always fill with an even number of entries, make
+		 * sure we skip any unused one at the end as well.
+		 */
+		if (buf_count & 1)
+			buf_count++;
+		descr_count++;
 	}
-	mac->tx->next_to_clean += count * 2;
+	mac->tx->next_to_clean = i;
+
 	spin_unlock_irqrestore(&mac->tx->lock, flags);
 	netif_wake_queue(mac->netdev);
 
-	for (i = 0; i < count; i++) {
-		pci_unmap_single(mac->dma_pdev, dmas[i],
-				 skbs[i]->len, PCI_DMA_TODEVICE);
-		dev_kfree_skb_irq(skbs[i]);
-	}
+	for (i = 0; i < descr_count; i++)
+		pasemi_mac_unmap_tx_skb(mac, skbs[i], dmas[i]);
 
-	total_count += count;
+	total_count += descr_count;
 
 	/* If the batch was full, try to clean more */
-	if (count == 32)
+	if (descr_count == limit)
 		goto restart;
 
 	return total_count;
@@ -997,9 +1036,11 @@ static int pasemi_mac_start_tx(struct sk
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
 	struct pasemi_mac_txring *txring;
-	u64 dflags, mactx, ptr;
-	dma_addr_t map;
+	u64 dflags, mactx;
+	dma_addr_t map[MAX_SKB_FRAGS+1];
+	unsigned int map_size[MAX_SKB_FRAGS+1];
 	unsigned long flags;
+	int i, nfrags;
 
 	dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
 
@@ -1020,25 +1061,40 @@ static int pasemi_mac_start_tx(struct sk
 		}
 	}
 
-	map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	nfrags = skb_shinfo(skb)->nr_frags;
 
-	if (dma_mapping_error(map))
-		return NETDEV_TX_BUSY;
+	map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb),
+				PCI_DMA_TODEVICE);
+	map_size[0] = skb_headlen(skb);
+	if (dma_mapping_error(map[0]))
+		goto out_err_nolock;
+
+	for (i = 0; i < nfrags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		map[i+1] = pci_map_page(mac->dma_pdev, frag->page,
+					frag->page_offset, frag->size,
+					PCI_DMA_TODEVICE);
+		map_size[i+1] = frag->size;
+		if (dma_mapping_error(map[i+1])) {
+			nfrags = i;
+			goto out_err_nolock;
+		}
+	}
 
 	mactx = dflags | XCT_MACTX_LLEN(skb->len);
-	ptr   = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
 
 	txring = mac->tx;
 
 	spin_lock_irqsave(&txring->lock, flags);
 
-	if (RING_AVAIL(txring) <= 2) {
+	if (RING_AVAIL(txring) <= nfrags+3) {
 		spin_unlock_irqrestore(&txring->lock, flags);
 		pasemi_mac_clean_tx(mac);
 		pasemi_mac_restart_tx_intr(mac);
 		spin_lock_irqsave(&txring->lock, flags);
 
-		if (RING_AVAIL(txring) <= 2) {
+		if (RING_AVAIL(txring) <= nfrags+3) {
 			/* Still no room -- stop the queue and wait for tx
 			 * intr when there's room.
 			 */
@@ -1048,25 +1104,40 @@ static int pasemi_mac_start_tx(struct sk
 	}
 
 	TX_RING(mac, txring->next_to_fill) = mactx;
-	TX_RING(mac, txring->next_to_fill+1) = ptr;
+	txring->next_to_fill++;
+	TX_RING_INFO(mac, txring->next_to_fill).skb = skb;
+	for (i = 0; i <= nfrags; i++) {
+		TX_RING(mac, txring->next_to_fill+i) =
+		XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);
+		TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i];
+	}
+
+	/* We have to add an even number of 8-byte entries to the ring
+	 * even if the last one is unused. That means always an odd number
+	 * of pointers + one mactx descriptor.
+	 */
+	if (nfrags & 1)
+		nfrags++;
 
-	TX_RING_INFO(mac, txring->next_to_fill+1).dma = map;
-	TX_RING_INFO(mac, txring->next_to_fill+1).skb = skb;
+	txring->next_to_fill += nfrags + 1;
 
-	txring->next_to_fill += 2;
 
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += skb->len;
 
 	spin_unlock_irqrestore(&txring->lock, flags);
 
-	write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+	write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1);
 
 	return NETDEV_TX_OK;
 
 out_err:
 	spin_unlock_irqrestore(&txring->lock, flags);
-	pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
+out_err_nolock:
+	while (nfrags--)
+		pci_unmap_single(mac->dma_pdev, map[nfrags], map_size[nfrags],
+				 PCI_DMA_TODEVICE);
+
 	return NETDEV_TX_BUSY;
 }
 
@@ -1202,7 +1273,7 @@ pasemi_mac_probe(struct pci_dev *pdev, c
 
 	netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64);
 
-	dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX;
+	dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX | NETIF_F_SG;
 
 	/* These should come out of the device tree eventually */
 	mac->dma_txch = index;
#6 lore raw

PATCH 5/11 pasemi_mac: workaround for erratum 5971

In reply to Olof Johansson

pasemi_mac: workaround for erratum 5971

Implement workarounds for erratum 5971, where L2 hints aren't considered properly unless the way hint is enabled on the interface. Since L2 isn't setup to dedicate a way to headers, we need to reset the packet count by hand so it won't run out of credits.

drivers/net/pasemi_mac.c +8 -1
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -239,7 +239,9 @@ static int pasemi_mac_setup_rx_resources
 			   PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
 
 	write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if),
-			   PAS_DMA_RXINT_CFG_DHL(2));
+			   PAS_DMA_RXINT_CFG_DHL(3) |
+			   PAS_DMA_RXINT_CFG_L2 |
+			   PAS_DMA_RXINT_CFG_LW);
 
 	ring->next_to_fill = 0;
 	ring->next_to_clean = 0;
@@ -589,6 +591,11 @@ static int pasemi_mac_clean_rx(struct pa
 		n += 2;
 	}
 
+	if (n > RX_RING_SIZE) {
+		/* Errata 5971 workaround: L2 target of headers */
+		write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0);
+		n &= (RX_RING_SIZE-1);
+	}
 	mac->rx->next_to_clean = n;
 	pasemi_mac_replenish_rx_ring(mac->netdev, limit-count);
 
drivers/net/pasemi_mac.h +8 -0
Index: k.org/drivers/net/pasemi_mac.h
===================================================================
@@ -210,6 +210,8 @@ enum {
 #define    PAS_DMA_RXINT_CFG_DHL_S	24
 #define    PAS_DMA_RXINT_CFG_DHL(x)	(((x) << PAS_DMA_RXINT_CFG_DHL_S) & \
 					 PAS_DMA_RXINT_CFG_DHL_M)
+#define    PAS_DMA_RXINT_CFG_LW		0x00200000
+#define    PAS_DMA_RXINT_CFG_L2		0x00100000
 #define    PAS_DMA_RXINT_CFG_WIF	0x00000002
 #define    PAS_DMA_RXINT_CFG_WIL	0x00000001
 
@@ -315,6 +317,12 @@ enum {
 #define    PAS_STATUS_SOFT		0x4000000000000000ull
 #define    PAS_STATUS_INT		0x8000000000000000ull
 
+#define PAS_IOB_COM_PKTHDRCNT		0x120
+#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR1_M	0x0fff0000
+#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR1_S	16
+#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR0_M	0x00000fff
+#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR0_S	0
+
 #define PAS_IOB_DMA_RXCH_CFG(i)		(0x1100 + (i)*4)
 #define    PAS_IOB_DMA_RXCH_CFG_CNTTH_M		0x00000fff
 #define    PAS_IOB_DMA_RXCH_CFG_CNTTH_S		0
#7 lore raw

PATCH 6/11 pasemi_mac: add local skb alignment

In reply to Olof Johansson

pasemi_mac: add local skb alignment

Add local SKB alignment to pasemi_mac, since ppc64 in general has it at 0 because of design flaws in some of the IBM server bridge chips. However, for PWRficient doing the unaligned copies is more expensive than doing unaligned DMA so make sure the data is aligned instead.

drivers/net/pasemi_mac.c +16 -5
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -37,6 +37,12 @@
 
 #include "pasemi_mac.h"
 
+/* We have our own align, since ppc64 in general has it at 0 because
+ * of design flaws in some of the server bridge chips. However, for
+ * PWRficient doing the unaligned copies is more expensive than doing
+ * unaligned DMA, so make sure the data is aligned instead.
+ */
+#define LOCAL_SKB_ALIGN	2
 
 /* TODO list
  *
@@ -409,13 +415,16 @@ static void pasemi_mac_replenish_rx_ring
 		/* skb might still be in there for recycle on short receives */
 		if (info->skb)
 			skb = info->skb;
-		else
+		else {
 			skb = dev_alloc_skb(BUF_SIZE);
+			skb_reserve(skb, LOCAL_SKB_ALIGN);
+		}
 
 		if (unlikely(!skb))
 			break;
 
-		dma = pci_map_single(mac->dma_pdev, skb->data, BUF_SIZE,
+		dma = pci_map_single(mac->dma_pdev, skb->data,
+				     BUF_SIZE - LOCAL_SKB_ALIGN,
 				     PCI_DMA_FROMDEVICE);
 
 		if (unlikely(dma_mapping_error(dma))) {
@@ -553,10 +562,12 @@ static int pasemi_mac_clean_rx(struct pa
 		len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
 
 		if (len < 256) {
-			struct sk_buff *new_skb =
-			    netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN);
+			struct sk_buff *new_skb;
+
+			new_skb = netdev_alloc_skb(mac->netdev,
+						   len + LOCAL_SKB_ALIGN);
 			if (new_skb) {
-				skb_reserve(new_skb, NET_IP_ALIGN);
+				skb_reserve(new_skb, LOCAL_SKB_ALIGN);
 				memcpy(new_skb->data, skb->data, len);
 				/* save the skb in buffer_info as good */
 				skb = new_skb;
#8 lore raw

PATCH 7/11 pasemi_mac: further performance tweaks

In reply to Olof Johansson

pasemi_mac: further performance tweaks

Misc driver tweaks for pasemi_mac:
* Increase ring size (really needed mostly on 10G)
* Take out an unneeded barrier
* Move around a few prefetches and reorder a few calls
* Don't try to clean on full tx buffer, just let things take their course and stop the queue directly
* Avoid filling on the same line as the interface is working on to reduce cache line bouncing
* Avoid unneeded clearing of software state (and make the interface shutdown code handle it)
* Fix up some of the tx ring wrap logic.

drivers/net/pasemi_mac.c +47 -45
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -56,8 +56,8 @@
 
 
 /* Must be a power of two */
-#define RX_RING_SIZE 512
-#define TX_RING_SIZE 512
+#define RX_RING_SIZE 4096
+#define TX_RING_SIZE 4096
 
 #define DEFAULT_MSG_ENABLE	  \
 	(NETIF_MSG_DRV		| \
@@ -336,8 +336,16 @@ static void pasemi_mac_free_tx_resources
 	struct pasemi_mac_buffer *info;
 	dma_addr_t dmas[MAX_SKB_FRAGS+1];
 	int freed;
+	int start, limit;
 
-	for (i = 0; i < TX_RING_SIZE; i += freed) {
+	start = mac->tx->next_to_clean;
+	limit = mac->tx->next_to_fill;
+
+	/* Compensate for when fill has wrapped and clean has not */
+	if (start > limit)
+		limit += TX_RING_SIZE;
+
+	for (i = start; i < limit; i += freed) {
 		info = &TX_RING_INFO(mac, i+1);
 		if (info->dma && info->skb) {
 			for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++)
@@ -520,9 +528,6 @@ static int pasemi_mac_clean_rx(struct pa
 	n = mac->rx->next_to_clean;
 
 	for (count = limit; count; count--) {
-
-		rmb();
-
 		macrx = RX_RING(mac, n);
 
 		if ((macrx & XCT_MACRX_E) ||
@@ -550,14 +555,10 @@ static int pasemi_mac_clean_rx(struct pa
 				break;
 		}
 
-		prefetchw(info);
-
 		skb = info->skb;
-		prefetchw(skb);
-		info->dma = 0;
 
-		pci_unmap_single(mac->dma_pdev, dma, skb->len,
-				 PCI_DMA_FROMDEVICE);
+		prefetch(skb);
+		prefetch(&skb->data_len);
 
 		len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
 
@@ -576,10 +577,9 @@ static int pasemi_mac_clean_rx(struct pa
 		} else
 			info->skb = NULL;
 
-		/* Need to zero it out since hardware doesn't, since the
-		 * replenish loop uses it to tell when it's done.
-		 */
-		RX_BUFF(mac, i) = 0;
+		pci_unmap_single(mac->dma_pdev, dma, len, PCI_DMA_FROMDEVICE);
+
+		info->dma = 0;
 
 		skb_put(skb, len);
 
@@ -599,6 +599,11 @@ static int pasemi_mac_clean_rx(struct pa
 		RX_RING(mac, n) = 0;
 		RX_RING(mac, n+1) = 0;
 
+		/* Need to zero it out since hardware doesn't, since the
+		 * replenish loop uses it to tell when it's done.
+		 */
+		RX_BUFF(mac, i) = 0;
+
 		n += 2;
 	}
 
@@ -621,27 +626,33 @@ static int pasemi_mac_clean_rx(struct pa
 static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
 {
 	int i, j;
-	struct pasemi_mac_buffer *info;
-	unsigned int start, descr_count, buf_count, limit;
+	unsigned int start, descr_count, buf_count, batch_limit;
+	unsigned int ring_limit;
 	unsigned int total_count;
 	unsigned long flags;
 	struct sk_buff *skbs[TX_CLEAN_BATCHSIZE];
 	dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1];
 
 	total_count = 0;
-	limit = TX_CLEAN_BATCHSIZE;
+	batch_limit = TX_CLEAN_BATCHSIZE;
 restart:
 	spin_lock_irqsave(&mac->tx->lock, flags);
 
 	start = mac->tx->next_to_clean;
+	ring_limit = mac->tx->next_to_fill;
+
+	/* Compensate for when fill has wrapped but clean has not */
+	if (start > ring_limit)
+		ring_limit += TX_RING_SIZE;
 
 	buf_count = 0;
 	descr_count = 0;
 
 	for (i = start;
-	     descr_count < limit && i < mac->tx->next_to_fill;
+	     descr_count < batch_limit && i < ring_limit;
 	     i += buf_count) {
 		u64 mactx = TX_RING(mac, i);
+		struct sk_buff *skb;
 
 		if ((mactx  & XCT_MACTX_E) ||
 		    (*mac->tx_status & PAS_STATUS_ERROR))
@@ -651,19 +662,15 @@ restart:
 			/* Not yet transmitted */
 			break;
 
-		info = &TX_RING_INFO(mac, i+1);
-		skbs[descr_count] = info->skb;
+		skb = TX_RING_INFO(mac, i+1).skb;
+		skbs[descr_count] = skb;
 
-		buf_count = 2 + skb_shinfo(info->skb)->nr_frags;
-		for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++)
+		buf_count = 2 + skb_shinfo(skb)->nr_frags;
+		for (j = 0; j <= skb_shinfo(skb)->nr_frags; j++)
 			dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma;
 
-
-		info->dma = 0;
 		TX_RING(mac, i) = 0;
 		TX_RING(mac, i+1) = 0;
-		TX_RING_INFO(mac, i+1).skb = 0;
-		TX_RING_INFO(mac, i+1).dma = 0;
 
 		/* Since we always fill with an even number of entries, make
 		 * sure we skip any unused one at the end as well.
@@ -672,7 +679,7 @@ restart:
 			buf_count++;
 		descr_count++;
 	}
-	mac->tx->next_to_clean = i;
+	mac->tx->next_to_clean = i & (TX_RING_SIZE-1);
 
 	spin_unlock_irqrestore(&mac->tx->lock, flags);
 	netif_wake_queue(mac->netdev);
@@ -683,7 +690,7 @@ restart:
 	total_count += descr_count;
 
 	/* If the batch was full, try to clean more */
-	if (descr_count == limit)
+	if (descr_count == batch_limit)
 		goto restart;
 
 	return total_count;
@@ -1106,19 +1113,14 @@ static int pasemi_mac_start_tx(struct sk
 
 	spin_lock_irqsave(&txring->lock, flags);
 
-	if (RING_AVAIL(txring) <= nfrags+3) {
-		spin_unlock_irqrestore(&txring->lock, flags);
-		pasemi_mac_clean_tx(mac);
-		pasemi_mac_restart_tx_intr(mac);
-		spin_lock_irqsave(&txring->lock, flags);
-
-		if (RING_AVAIL(txring) <= nfrags+3) {
-			/* Still no room -- stop the queue and wait for tx
-			 * intr when there's room.
-			 */
-			netif_stop_queue(dev);
-			goto out_err;
-		}
+	/* Avoid stepping on the same cache line that the DMA controller
+	 * is currently about to send, so leave at least 8 words available.
+	 * Total free space needed is mactx + fragments + 8
+	 */
+	if (RING_AVAIL(txring) < nfrags + 10) {
+		/* no room -- stop the queue and wait for tx intr */
+		netif_stop_queue(dev);
+		goto out_err;
 	}
 
 	TX_RING(mac, txring->next_to_fill) = mactx;
@@ -1137,8 +1139,8 @@ static int pasemi_mac_start_tx(struct sk
 	if (nfrags & 1)
 		nfrags++;
 
-	txring->next_to_fill += nfrags + 1;
-
+	txring->next_to_fill = (txring->next_to_fill + nfrags + 1) &
+				(TX_RING_SIZE-1);
 
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += skb->len;
#9 lore raw

PATCH 8/11 pasemi_mac: update todo list

In reply to Olof Johansson

pasemi_mac: update todo list

Remove some stale todo items that have been taken care of. Add a couple of upcoming ones.

drivers/net/pasemi_mac.c +2 -4
Index: 2.6.23/drivers/net/pasemi_mac.c
===================================================================
@@ -46,12 +46,10 @@
 
 /* TODO list
  *
- * - Get rid of pci_{read,write}_config(), map registers with ioremap
- *   for performance
- * - PHY support
  * - Multicast support
  * - Large MTU support
- * - Other performance improvements
+ * - SW LRO
+ * - Multiqueue RX/TX
  */
 
 
#10 lore raw

PATCH 9/11 pasemi_mac: clear out old errors on interface open

In reply to Olof Johansson

pasemi_mac: clear out old errors on interface open

Clear out any pending errors when an interface is brought up. Since the bits are sticky, they might be from interface shutdown time after firmware has used it, etc.

drivers/net/pasemi_mac.c +44 -13
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -903,16 +903,27 @@ static int pasemi_mac_open(struct net_de
 
 	/* enable rx if */
 	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
-			   PAS_DMA_RXINT_RCMDSTA_EN);
+			   PAS_DMA_RXINT_RCMDSTA_EN |
+			   PAS_DMA_RXINT_RCMDSTA_DROPS_M |
+			   PAS_DMA_RXINT_RCMDSTA_BP |
+			   PAS_DMA_RXINT_RCMDSTA_OO |
+			   PAS_DMA_RXINT_RCMDSTA_BT);
 
 	/* enable rx channel */
 	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
 			   PAS_DMA_RXCHAN_CCMDSTA_EN |
-			   PAS_DMA_RXCHAN_CCMDSTA_DU);
+			   PAS_DMA_RXCHAN_CCMDSTA_DU |
+			   PAS_DMA_RXCHAN_CCMDSTA_OD |
+			   PAS_DMA_RXCHAN_CCMDSTA_FD |
+			   PAS_DMA_RXCHAN_CCMDSTA_DT);
 
 	/* enable tx channel */
 	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
-			   PAS_DMA_TXCHAN_TCMDSTA_EN);
+			   PAS_DMA_TXCHAN_TCMDSTA_EN |
+			   PAS_DMA_TXCHAN_TCMDSTA_SZ |
+			   PAS_DMA_TXCHAN_TCMDSTA_DB |
+			   PAS_DMA_TXCHAN_TCMDSTA_DE |
+			   PAS_DMA_TXCHAN_TCMDSTA_DA);
 
 	pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE);
 
@@ -987,7 +998,7 @@ out_rx_resources:
 static int pasemi_mac_close(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	unsigned int stat;
+	unsigned int sta;
 	int retries;
 
 	if (mac->phydev) {
@@ -998,6 +1009,26 @@ static int pasemi_mac_close(struct net_d
 	netif_stop_queue(dev);
 	napi_disable(&mac->napi);
 
+	sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+	if (sta & (PAS_DMA_RXINT_RCMDSTA_BP |
+		      PAS_DMA_RXINT_RCMDSTA_OO |
+		      PAS_DMA_RXINT_RCMDSTA_BT))
+		printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta);
+
+	sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+	if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU |
+		     PAS_DMA_RXCHAN_CCMDSTA_OD |
+		     PAS_DMA_RXCHAN_CCMDSTA_FD |
+		     PAS_DMA_RXCHAN_CCMDSTA_DT))
+		printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta);
+
+	sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+	if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ |
+		      PAS_DMA_TXCHAN_TCMDSTA_DB |
+		      PAS_DMA_TXCHAN_TCMDSTA_DE |
+		      PAS_DMA_TXCHAN_TCMDSTA_DA))
+		printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta);
+
 	/* Clean out any pending buffers */
 	pasemi_mac_clean_tx(mac);
 	pasemi_mac_clean_rx(mac, RX_RING_SIZE);
@@ -1008,33 +1039,33 @@ static int pasemi_mac_close(struct net_d
 	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST);
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		stat = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
-		if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT))
+		sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+		if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+	if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		stat = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
-		if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT))
+		sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+		if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+	if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		stat = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
-		if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT))
+		sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+		if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+	if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
 
 	/* Then, disable the channel. This must be done separately from
drivers/net/pasemi_mac.h +7 -0
Index: k.org/drivers/net/pasemi_mac.h
===================================================================
@@ -241,6 +241,10 @@ enum {
 #define    PAS_DMA_TXCHAN_TCMDSTA_EN	0x00000001	/* Enabled */
 #define    PAS_DMA_TXCHAN_TCMDSTA_ST	0x00000002	/* Stop interface */
 #define    PAS_DMA_TXCHAN_TCMDSTA_ACT	0x00010000	/* Active */
+#define    PAS_DMA_TXCHAN_TCMDSTA_SZ	0x00000800
+#define    PAS_DMA_TXCHAN_TCMDSTA_DB	0x00000400
+#define    PAS_DMA_TXCHAN_TCMDSTA_DE	0x00000200
+#define    PAS_DMA_TXCHAN_TCMDSTA_DA	0x00000100
 #define PAS_DMA_TXCHAN_CFG(c)     (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
 #define    PAS_DMA_TXCHAN_CFG_TY_IFACE	0x00000000	/* Type = interface */
 #define    PAS_DMA_TXCHAN_CFG_TATTR_M	0x0000003c
@@ -283,6 +287,9 @@ enum {
 #define    PAS_DMA_RXCHAN_CCMDSTA_ST	0x00000002	/* Stop interface */
 #define    PAS_DMA_RXCHAN_CCMDSTA_ACT	0x00010000	/* Active */
 #define    PAS_DMA_RXCHAN_CCMDSTA_DU	0x00020000
+#define    PAS_DMA_RXCHAN_CCMDSTA_OD	0x00002000
+#define    PAS_DMA_RXCHAN_CCMDSTA_FD	0x00001000
+#define    PAS_DMA_RXCHAN_CCMDSTA_DT	0x00000800
 #define PAS_DMA_RXCHAN_CFG(c)     (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
 #define    PAS_DMA_RXCHAN_CFG_HBU_M	0x00000380
 #define    PAS_DMA_RXCHAN_CFG_HBU_S	7
#11 lore raw

Re: [PATCH] [9/11] pasemi_mac: clear out old errors on interface open

Quoted 7 lines · Olof Johansson

pasemi_mac: clear out old errors on interface open

Clear out any pending errors when an interface is brought up. Since the bits are sticky, they might be from interface shutdown time after firmware has used it, etc.

In general, interface-open should completely reset and initialize the hardware. does pasemi_mac not do that?

Jeff

#12 lore raw

Re: [PATCH] [9/11] pasemi_mac: clear out old errors on interface open

Quoted 10 lines · Jeff Garzik
Quoted 6 lines · Olof Johansson

pasemi_mac: clear out old errors on interface open
Clear out any pending errors when an interface is brought up. Since the bits
are sticky, they might be from interface shutdown time after firmware has used it, etc.

In general, interface-open should completely reset and initialize the hardware. does pasemi_mac not do that?

There's no explicit way to reset just one interface besides disabling it (which we do at close, and re-enable at open). It seems that some of the error bits are sticky across disable/enable, which is why this was needed. Also, they're RW1C, so writing 0 doesn't remove them (need to write 1 to clear).

The only other dependency from firmware at this time is the setting of mac addresses, something that will be taken care of once we allow override of them via ethtool, since we'd need to program them from the driver then no matter what. Right now we assume that firmware has programmed it.

-Olof

#13 lore raw

Re: [PATCH] [9/11] pasemi_mac: clear out old errors on interface open

Quoted 7 lines · Olof Johansson
Quoted 6 lines · Jeff Garzik
Quoted 5 lines · Olof Johansson

pasemi_mac: clear out old errors on interface open
Clear out any pending errors when an interface is brought up. Since the bits are sticky, they might be from interface shutdown time after firmware has used it, etc.

Quoted 7 lines
Quoted 1 line

In general, interface-open should completely reset and initialize the hardware. does pasemi_mac not do that?

There's no explicit way to reset just one interface besides disabling it (which we do at close, and re-enable at open). It seems that some of the error bits are sticky across disable/enable, which is why this was needed. Also, they're RW1C, so writing 0 doesn't remove them (need to write 1 to clear).

OK just making sure, thanks.

Quoted 4 lines

The only other dependency from firmware at this time is the setting of mac addresses, something that will be taken care of once we allow override of them via ethtool, since we'd need to program them from the driver then no matter what. Right now we assume that firmware has programmed it.

Standard procedure for this is

* upon module-load, obtain the MAC address from <whatever canonical source>
* upon interface-up, program dev->dev_addr[] into chip's RX filter (aka MAC address) registers

That permits the admin to override the MAC address via ifconfig. (ethtool doesn't support that, but you basically had the right idea)

Jeff

#14 lore raw

PATCH 10/11 pasemi_mac: use buffer index pointer in clean_rx()

In reply to Olof Johansson

pasemi_mac: use buffer index pointer in clean_rx()

Use the new features in B0 for buffer ring index on the receive side. This means we no longer have to search in the ring for where the buffer came from.

Also cleanup the RX cleaning side a little, while I was at it.

Note: Pre-B0 hardware is no longer supported, and needs a pile of other workarounds that are not being submitted for mainline inclusion. So the fact that this breaks old hardware is not a problem at this time.

drivers/net/pasemi_mac.c +33 -27
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -243,9 +243,9 @@ static int pasemi_mac_setup_rx_resources
 			   PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
 
 	write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if),
-			   PAS_DMA_RXINT_CFG_DHL(3) |
-			   PAS_DMA_RXINT_CFG_L2 |
-			   PAS_DMA_RXINT_CFG_LW);
+		      PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 |
+		      PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP |
+		      PAS_DMA_RXINT_CFG_HEN);
 
 	ring->next_to_fill = 0;
 	ring->next_to_clean = 0;
@@ -402,13 +402,12 @@ static void pasemi_mac_free_rx_resources
 static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	int start = mac->rx->next_to_fill;
-	unsigned int fill, count;
+	int fill, count;
 
 	if (limit <= 0)
 		return;
 
-	fill = start;
+	fill = mac->rx->next_to_fill;
 	for (count = 0; count < limit; count++) {
 		struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill);
 		u64 *buff = &RX_BUFF(mac, fill);
@@ -446,10 +445,10 @@ static void pasemi_mac_replenish_rx_ring
 
 	wmb();
 
-	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count);
 	write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count);
 
-	mac->rx->next_to_fill += count;
+	mac->rx->next_to_fill = (mac->rx->next_to_fill + count) &
+				(RX_RING_SIZE - 1);
 }
 
 static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
@@ -517,15 +516,19 @@ static int pasemi_mac_clean_rx(struct pa
 	int count;
 	struct pasemi_mac_buffer *info;
 	struct sk_buff *skb;
-	unsigned int i, len;
+	unsigned int len;
 	u64 macrx;
 	dma_addr_t dma;
+	int buf_index;
+	u64 eval;
 
 	spin_lock(&mac->rx->lock);
 
 	n = mac->rx->next_to_clean;
 
-	for (count = limit; count; count--) {
+	prefetch(RX_RING(mac, n));
+
+	for (count = 0; count < limit; count++) {
 		macrx = RX_RING(mac, n);
 
 		if ((macrx & XCT_MACRX_E) ||
@@ -537,21 +540,14 @@ static int pasemi_mac_clean_rx(struct pa
 
 		info = NULL;
 
-		/* We have to scan for our skb since there's no way
-		 * to back-map them from the descriptor, and if we
-		 * have several receive channels then they might not
-		 * show up in the same order as they were put on the
-		 * interface ring.
-		 */
+		BUG_ON(!(macrx & XCT_MACRX_RR_8BRES));
 
-		dma = (RX_RING(mac, n+1) & XCT_PTR_ADDR_M);
-		for (i = mac->rx->next_to_fill;
-		     i < (mac->rx->next_to_fill + RX_RING_SIZE);
-		     i++) {
-			info = &RX_RING_INFO(mac, i);
-			if (info->dma == dma)
-				break;
-		}
+		eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >>
+			XCT_RXRES_8B_EVAL_S;
+		buf_index = eval-1;
+
+		dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M);
+		info = &RX_RING_INFO(mac, buf_index);
 
 		skb = info->skb;
 
@@ -600,9 +596,9 @@ static int pasemi_mac_clean_rx(struct pa
 		/* Need to zero it out since hardware doesn't, since the
 		 * replenish loop uses it to tell when it's done.
 		 */
-		RX_BUFF(mac, i) = 0;
+		RX_BUFF(mac, buf_index) = 0;
 
-		n += 2;
+		n += 4;
 	}
 
 	if (n > RX_RING_SIZE) {
@@ -610,8 +606,16 @@ static int pasemi_mac_clean_rx(struct pa
 		write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0);
 		n &= (RX_RING_SIZE-1);
 	}
+
 	mac->rx->next_to_clean = n;
-	pasemi_mac_replenish_rx_ring(mac->netdev, limit-count);
+
+	/* Increase is in number of 16-byte entries, and since each descriptor
+	 * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
+	 * count*2.
+	 */
+	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1);
+
+	pasemi_mac_replenish_rx_ring(mac->netdev, count);
 
 	spin_unlock(&mac->rx->lock);
 
@@ -927,6 +931,8 @@ static int pasemi_mac_open(struct net_de
 
 	pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE);
 
+	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1);
+
 	flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
 		PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
 
drivers/net/pasemi_mac.h +17 -4
Index: k.org/drivers/net/pasemi_mac.h
===================================================================
@@ -206,12 +206,15 @@ enum {
 #define    PAS_DMA_RXINT_RCMDSTA_DROPS_M	0xfffe0000
 #define    PAS_DMA_RXINT_RCMDSTA_DROPS_S	17
 #define PAS_DMA_RXINT_CFG(i)		(0x204+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_CFG_RBP	0x80000000
+#define    PAS_DMA_RXINT_CFG_ITRR	0x40000000
 #define    PAS_DMA_RXINT_CFG_DHL_M	0x07000000
 #define    PAS_DMA_RXINT_CFG_DHL_S	24
 #define    PAS_DMA_RXINT_CFG_DHL(x)	(((x) << PAS_DMA_RXINT_CFG_DHL_S) & \
 					 PAS_DMA_RXINT_CFG_DHL_M)
 #define    PAS_DMA_RXINT_CFG_LW		0x00200000
 #define    PAS_DMA_RXINT_CFG_L2		0x00100000
+#define    PAS_DMA_RXINT_CFG_HEN	0x00080000
 #define    PAS_DMA_RXINT_CFG_WIF	0x00000002
 #define    PAS_DMA_RXINT_CFG_WIL	0x00000001
 
@@ -425,10 +428,9 @@ enum {
 /* Receive descriptor fields */
 #define	XCT_MACRX_T		0x8000000000000000ull
 #define	XCT_MACRX_ST		0x4000000000000000ull
-#define XCT_MACRX_NORES		0x0000000000000000ull
-#define XCT_MACRX_8BRES		0x1000000000000000ull
-#define XCT_MACRX_24BRES	0x2000000000000000ull
-#define XCT_MACRX_40BRES	0x3000000000000000ull
+#define XCT_MACRX_RR_M		0x3000000000000000ull
+#define XCT_MACRX_RR_NORES	0x0000000000000000ull
+#define XCT_MACRX_RR_8BRES	0x1000000000000000ull
 #define XCT_MACRX_O		0x0400000000000000ull
 #define XCT_MACRX_E		0x0200000000000000ull
 #define XCT_MACRX_FF		0x0100000000000000ull
@@ -476,6 +478,17 @@ enum {
 #define XCT_PTR_ADDR(x)		((((long)(x)) << XCT_PTR_ADDR_S) & \
 				 XCT_PTR_ADDR_M)
 
+/* Receive interface 8byte result fields */
+#define XCT_RXRES_8B_L4O_M	0xff00000000000000ull
+#define XCT_RXRES_8B_L4O_S	56
+#define XCT_RXRES_8B_RULE_M	0x00ffff0000000000ull
+#define XCT_RXRES_8B_RULE_S	40
+#define XCT_RXRES_8B_EVAL_M	0x000000ffff000000ull
+#define XCT_RXRES_8B_EVAL_S	24
+#define XCT_RXRES_8B_HTYPE_M	0x0000000000f00000ull
+#define XCT_RXRES_8B_HASH_M	0x00000000000fffffull
+#define XCT_RXRES_8B_HASH_S	0
+
 /* Receive interface buffer fields */
 #define XCT_RXB_LEN_M		0x0ffff00000000000ull
 #define XCT_RXB_LEN_S		44
#15 lore raw

PATCH 11/11 pasemi_mac: enable iommu support

In reply to Olof Johansson

pasemi_mac: use buffer index pointer in clean_rx()

Use the new features in B0 for buffer ring index on the receive side. This means we no longer have to search in the ring for where the buffer came from.

Also cleanup the RX cleaning side a little, while I was at it.

Note: Pre-B0 hardware is no longer supported, and needs a pile of other workarounds that are not being submitted for mainline inclusion. So the fact that this breaks old hardware is not a problem at this time.

drivers/net/pasemi_mac.c +33 -27
Index: k.org/drivers/net/pasemi_mac.c
===================================================================
@@ -243,9 +243,9 @@ static int pasemi_mac_setup_rx_resources
 			   PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
 
 	write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if),
-			   PAS_DMA_RXINT_CFG_DHL(3) |
-			   PAS_DMA_RXINT_CFG_L2 |
-			   PAS_DMA_RXINT_CFG_LW);
+		      PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 |
+		      PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP |
+		      PAS_DMA_RXINT_CFG_HEN);
 
 	ring->next_to_fill = 0;
 	ring->next_to_clean = 0;
@@ -402,13 +402,12 @@ static void pasemi_mac_free_rx_resources
 static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	int start = mac->rx->next_to_fill;
-	unsigned int fill, count;
+	int fill, count;
 
 	if (limit <= 0)
 		return;
 
-	fill = start;
+	fill = mac->rx->next_to_fill;
 	for (count = 0; count < limit; count++) {
 		struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill);
 		u64 *buff = &RX_BUFF(mac, fill);
@@ -446,10 +445,10 @@ static void pasemi_mac_replenish_rx_ring
 
 	wmb();
 
-	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count);
 	write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count);
 
-	mac->rx->next_to_fill += count;
+	mac->rx->next_to_fill = (mac->rx->next_to_fill + count) &
+				(RX_RING_SIZE - 1);
 }
 
 static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
@@ -517,15 +516,19 @@ static int pasemi_mac_clean_rx(struct pa
 	int count;
 	struct pasemi_mac_buffer *info;
 	struct sk_buff *skb;
-	unsigned int i, len;
+	unsigned int len;
 	u64 macrx;
 	dma_addr_t dma;
+	int buf_index;
+	u64 eval;
 
 	spin_lock(&mac->rx->lock);
 
 	n = mac->rx->next_to_clean;
 
-	for (count = limit; count; count--) {
+	prefetch(RX_RING(mac, n));
+
+	for (count = 0; count < limit; count++) {
 		macrx = RX_RING(mac, n);
 
 		if ((macrx & XCT_MACRX_E) ||
@@ -537,21 +540,14 @@ static int pasemi_mac_clean_rx(struct pa
 
 		info = NULL;
 
-		/* We have to scan for our skb since there's no way
-		 * to back-map them from the descriptor, and if we
-		 * have several receive channels then they might not
-		 * show up in the same order as they were put on the
-		 * interface ring.
-		 */
+		BUG_ON(!(macrx & XCT_MACRX_RR_8BRES));
 
-		dma = (RX_RING(mac, n+1) & XCT_PTR_ADDR_M);
-		for (i = mac->rx->next_to_fill;
-		     i < (mac->rx->next_to_fill + RX_RING_SIZE);
-		     i++) {
-			info = &RX_RING_INFO(mac, i);
-			if (info->dma == dma)
-				break;
-		}
+		eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >>
+			XCT_RXRES_8B_EVAL_S;
+		buf_index = eval-1;
+
+		dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M);
+		info = &RX_RING_INFO(mac, buf_index);
 
 		skb = info->skb;
 
@@ -600,9 +596,9 @@ static int pasemi_mac_clean_rx(struct pa
 		/* Need to zero it out since hardware doesn't, since the
 		 * replenish loop uses it to tell when it's done.
 		 */
-		RX_BUFF(mac, i) = 0;
+		RX_BUFF(mac, buf_index) = 0;
 
-		n += 2;
+		n += 4;
 	}
 
 	if (n > RX_RING_SIZE) {
@@ -610,8 +606,16 @@ static int pasemi_mac_clean_rx(struct pa
 		write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0);
 		n &= (RX_RING_SIZE-1);
 	}
+
 	mac->rx->next_to_clean = n;
-	pasemi_mac_replenish_rx_ring(mac->netdev, limit-count);
+
+	/* Increase is in number of 16-byte entries, and since each descriptor
+	 * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
+	 * count*2.
+	 */
+	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1);
+
+	pasemi_mac_replenish_rx_ring(mac->netdev, count);
 
 	spin_unlock(&mac->rx->lock);
 
@@ -927,6 +931,8 @@ static int pasemi_mac_open(struct net_de
 
 	pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE);
 
+	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1);
+
 	flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
 		PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
 
drivers/net/pasemi_mac.h +17 -4
Index: k.org/drivers/net/pasemi_mac.h
===================================================================
@@ -206,12 +206,15 @@ enum {
 #define    PAS_DMA_RXINT_RCMDSTA_DROPS_M	0xfffe0000
 #define    PAS_DMA_RXINT_RCMDSTA_DROPS_S	17
 #define PAS_DMA_RXINT_CFG(i)		(0x204+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_CFG_RBP	0x80000000
+#define    PAS_DMA_RXINT_CFG_ITRR	0x40000000
 #define    PAS_DMA_RXINT_CFG_DHL_M	0x07000000
 #define    PAS_DMA_RXINT_CFG_DHL_S	24
 #define    PAS_DMA_RXINT_CFG_DHL(x)	(((x) << PAS_DMA_RXINT_CFG_DHL_S) & \
 					 PAS_DMA_RXINT_CFG_DHL_M)
 #define    PAS_DMA_RXINT_CFG_LW		0x00200000
 #define    PAS_DMA_RXINT_CFG_L2		0x00100000
+#define    PAS_DMA_RXINT_CFG_HEN	0x00080000
 #define    PAS_DMA_RXINT_CFG_WIF	0x00000002
 #define    PAS_DMA_RXINT_CFG_WIL	0x00000001
 
@@ -425,10 +428,9 @@ enum {
 /* Receive descriptor fields */
 #define	XCT_MACRX_T		0x8000000000000000ull
 #define	XCT_MACRX_ST		0x4000000000000000ull
-#define XCT_MACRX_NORES		0x0000000000000000ull
-#define XCT_MACRX_8BRES		0x1000000000000000ull
-#define XCT_MACRX_24BRES	0x2000000000000000ull
-#define XCT_MACRX_40BRES	0x3000000000000000ull
+#define XCT_MACRX_RR_M		0x3000000000000000ull
+#define XCT_MACRX_RR_NORES	0x0000000000000000ull
+#define XCT_MACRX_RR_8BRES	0x1000000000000000ull
 #define XCT_MACRX_O		0x0400000000000000ull
 #define XCT_MACRX_E		0x0200000000000000ull
 #define XCT_MACRX_FF		0x0100000000000000ull
@@ -476,6 +478,17 @@ enum {
 #define XCT_PTR_ADDR(x)		((((long)(x)) << XCT_PTR_ADDR_S) & \
 				 XCT_PTR_ADDR_M)
 
+/* Receive interface 8byte result fields */
+#define XCT_RXRES_8B_L4O_M	0xff00000000000000ull
+#define XCT_RXRES_8B_L4O_S	56
+#define XCT_RXRES_8B_RULE_M	0x00ffff0000000000ull
+#define XCT_RXRES_8B_RULE_S	40
+#define XCT_RXRES_8B_EVAL_M	0x000000ffff000000ull
+#define XCT_RXRES_8B_EVAL_S	24
+#define XCT_RXRES_8B_HTYPE_M	0x0000000000f00000ull
+#define XCT_RXRES_8B_HASH_M	0x00000000000fffffull
+#define XCT_RXRES_8B_HASH_S	0
+
 /* Receive interface buffer fields */
 #define XCT_RXB_LEN_M		0x0ffff00000000000ull
 #define XCT_RXB_LEN_S		44
#16 lore raw

Re: [PATCH] [11/11] pasemi_mac: enable iommu support

Quoted 6 lines · Olof Johansson

pasemi_mac: use buffer index pointer in clean_rx()

Use the new features in B0 for buffer ring index on the receive side. This means we no longer have to search in the ring for where the buffer came from.

Quoted 7 lines

Also cleanup the RX cleaning side a little, while I was at it.

Note: Pre-B0 hardware is no longer supported, and needs a pile of other workarounds that are not being submitted for mainline inclusion. So the fact that this breaks old hardware is not a problem at this time.

You sent patch #10 against as patch #11 :)

#17 lore raw

PATCH RESEND 11/11 pasemi_mac: enable iommu support

pasemi_mac: enable iommu support

Enable IOMMU support for pasemi_mac, but avoid using it on non-partitioned systems for performance reasons.

The user can override this by selecting the PPC_PASEMI_IOMMU_DMA_FORCE configuration option.

---

Quoted 1 line · Jeff Garzik

You sent patch #10 against as patch #11 :)

Oops! Here's the real copy.

-Olof

arch/powerpc/platforms/pasemi/iommu.c +10 -5
Index: k.org/arch/powerpc/platforms/pasemi/iommu.c
===================================================================
@@ -25,6 +25,7 @@
 #include <asm/iommu.h>
 #include <asm/machdep.h>
 #include <asm/abs_addr.h>
+#include <asm/firmware.h>
 
 
 #define IOBMAP_PAGE_SHIFT	12
@@ -175,13 +176,17 @@ static void pci_dma_dev_setup_pasemi(str
 {
 	pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev));
 
-	/* DMA device is untranslated, but all other PCI-e goes through
-	 * the IOMMU
+#if !defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE)
+	/* For non-LPAR environment, don't translate anything for the DMA
+	 * engine. The exception to this is if the user has enabled
+	 * CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE at build time.
 	 */
-	if (dev->vendor == 0x1959 && dev->device == 0xa007)
+	if (dev->vendor == 0x1959 && dev->device == 0xa007 &&
+	    !firmware_has_feature(FW_FEATURE_LPAR))
 		dev->dev.archdata.dma_ops = &dma_direct_ops;
-	else
-		dev->dev.archdata.dma_data = &iommu_table_iobmap;
+#endif
+
+	dev->dev.archdata.dma_data = &iommu_table_iobmap;
 }
 
 static void pci_dma_bus_setup_null(struct pci_bus *b) { }
drivers/net/pasemi_mac.c +37 -13

92 lines not on this page · raw message

drivers/net/pasemi_mac.h +6 -2
Index: k.org/drivers/net/pasemi_mac.h
===================================================================
@@ -212,6 +212,7 @@ enum {
 #define    PAS_DMA_RXINT_CFG_DHL_S	24
 #define    PAS_DMA_RXINT_CFG_DHL(x)	(((x) << PAS_DMA_RXINT_CFG_DHL_S) & \
 					 PAS_DMA_RXINT_CFG_DHL_M)
+#define    PAS_DMA_RXINT_CFG_ITR	0x00400000
 #define    PAS_DMA_RXINT_CFG_LW		0x00200000
 #define    PAS_DMA_RXINT_CFG_L2		0x00100000
 #define    PAS_DMA_RXINT_CFG_HEN	0x00080000
@@ -258,9 +259,11 @@ enum {
 #define    PAS_DMA_TXCHAN_CFG_WT_S	6
 #define    PAS_DMA_TXCHAN_CFG_WT(x)	(((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
 					 PAS_DMA_TXCHAN_CFG_WT_M)
-#define    PAS_DMA_TXCHAN_CFG_CF	0x00001000	/* Clean first line */
-#define    PAS_DMA_TXCHAN_CFG_CL	0x00002000	/* Clean last line */
+#define    PAS_DMA_TXCHAN_CFG_TRD	0x00010000	/* translate data */
+#define    PAS_DMA_TXCHAN_CFG_TRR	0x00008000	/* translate rings */
 #define    PAS_DMA_TXCHAN_CFG_UP	0x00004000	/* update tx descr when sent */
+#define    PAS_DMA_TXCHAN_CFG_CL	0x00002000	/* Clean last line */
+#define    PAS_DMA_TXCHAN_CFG_CF	0x00001000	/* Clean first line */
 #define PAS_DMA_TXCHAN_INCR(c)    (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
 #define PAS_DMA_TXCHAN_BASEL(c)   (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
 #define    PAS_DMA_TXCHAN_BASEL_BRBL_M	0xffffffc0
@@ -294,6 +297,7 @@ enum {
 #define    PAS_DMA_RXCHAN_CCMDSTA_FD	0x00001000
 #define    PAS_DMA_RXCHAN_CCMDSTA_DT	0x00000800
 #define PAS_DMA_RXCHAN_CFG(c)     (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_CFG_CTR	0x00000400
 #define    PAS_DMA_RXCHAN_CFG_HBU_M	0x00000380
 #define    PAS_DMA_RXCHAN_CFG_HBU_S	7
 #define    PAS_DMA_RXCHAN_CFG_HBU(x)	(((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
arch/powerpc/platforms/pasemi/Kconfig +10 -0
Index: k.org/arch/powerpc/platforms/pasemi/Kconfig
===================================================================
@@ -19,6 +19,16 @@ config PPC_PASEMI_IOMMU
 	help
 	  IOMMU support for PA6T-1682M
 
+config PPC_PASEMI_IOMMU_DMA_FORCE
+	bool "Force DMA engine to use IOMMU"
+	depends on PPC_PASEMI_IOMMU
+	help
+	  This option forces the use of the IOMMU also for the
+	  DMA engine. Otherwise the kernel will use it only when
+	  running under a hypervisor.
+
+	  If in doubt, say "N".
+
 config PPC_PASEMI_MDIO
 	depends on PHYLIB
 	tristate "MDIO support via GPIO"
Applied
#18 lore raw

Re: [PATCH RESEND] [11/11] pasemi_mac: enable iommu support

Quoted 9 lines · Olof Johansson

pasemi_mac: enable iommu support

Enable IOMMU support for pasemi_mac, but avoid using it on non-partitioned systems for performance reasons.

The user can override this by selecting the PPC_PASEMI_IOMMU_DMA_FORCE configuration option.

applied