This is a patch for rt2x00 driver to do TX flow control. It is compile-tested only.
Signed-off-by: Jiri Benc <[EMAIL PROTECTED]> --- drivers/net/wireless/d80211/rt2x00/rt2400pci.c | 26 ++++++++++++++++++------- drivers/net/wireless/d80211/rt2x00/rt2500pci.c | 26 ++++++++++++++++++------- drivers/net/wireless/d80211/rt2x00/rt2500usb.c | 18 +++++++++++++---- drivers/net/wireless/d80211/rt2x00/rt61pci.c | 26 ++++++++++++++++++------- drivers/net/wireless/d80211/rt2x00/rt73usb.c | 18 +++++++++++++---- 5 files changed, 85 insertions(+), 29 deletions(-) --- dscape.orig/drivers/net/wireless/d80211/rt2x00/rt2400pci.c +++ dscape/drivers/net/wireless/d80211/rt2x00/rt2400pci.c @@ -1001,7 +1001,7 @@ rt2400pci_txdone(void *data) struct data_entry *entry; struct txd *txd; int tx_status; - int ack; + int ack, wake, queue; while (!rt2x00_ring_empty(ring)) { entry = rt2x00_get_data_entry_done(ring); @@ -1048,7 +1048,11 @@ rt2400pci_txdone(void *data) rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0); entry->skb = NULL; + wake = rt2x00_ring_full(ring); + queue = entry->tx_status.control.queue; rt2x00_ring_index_done_inc(ring); + if (wake) + ieee80211_wake_queue(ring->net_dev, queue); } /* @@ -1541,24 +1545,31 @@ rt2400pci_tx(struct net_device *net_dev, ERROR("Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", control->queue, DRV_PROJECT); - return NET_XMIT_DROP; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } - if (rt2x00_ring_full(ring)) - return NET_XMIT_DROP; + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(net_dev, control->queue); + return NETDEV_TX_BUSY; + } entry = rt2x00_get_data_entry(ring); txd = entry->desc_addr; - if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) - || rt2x00_get_field32(txd->word0, TXD_W0_VALID)) - return NET_XMIT_DROP; + if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(txd->word0, TXD_W0_VALID)) { + ieee80211_stop_queue(net_dev, control->queue); + return NETDEV_TX_BUSY; + } memcpy(entry->data_addr, skb->data, skb->len); rt2400pci_write_tx_desc(rt2x00pci, txd, skb, control); entry->skb = skb; rt2x00_ring_index_inc(ring); + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(net_dev, control->queue); rt2x00_register_read(rt2x00pci, TXCSR0, ®); if (control->queue == IEEE80211_TX_QUEUE_DATA0) @@ -1668,6 +1679,7 @@ rt2400pci_open(struct net_device *net_de rt2x00_register_write(rt2x00pci, CSR8, reg); SET_FLAG(rt2x00pci, RADIO_ENABLED); + ieee80211_start_queues(net_dev); return 0; --- dscape.orig/drivers/net/wireless/d80211/rt2x00/rt2500pci.c +++ dscape/drivers/net/wireless/d80211/rt2x00/rt2500pci.c @@ -1089,7 +1089,7 @@ rt2500pci_txdone(void *data) struct data_entry *entry; struct txd *txd; int tx_status; - int ack; + int ack, wake, queue; while (!rt2x00_ring_empty(ring)) { entry = rt2x00_get_data_entry_done(ring); @@ -1136,7 +1136,11 @@ rt2500pci_txdone(void *data) rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0); entry->skb = NULL; + wake = rt2x00_ring_full(ring); + queue = entry->tx_status.control.queue; rt2x00_ring_index_done_inc(ring); + if (wake) + ieee80211_wake_queue(ring->net_dev, queue); } /* @@ -1664,24 +1668,31 @@ rt2500pci_tx(struct net_device *net_dev, ERROR("Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", control->queue, DRV_PROJECT); - return NET_XMIT_DROP; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } - if (rt2x00_ring_full(ring)) - return NET_XMIT_DROP; + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(net_dev, control->queue); + return NETDEV_TX_BUSY; + } entry = rt2x00_get_data_entry(ring); txd = entry->desc_addr; - if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) - || rt2x00_get_field32(txd->word0, TXD_W0_VALID)) - return NET_XMIT_DROP; + if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(txd->word0, TXD_W0_VALID)) { + ieee80211_stop_queue(net_dev, control->queue); + return NETDEV_TX_BUSY; + } memcpy(entry->data_addr, skb->data, skb->len); rt2500pci_write_tx_desc(rt2x00pci, txd, skb, control); entry->skb = skb; rt2x00_ring_index_inc(ring); + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(net_dev, control->queue); rt2x00_register_read(rt2x00pci, TXCSR0, ®); if (control->queue == IEEE80211_TX_QUEUE_DATA0) @@ -1791,6 +1802,7 @@ rt2500pci_open(struct net_device *net_de rt2x00_register_write(rt2x00pci, CSR8, reg); SET_FLAG(rt2x00pci, RADIO_ENABLED); + ieee80211_start_queues(net_dev); return 0; --- dscape.orig/drivers/net/wireless/d80211/rt2x00/rt2500usb.c +++ dscape/drivers/net/wireless/d80211/rt2x00/rt2500usb.c @@ -929,7 +929,7 @@ rt2500usb_txdone(void *data) ieee80211_dev_hw_data(ring->net_dev); struct data_entry *entry; struct txd *txd; - int ack; + int ack, wake, queue; while (!rt2x00_ring_empty(ring)) { entry = rt2x00_get_data_entry_done(ring); @@ -968,7 +968,11 @@ rt2500usb_txdone(void *data) entry->skb = NULL; + wake = rt2x00_ring_full(ring); + queue = entry->tx_status.control.queue; rt2x00_ring_index_done_inc(entry->ring); + if (wake) + ieee80211_wake_queue(ring->net_dev, queue); } /* @@ -1376,11 +1380,14 @@ rt2500usb_tx(struct net_device *net_dev, ERROR("Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", control->queue, DRV_PROJECT); - return NET_XMIT_DROP; + dev_kfree_skb_any(skb); + return NETDEV_TX_BUSY; } - if (rt2x00_ring_full(ring)) - return NET_XMIT_DROP; + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(net_dev, control->queue); + return NETDEV_TX_BUSY; + } entry = rt2x00_get_data_entry(ring); txd = rt2x00usb_txdesc_addr(entry); @@ -1401,6 +1408,8 @@ rt2500usb_tx(struct net_device *net_dev, usb_submit_urb(entry->urb, GFP_ATOMIC); rt2x00_ring_index_inc(ring); + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(net_dev, control->queue); return 0; } @@ -1468,6 +1477,7 @@ rt2500usb_open(struct net_device *net_de rt2500usb_enable_led(rt2x00usb); SET_FLAG(rt2x00usb, RADIO_ENABLED); + ieee80211_start_queues(net_dev); return 0; --- dscape.orig/drivers/net/wireless/d80211/rt2x00/rt61pci.c +++ dscape/drivers/net/wireless/d80211/rt2x00/rt61pci.c @@ -1351,7 +1351,7 @@ rt61pci_txdone(void *data) struct data_entry *entry; struct txd *txd; int tx_status; - int ack; + int ack, wake, queue; int reg; while (!rt2x00_ring_empty(ring)) { @@ -1402,7 +1402,11 @@ rt61pci_txdone(void *data) rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0); entry->skb = NULL; + wake = rt2x00_ring_full(ring); + queue = entry->tx_status.control.queue; rt2x00_ring_index_done_inc(ring); + if (wake) + ieee80211_wake_queue(ring->net_dev, queue); } /* @@ -2100,24 +2104,31 @@ rt61pci_tx(struct net_device *net_dev, ERROR("Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", control->queue, DRV_PROJECT); - return NET_XMIT_DROP; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } - if (rt2x00_ring_full(ring)) - return NET_XMIT_DROP; + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(net_dev, control->queue); + return NETDEV_TX_BUSY; + } entry = rt2x00_get_data_entry(ring); txd = entry->desc_addr; - if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) - || rt2x00_get_field32(txd->word0, TXD_W0_VALID)) - return NET_XMIT_DROP; + if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(txd->word0, TXD_W0_VALID)) { + ieee80211_stop_queue(net_dev, control->queue); + return NETDEV_TX_BUSY; + } memcpy(entry->data_addr, skb->data, skb->len); rt61pci_write_tx_desc(rt2x00pci, txd, skb, control); entry->skb = skb; rt2x00_ring_index_inc(ring); + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(net_dev, control->queue); rt2x00_register_read(rt2x00pci, TX_CNTL_CSR, ®); if (control->queue == IEEE80211_TX_QUEUE_DATA0) @@ -2248,6 +2259,7 @@ rt61pci_open(struct net_device *net_dev) rt2x00_register_write(rt2x00pci, INT_SOURCE_CSR, reg); SET_FLAG(rt2x00pci, RADIO_ENABLED); + ieee80211_start_queues(net_dev); return 0; --- dscape.orig/drivers/net/wireless/d80211/rt2x00/rt73usb.c +++ dscape/drivers/net/wireless/d80211/rt2x00/rt73usb.c @@ -1093,7 +1093,7 @@ rt73usb_txdone(void *data) ieee80211_dev_hw_data(ring->net_dev); struct data_entry *entry; struct txd *txd; - int ack; + int ack, wake, queue; while (!rt2x00_ring_empty(ring)) { entry = rt2x00_get_data_entry_done(ring); @@ -1132,7 +1132,11 @@ rt73usb_txdone(void *data) entry->skb = NULL; + wake = rt2x00_ring_full(ring); + queue = entry->tx_status.control.queue; rt2x00_ring_index_done_inc(entry->ring); + if (wake) + ieee80211_wake_queue(ring->net_dev, queue); } /* @@ -1668,11 +1672,14 @@ rt73usb_tx(struct net_device *net_dev, ERROR("Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", control->queue, DRV_PROJECT); - return NET_XMIT_DROP; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } - if (rt2x00_ring_full(ring)) - return NET_XMIT_DROP; + if (rt2x00_ring_full(ring)) { + ieee80211_stop_queue(net_dev, control->queue); + return NETDEV_TX_BUSY; + } entry = rt2x00_get_data_entry(ring); txd = rt2x00usb_txdesc_addr(entry); @@ -1693,6 +1700,8 @@ rt73usb_tx(struct net_device *net_dev, usb_submit_urb(entry->urb, GFP_ATOMIC); rt2x00_ring_index_inc(ring); + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(net_dev, control->queue); return 0; } @@ -1765,6 +1774,7 @@ rt73usb_open(struct net_device *net_dev) rt73usb_enable_led(rt2x00usb); SET_FLAG(rt2x00usb, RADIO_ENABLED); + ieee80211_start_queues(net_dev); return 0; - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html