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

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

pasemi_mac: Fix TX ring wrap checking



The old logic didn't detect full (tx) ring cases properly, causing
overruns and general badness. Clean it up a bit and abstract out the
ring size checks, always making sure to leave 1 slot open.

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 02df6cfa
Loading
Loading
Loading
Loading
+14 −11
Original line number Diff line number Diff line
@@ -69,6 +69,10 @@
#define RX_DESC_INFO(mac, num)	((mac)->rx->desc_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) \
				 & ((ring)->size - 1))
#define RING_AVAIL(ring)	((ring->size) - RING_USED(ring))

#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */

MODULE_LICENSE("GPL");
@@ -174,6 +178,7 @@ 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) *
				  RX_RING_SIZE, GFP_KERNEL);

@@ -253,6 +258,7 @@ 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) *
				  TX_RING_SIZE, GFP_KERNEL);
	if (!ring->desc_info)
@@ -281,7 +287,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
			   PAS_DMA_TXCHAN_CFG_UP |
			   PAS_DMA_TXCHAN_CFG_WT(2));

	ring->next_to_use = 0;
	ring->next_to_fill = 0;
	ring->next_to_clean = 0;

	snprintf(ring->irq_name, sizeof(ring->irq_name),
@@ -376,9 +382,7 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
	int start = mac->rx->next_to_fill;
	unsigned int limit, count;

	limit = (mac->rx->next_to_clean + RX_RING_SIZE -
		 mac->rx->next_to_fill) & (RX_RING_SIZE - 1);

	limit = RING_AVAIL(mac->rx);
	/* Check to see if we're doing first-time setup */
	if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
		limit = RX_RING_SIZE;
@@ -562,7 +566,7 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
	spin_lock_irqsave(&mac->tx->lock, flags);

	start = mac->tx->next_to_clean;
	limit = min(mac->tx->next_to_use, start+32);
	limit = min(mac->tx->next_to_fill, start+32);

	count = 0;

@@ -1004,14 +1008,13 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)

	spin_lock_irqsave(&txring->lock, flags);

	if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
	if (RING_AVAIL(txring) <= 1) {
		spin_unlock_irqrestore(&txring->lock, flags);
		pasemi_mac_clean_tx(mac);
		pasemi_mac_restart_tx_intr(mac);
		spin_lock_irqsave(&txring->lock, flags);

		if (txring->next_to_clean - txring->next_to_use ==
		    TX_RING_SIZE) {
		if (RING_AVAIL(txring) <= 1) {
			/* Still no room -- stop the queue and wait for tx
			 * intr when there's room.
			 */
@@ -1020,15 +1023,15 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
		}
	}

	dp = &TX_DESC(mac, txring->next_to_use);
	info = &TX_DESC_INFO(mac, txring->next_to_use);
	dp = &TX_DESC(mac, txring->next_to_fill);
	info = &TX_DESC_INFO(mac, txring->next_to_fill);

	dp->mactx = mactx;
	dp->ptr   = ptr;
	info->dma = map;
	info->skb = skb;

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

+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ struct pasemi_mac_txring {
	struct pas_dma_xct_descr	*desc;
	dma_addr_t	 dma;
	unsigned int	 size;
	unsigned int	 next_to_use;
	unsigned int	 next_to_fill;
	unsigned int	 next_to_clean;
	struct pasemi_mac_buffer *desc_info;
	char		 irq_name[10];  /* "eth%d tx" */