Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc9e4d2a authored by Olof Johansson's avatar Olof Johansson Committed by David S. Miller
Browse files

pasemi_mac: rework ring management



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.

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 18eec695
Loading
Loading
Loading
Loading
+103 −110
Original line number Diff line number Diff line
@@ -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(struct net_device *dev)
	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(struct net_device *dev)

	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(struct net_device *dev)

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(struct net_device *dev)
	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(struct net_device *dev)

	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 net_device *dev)
	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) {
	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;
			dp->mactx = 0;
			dp->ptr = 0;
		}
	}

	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,13 +332,10 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev)
	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) {
		info = &RX_RING_INFO(mac, i);
		if (info->skb && info->dma) {
			pci_unmap_single(mac->dma_pdev,
					 info->dma,
					 info->skb->len,
@@ -353,19 +344,19 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev)
		}
		info->dma = 0;
		info->skb = NULL;
			dp->macrx = 0;
			dp->ptr = 0;
		}
	}

	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(struct net_device *dev)
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(struct net_device *dev, int limit)
		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 pasemi_mac *mac, int limit)
{
	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 pasemi_mac *mac, int limit)

		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 pasemi_mac *mac, int limit)
		 * 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 pasemi_mac *mac, int limit)
		} 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 pasemi_mac *mac, int limit)
		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 pasemi_mac *mac)
{
	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 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac)

	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_buff *skb, struct net_device *dev)
{
	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_buff *skb, struct net_device *dev)

	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_buff *skb, struct net_device *dev)
		}
	}

	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;

	dp->mactx = mactx;
	dp->ptr   = ptr;
	info->dma = map;
	info->skb = skb;
	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 += 2;

	txring->next_to_fill++;
	dev->stats.tx_packets++;
	dev->stats.tx_bytes += skb->len;

+5 −18
Original line number Diff line number Diff line
@@ -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,