diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2008-05-10 07:42:06 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-05-21 21:47:30 -0400 |
commit | fb55f4d1fa252ba1e479284b79da1049d658c371 (patch) | |
tree | 0922dcd4e12037026293dd41914d774f06955641 /drivers/net/wireless | |
parent | 5a6e59991b82580c3ca00115603b85762ec76104 (diff) |
rt2x00: Fix TX status reporting
The tx_status enumeration was broken since the introduction
of rt61pci. That driver uses different values to report the
status of the tx action.
This would lead to frames that were reported as success but
actually failed to be send out, or frames that were neither
successfull or failure which were reported as failure.
Fix this by change the TX status reporting and more explicitely
check for failure or success. Note that a third possibility is
added "unknown". Not all hardware (USB) can report the actual
TX status, for rt61pci some frames will receive this status
because the TXdone handler is never called for those frames.
This unknown will now be handled as neither success or failure,
so we no longer increment the failure counter while this conclusion
could not be determined from the real status of the frame.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2400pci.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500pci.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.h | 20 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00reg.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt61pci.c | 15 |
7 files changed, 76 insertions, 31 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index afa565c63621..69b1dbd1adf0 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1137,7 +1137,18 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, | |||
1137 | /* | 1137 | /* |
1138 | * Obtain the status about this packet. | 1138 | * Obtain the status about this packet. |
1139 | */ | 1139 | */ |
1140 | txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); | 1140 | txdesc.flags = 0; |
1141 | switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { | ||
1142 | case 0: /* Success */ | ||
1143 | case 1: /* Success with retry */ | ||
1144 | __set_bit(TXDONE_SUCCESS, &txdesc.flags); | ||
1145 | break; | ||
1146 | case 2: /* Failure, excessive retries */ | ||
1147 | __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); | ||
1148 | /* Don't break, this is a failed frame! */ | ||
1149 | default: /* Failure */ | ||
1150 | __set_bit(TXDONE_FAILURE, &txdesc.flags); | ||
1151 | } | ||
1141 | txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); | 1152 | txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); |
1142 | 1153 | ||
1143 | rt2x00pci_txdone(rt2x00dev, entry, &txdesc); | 1154 | rt2x00pci_txdone(rt2x00dev, entry, &txdesc); |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c06f1b5e5887..aa195dab1554 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1292,7 +1292,18 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, | |||
1292 | /* | 1292 | /* |
1293 | * Obtain the status about this packet. | 1293 | * Obtain the status about this packet. |
1294 | */ | 1294 | */ |
1295 | txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); | 1295 | txdesc.flags = 0; |
1296 | switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { | ||
1297 | case 0: /* Success */ | ||
1298 | case 1: /* Success with retry */ | ||
1299 | __set_bit(TXDONE_SUCCESS, &txdesc.flags); | ||
1300 | break; | ||
1301 | case 2: /* Failure, excessive retries */ | ||
1302 | __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); | ||
1303 | /* Don't break, this is a failed frame! */ | ||
1304 | default: /* Failure */ | ||
1305 | __set_bit(TXDONE_FAILURE, &txdesc.flags); | ||
1306 | } | ||
1296 | txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); | 1307 | txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); |
1297 | 1308 | ||
1298 | rt2x00pci_txdone(rt2x00dev, entry, &txdesc); | 1309 | rt2x00pci_txdone(rt2x00dev, entry, &txdesc); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index ea130f2eb008..69da22cf085c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -496,38 +496,36 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
496 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 496 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
497 | struct skb_frame_desc *skbdesc; | 497 | struct skb_frame_desc *skbdesc; |
498 | struct ieee80211_tx_status tx_status; | 498 | struct ieee80211_tx_status tx_status; |
499 | int success = !!(txdesc->status == TX_SUCCESS || | ||
500 | txdesc->status == TX_SUCCESS_RETRY); | ||
501 | int fail = !!(txdesc->status == TX_FAIL_RETRY || | ||
502 | txdesc->status == TX_FAIL_INVALID || | ||
503 | txdesc->status == TX_FAIL_OTHER); | ||
504 | 499 | ||
505 | /* | 500 | /* |
506 | * Update TX statistics. | 501 | * Update TX statistics. |
507 | */ | 502 | */ |
508 | rt2x00dev->link.qual.tx_success += success; | 503 | rt2x00dev->link.qual.tx_success += |
509 | rt2x00dev->link.qual.tx_failed += txdesc->retry + fail; | 504 | test_bit(TXDONE_SUCCESS, &txdesc->flags); |
505 | rt2x00dev->link.qual.tx_failed += | ||
506 | txdesc->retry + !!test_bit(TXDONE_FAILURE, &txdesc->flags); | ||
510 | 507 | ||
511 | /* | 508 | /* |
512 | * Initialize TX status | 509 | * Initialize TX status |
513 | */ | 510 | */ |
514 | tx_status.flags = 0; | 511 | tx_status.flags = 0; |
515 | tx_status.ack_signal = 0; | 512 | tx_status.ack_signal = 0; |
516 | tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY); | 513 | tx_status.excessive_retries = |
514 | test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); | ||
517 | tx_status.retry_count = txdesc->retry; | 515 | tx_status.retry_count = txdesc->retry; |
518 | memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); | 516 | memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); |
519 | 517 | ||
520 | if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { | 518 | if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { |
521 | if (success) | 519 | if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) |
522 | tx_status.flags |= IEEE80211_TX_STATUS_ACK; | 520 | tx_status.flags |= IEEE80211_TX_STATUS_ACK; |
523 | else | 521 | else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) |
524 | rt2x00dev->low_level_stats.dot11ACKFailureCount++; | 522 | rt2x00dev->low_level_stats.dot11ACKFailureCount++; |
525 | } | 523 | } |
526 | 524 | ||
527 | if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { | 525 | if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { |
528 | if (success) | 526 | if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) |
529 | rt2x00dev->low_level_stats.dot11RTSSuccessCount++; | 527 | rt2x00dev->low_level_stats.dot11RTSSuccessCount++; |
530 | else | 528 | else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) |
531 | rt2x00dev->low_level_stats.dot11RTSFailureCount++; | 529 | rt2x00dev->low_level_stats.dot11RTSFailureCount++; |
532 | } | 530 | } |
533 | 531 | ||
@@ -546,7 +544,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
546 | ieee80211_tx_status_irqsafe(rt2x00dev->hw, | 544 | ieee80211_tx_status_irqsafe(rt2x00dev->hw, |
547 | entry->skb, &tx_status); | 545 | entry->skb, &tx_status); |
548 | else | 546 | else |
549 | dev_kfree_skb(entry->skb); | 547 | dev_kfree_skb_irq(entry->skb); |
550 | entry->skb = NULL; | 548 | entry->skb = NULL; |
551 | } | 549 | } |
552 | EXPORT_SYMBOL_GPL(rt2x00lib_txdone); | 550 | EXPORT_SYMBOL_GPL(rt2x00lib_txdone); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index c3493ed7f4c3..f361f784965e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h | |||
@@ -168,18 +168,34 @@ struct rxdone_entry_desc { | |||
168 | }; | 168 | }; |
169 | 169 | ||
170 | /** | 170 | /** |
171 | * enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc | ||
172 | * | ||
173 | * @TXDONE_UNKNOWN: Hardware could not determine success of transmission. | ||
174 | * @TXDONE_SUCCESS: Frame was successfully send | ||
175 | * @TXDONE_FAILURE: Frame was not successfully send | ||
176 | * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the | ||
177 | * frame transmission failed due to excessive retries. | ||
178 | */ | ||
179 | enum txdone_entry_desc_flags { | ||
180 | TXDONE_UNKNOWN = 1 << 0, | ||
181 | TXDONE_SUCCESS = 1 << 1, | ||
182 | TXDONE_FAILURE = 1 << 2, | ||
183 | TXDONE_EXCESSIVE_RETRY = 1 << 3, | ||
184 | }; | ||
185 | |||
186 | /** | ||
171 | * struct txdone_entry_desc: TX done entry descriptor | 187 | * struct txdone_entry_desc: TX done entry descriptor |
172 | * | 188 | * |
173 | * Summary of information that has been read from the TX frame descriptor | 189 | * Summary of information that has been read from the TX frame descriptor |
174 | * after the device is done with transmission. | 190 | * after the device is done with transmission. |
175 | * | 191 | * |
176 | * @control: Control structure which was used to transmit the frame. | 192 | * @control: Control structure which was used to transmit the frame. |
177 | * @status: TX status (See &enum tx_status). | 193 | * @flags: TX done flags (See &enum txdone_entry_desc_flags). |
178 | * @retry: Retry count. | 194 | * @retry: Retry count. |
179 | */ | 195 | */ |
180 | struct txdone_entry_desc { | 196 | struct txdone_entry_desc { |
181 | struct ieee80211_tx_control *control; | 197 | struct ieee80211_tx_control *control; |
182 | int status; | 198 | unsigned long flags; |
183 | int retry; | 199 | int retry; |
184 | }; | 200 | }; |
185 | 201 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 0325bed2fbf5..3f255df58b78 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h | |||
@@ -27,17 +27,6 @@ | |||
27 | #define RT2X00REG_H | 27 | #define RT2X00REG_H |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * TX result flags. | ||
31 | */ | ||
32 | enum tx_status { | ||
33 | TX_SUCCESS = 0, | ||
34 | TX_SUCCESS_RETRY = 1, | ||
35 | TX_FAIL_RETRY = 2, | ||
36 | TX_FAIL_INVALID = 3, | ||
37 | TX_FAIL_OTHER = 4, | ||
38 | }; | ||
39 | |||
40 | /* | ||
41 | * Antenna values | 30 | * Antenna values |
42 | */ | 31 | */ |
43 | enum antenna { | 32 | enum antenna { |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 98aafc2d584a..caee65e82198 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -147,8 +147,17 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) | |||
147 | 147 | ||
148 | /* | 148 | /* |
149 | * Obtain the status about this packet. | 149 | * Obtain the status about this packet. |
150 | * Note that when the status is 0 it does not mean the | ||
151 | * frame was send out correctly. It only means the frame | ||
152 | * was succesfully pushed to the hardware, we have no | ||
153 | * way to determine the transmission status right now. | ||
154 | * (Only indirectly by looking at the failed TX counters | ||
155 | * in the register). | ||
150 | */ | 156 | */ |
151 | txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; | 157 | if (!urb->status) |
158 | __set_bit(TXDONE_UNKNOWN, &txdesc.flags); | ||
159 | else | ||
160 | __set_bit(TXDONE_FAILURE, &txdesc.flags); | ||
152 | txdesc.retry = 0; | 161 | txdesc.retry = 0; |
153 | txdesc.control = &priv_tx->control; | 162 | txdesc.control = &priv_tx->control; |
154 | 163 | ||
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index edddbf35bbab..15191d6581b1 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -1764,7 +1764,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) | |||
1764 | "TX status report missed for entry %d\n", | 1764 | "TX status report missed for entry %d\n", |
1765 | entry_done->entry_idx); | 1765 | entry_done->entry_idx); |
1766 | 1766 | ||
1767 | txdesc.status = TX_FAIL_OTHER; | 1767 | txdesc.flags = 0; |
1768 | __set_bit(TXDONE_UNKNOWN, &txdesc.flags); | ||
1768 | txdesc.retry = 0; | 1769 | txdesc.retry = 0; |
1769 | 1770 | ||
1770 | rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc); | 1771 | rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc); |
@@ -1774,7 +1775,17 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) | |||
1774 | /* | 1775 | /* |
1775 | * Obtain the status about this packet. | 1776 | * Obtain the status about this packet. |
1776 | */ | 1777 | */ |
1777 | txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); | 1778 | txdesc.flags = 0; |
1779 | switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) { | ||
1780 | case 0: /* Success, maybe with retry */ | ||
1781 | __set_bit(TXDONE_SUCCESS, &txdesc.flags); | ||
1782 | break; | ||
1783 | case 6: /* Failure, excessive retries */ | ||
1784 | __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); | ||
1785 | /* Don't break, this is a failed frame! */ | ||
1786 | default: /* Failure */ | ||
1787 | __set_bit(TXDONE_FAILURE, &txdesc.flags); | ||
1788 | } | ||
1778 | txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); | 1789 | txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); |
1779 | 1790 | ||
1780 | rt2x00pci_txdone(rt2x00dev, entry, &txdesc); | 1791 | rt2x00pci_txdone(rt2x00dev, entry, &txdesc); |