diff options
author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-09-22 00:34:53 +0000 |
---|---|---|
committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-09-22 00:34:53 +0000 |
commit | cc4fec07c7009508ce71b85f19252c2ff929bbdd (patch) | |
tree | d5b9c20d215d3125f9a1173c125f05c4e0b4d5b2 | |
parent | ddbfaa46f731b12d4a284452d9461c2c379e552f (diff) |
cns3xxx: fix ethernet driver tx completion and queue stop/start
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33504 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r-- | target/linux/cns3xxx/patches-3.3/430-ethernet_fix_tx_completion.patch | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/target/linux/cns3xxx/patches-3.3/430-ethernet_fix_tx_completion.patch b/target/linux/cns3xxx/patches-3.3/430-ethernet_fix_tx_completion.patch new file mode 100644 index 0000000000..9a16c99f8f --- /dev/null +++ b/target/linux/cns3xxx/patches-3.3/430-ethernet_fix_tx_completion.patch @@ -0,0 +1,110 @@ +--- a/drivers/net/ethernet/cavium/cns3xxx_eth.c ++++ b/drivers/net/ethernet/cavium/cns3xxx_eth.c +@@ -28,6 +28,7 @@ + + #define RX_DESCS 128 + #define TX_DESCS 128 ++#define TX_DESC_RESERVE 20 + + #define RX_POOL_ALLOC_SIZE (sizeof(struct rx_desc) * RX_DESCS) + #define TX_POOL_ALLOC_SIZE (sizeof(struct tx_desc) * TX_DESCS) +@@ -266,6 +267,7 @@ struct _tx_ring { + u32 cur_index; + int num_used; + int num_count; ++ bool stopped; + }; + + struct _rx_ring { +@@ -546,7 +548,34 @@ out: + rx_ring->alloc_index = i; + } + +-static void clear_tx_desc(struct sw *sw) ++static void eth_check_num_used(struct _tx_ring *tx_ring) ++{ ++ bool stop = false; ++ int i; ++ ++ if (tx_ring->num_used >= TX_DESCS - TX_DESC_RESERVE) ++ stop = true; ++ ++ if (tx_ring->stopped == stop) ++ return; ++ ++ tx_ring->stopped = stop; ++ for (i = 0; i < 4; i++) { ++ struct port *port = switch_port_tab[i]; ++ struct net_device *dev; ++ ++ if (!port) ++ continue; ++ ++ dev = port->netdev; ++ if (stop) ++ netif_stop_queue(dev); ++ else ++ netif_wake_queue(dev); ++ } ++} ++ ++static void eth_complete_tx(struct sw *sw) + { + struct _tx_ring *tx_ring = sw->tx_ring; + struct tx_desc *desc; +@@ -555,9 +584,6 @@ static void clear_tx_desc(struct sw *sw) + int num_used = tx_ring->num_used; + struct sk_buff *skb; + +- if (num_used < (TX_DESCS >> 1)) +- return; +- + index = tx_ring->free_index; + desc = &(tx_ring)->desc[index]; + for (i = 0; i < num_used; i++) { +@@ -580,6 +606,7 @@ static void clear_tx_desc(struct sw *sw) + } + tx_ring->free_index = index; + tx_ring->num_used -= i; ++ eth_check_num_used(tx_ring); + } + + static int eth_poll(struct napi_struct *napi, int budget) +@@ -688,6 +715,10 @@ static int eth_poll(struct napi_struct * + + enable_rx_dma(sw); + ++ spin_lock_bh(&tx_lock); ++ eth_complete_tx(sw); ++ spin_unlock_bh(&tx_lock); ++ + return received; + } + +@@ -732,21 +763,19 @@ static int eth_xmit(struct sk_buff *skb, + skb_walk_frags(skb, skb1) + nr_desc++; + +- spin_lock(&tx_lock); ++ spin_lock_bh(&tx_lock); + ++ eth_complete_tx(sw); + if ((tx_ring->num_used + nr_desc + 1) >= TX_DESCS) { +- clear_tx_desc(sw); +- if ((tx_ring->num_used + nr_desc + 1) >= TX_DESCS) { +- spin_unlock(&tx_lock); +- return NETDEV_TX_BUSY; +- } ++ spin_unlock_bh(&tx_lock); ++ return NETDEV_TX_BUSY; + } + + index = index0 = tx_ring->cur_index; + index_last = (index0 + nr_desc) % TX_DESCS; + tx_ring->cur_index = (index_last + 1) % TX_DESCS; + +- spin_unlock(&tx_lock); ++ spin_unlock_bh(&tx_lock); + + config0 = FORCE_ROUTE; + if (skb->ip_summed == CHECKSUM_PARTIAL) |