Message ID | 201105182025.50070.IvDoorn@gmail.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
Hi, I tested the patches and got this during boot on a rt3070 chip: [ 14.173458] ------------[ cut here ]------------ [ 14.173482] WARNING: at /home/marc/ac100/marvin24s-kernel/kernel/softirq.c:159 local_bh_enable_ip+0x4c/0xcc() [ 14.173490] Modules linked in: binfmt_misc snd_soc_tegra_paz00 snd_soc_alc5632 snd_soc_tegra_i2s snd_soc_tegra_pcm snd_soc_tegra_das rt2800usb snd_soc_core snd_pcm_oss rt2800lib rt2x00usb snd_mixer_oss rt2x00lib snd_pcm mac80211 snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq cfg80211 snd_timer snd_seq_device uvcvideo rfkill cdc_acm snd cdc_wdm videodev snd_soc_tegra_utils soundcore snd_page_alloc g_cdc btrfs [ 14.173567] Backtrace: [ 14.173607] [<c0043708>] (unwind_backtrace+0x0/0xe0) from [<c00753f8>] (warn_slowpath_common+0x4c/0x64) [ 14.173628] [<c00753f8>] (warn_slowpath_common+0x4c/0x64) from [<c0075428>] (warn_slowpath_null+0x18/0x1c) [ 14.173646] [<c0075428>] (warn_slowpath_null+0x18/0x1c) from [<c007bc80>] (local_bh_enable_ip+0x4c/0xcc) [ 14.173676] [<c007bc80>] (local_bh_enable_ip+0x4c/0xcc) from [<bf40b9b4>] (rt2x00usb_interrupt_rxdone+0x30/0x70 [rt2x00usb]) [ 14.173723] [<bf40b9b4>] (rt2x00usb_interrupt_rxdone+0x30/0x70 [rt2x00usb]) from [<c02d9150>] (usb_hcd_giveback_urb+0x74/0xbc) [ 14.173752] [<c02d9150>] (usb_hcd_giveback_urb+0x74/0xbc) from [<c02e75f8>] (ehci_urb_done+0x90/0x9c) [ 14.173775] [<c02e75f8>] (ehci_urb_done+0x90/0x9c) from [<c02eb284>] (qh_completions+0xb4/0x3ec) [ 14.173795] [<c02eb284>] (qh_completions+0xb4/0x3ec) from [<c02ec4b8>] (ehci_work+0xb4/0x97c) [ 14.173814] [<c02ec4b8>] (ehci_work+0xb4/0x97c) from [<c02ed3d0>] (ehci_irq+0x21c/0x24c) [ 14.173830] [<c02ed3d0>] (ehci_irq+0x21c/0x24c) from [<c02d8b34>] (usb_hcd_irq+0x34/0x6c) [ 14.173865] [<c02d8b34>] (usb_hcd_irq+0x34/0x6c) from [<c00bb840>] (handle_IRQ_event+0x9c/0x1b4) [ 14.173884] [<c00bb840>] (handle_IRQ_event+0x9c/0x1b4) from [<c00bd4fc>] (handle_level_irq+0xd0/0x154) [ 14.173910] [<c00bd4fc>] (handle_level_irq+0xd0/0x154) from [<c0037080>] (asm_do_IRQ+0x80/0xb4) [ 14.173943] [<c0037080>] (asm_do_IRQ+0x80/0xb4) from [<c040d84c>] (__irq_svc+0x4c/0xe0) [ 14.173954] Exception stack(0xdb84be10 to 0xdb84be58) [ 14.173964] be00: db929800 db28dc60 00000000 dcc00000 [ 14.173979] be20: db28dc60 dcd20000 00000000 00000010 db929800 00000008 00000010 db28dc98 [ 14.173991] be40: 00000000 db84be58 c026c86c c026ef58 60000013 ffffffff [ 14.174027] [<c040d84c>] (__irq_svc+0x4c/0xe0) from [<c026ef58>] (cfb_imageblit+0x54/0x43c) [ 14.174047] [<c026ef58>] (cfb_imageblit+0x54/0x43c) from [<c026c86c>] (soft_cursor+0x1a0/0x1a8) [ 14.174065] [<c026c86c>] (soft_cursor+0x1a0/0x1a8) from [<c026c254>] (bit_cursor+0x41c/0x42c) [ 14.174083] [<c026c254>] (bit_cursor+0x41c/0x42c) from [<c0266d08>] (fb_flashcursor+0xfc/0x118) [ 14.174114] [<c0266d08>] (fb_flashcursor+0xfc/0x118) from [<c008c9a0>] (process_one_work+0x274/0x43c) [ 14.174136] [<c008c9a0>] (process_one_work+0x274/0x43c) from [<c008e698>] (worker_thread+0x1b8/0x2b4) [ 14.174159] [<c008e698>] (worker_thread+0x1b8/0x2b4) from [<c0091d5c>] (kthread+0x7c/0x84) [ 14.174190] [<c0091d5c>] (kthread+0x7c/0x84) from [<c003d470>] (kernel_thread_exit+0x0/0x8) [ 14.174202] ---[ end trace 7b2804cb6c2b13fe ]--- Of course, this didn't happen before. Thanks Marc Am Mittwoch 18 Mai 2011, 20:25:49 schrieb Ivo van Doorn: > From: Gertjan van Wingerde <gwingerde@gmail.com> > > These two functions are only used by rt2800usb so they don't have to be > in rt2800lib. > > Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com> > Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> > --- > drivers/net/wireless/rt2x00/rt2800lib.c | 82 > ------------------------------ drivers/net/wireless/rt2x00/rt2800lib.h | > 1 - > drivers/net/wireless/rt2x00/rt2800usb.c | 83 > ++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 84 > deletions(-) > > diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c > b/drivers/net/wireless/rt2x00/rt2800lib.c index 445d681..562dc1d 100644 > --- a/drivers/net/wireless/rt2x00/rt2800lib.c > +++ b/drivers/net/wireless/rt2x00/rt2800lib.c > @@ -601,49 +601,6 @@ void rt2800_process_rxwi(struct queue_entry *entry, > } > EXPORT_SYMBOL_GPL(rt2800_process_rxwi); > > -static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) > -{ > - __le32 *txwi; > - u32 word; > - int wcid, ack, pid; > - int tx_wcid, tx_ack, tx_pid; > - > - wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); > - ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); > - pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); > - > - /* > - * This frames has returned with an IO error, > - * so the status report is not intended for this > - * frame. > - */ > - if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { > - rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); > - return false; > - } > - > - /* > - * Validate if this TX status report is intended for > - * this entry by comparing the WCID/ACK/PID fields. > - */ > - txwi = rt2800_drv_get_txwi(entry); > - > - rt2x00_desc_read(txwi, 1, &word); > - tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); > - tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); > - tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); > - > - if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { > - WARNING(entry->queue->rt2x00dev, > - "TX status report missed for queue %d entry %d\n", > - entry->queue->qid, entry->entry_idx); > - rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); > - return false; > - } > - > - return true; > -} > - > void rt2800_txdone_entry(struct queue_entry *entry, u32 status) > { > struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; > @@ -726,45 +683,6 @@ void rt2800_txdone_entry(struct queue_entry *entry, > u32 status) } > EXPORT_SYMBOL_GPL(rt2800_txdone_entry); > > -void rt2800_txdone(struct rt2x00_dev *rt2x00dev) > -{ > - struct data_queue *queue; > - struct queue_entry *entry; > - u32 reg; > - u8 qid; > - > - while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { > - > - /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus > - * qid is guaranteed to be one of the TX QIDs > - */ > - qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); > - queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); > - if (unlikely(!queue)) { > - WARNING(rt2x00dev, "Got TX status for an unavailable " > - "queue %u, dropping\n", qid); > - continue; > - } > - > - /* > - * Inside each queue, we process each entry in a chronological > - * order. We first check that the queue is not empty. > - */ > - entry = NULL; > - while (!rt2x00queue_empty(queue)) { > - entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); > - if (rt2800_txdone_entry_check(entry, reg)) > - break; > - } > - > - if (!entry || rt2x00queue_empty(queue)) > - break; > - > - rt2800_txdone_entry(entry, reg); > - } > -} > -EXPORT_SYMBOL_GPL(rt2800_txdone); > - > void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc > *txdesc) { > struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; > diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h > b/drivers/net/wireless/rt2x00/rt2800lib.h index f2d1594..69deb31 100644 > --- a/drivers/net/wireless/rt2x00/rt2800lib.h > +++ b/drivers/net/wireless/rt2x00/rt2800lib.h > @@ -152,7 +152,6 @@ void rt2800_write_tx_data(struct queue_entry *entry, > struct txentry_desc *txdesc); > void rt2800_process_rxwi(struct queue_entry *entry, struct > rxdone_entry_desc *txdesc); > > -void rt2800_txdone(struct rt2x00_dev *rt2x00dev); > void rt2800_txdone_entry(struct queue_entry *entry, u32 status); > > void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc > *txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c > b/drivers/net/wireless/rt2x00/rt2800usb.c index ba82c97..6e92298 100644 > --- a/drivers/net/wireless/rt2x00/rt2800usb.c > +++ b/drivers/net/wireless/rt2x00/rt2800usb.c > @@ -457,6 +457,87 @@ static int rt2800usb_get_tx_data_len(struct > queue_entry *entry) /* > * TX control handlers > */ > +static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 > reg) +{ > + __le32 *txwi; > + u32 word; > + int wcid, ack, pid; > + int tx_wcid, tx_ack, tx_pid; > + > + wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); > + ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); > + pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); > + > + /* > + * This frames has returned with an IO error, > + * so the status report is not intended for this > + * frame. > + */ > + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { > + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); > + return false; > + } > + > + /* > + * Validate if this TX status report is intended for > + * this entry by comparing the WCID/ACK/PID fields. > + */ > + txwi = rt2800usb_get_txwi(entry); > + > + rt2x00_desc_read(txwi, 1, &word); > + tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); > + tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); > + tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); > + > + if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { > + WARNING(entry->queue->rt2x00dev, > + "TX status report missed for queue %d entry %d\n", > + entry->queue->qid, entry->entry_idx); > + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); > + return false; > + } > + > + return true; > +} > + > +static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) > +{ > + struct data_queue *queue; > + struct queue_entry *entry; > + u32 reg; > + u8 qid; > + > + while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { > + > + /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus > + * qid is guaranteed to be one of the TX QIDs > + */ > + qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); > + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); > + if (unlikely(!queue)) { > + WARNING(rt2x00dev, "Got TX status for an unavailable " > + "queue %u, dropping\n", qid); > + continue; > + } > + > + /* > + * Inside each queue, we process each entry in a chronological > + * order. We first check that the queue is not empty. > + */ > + entry = NULL; > + while (!rt2x00queue_empty(queue)) { > + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); > + if (rt2800usb_txdone_entry_check(entry, reg)) > + break; > + } > + > + if (!entry || rt2x00queue_empty(queue)) > + break; > + > + rt2800_txdone_entry(entry, reg); > + } > +} > + > static void rt2800usb_work_txdone(struct work_struct *work) > { > struct rt2x00_dev *rt2x00dev = > @@ -464,7 +545,7 @@ static void rt2800usb_work_txdone(struct work_struct > *work) struct data_queue *queue; > struct queue_entry *entry; > > - rt2800_txdone(rt2x00dev); > + rt2800usb_txdone(rt2x00dev); > > /* > * Process any trailing TX status reports for IO failures, -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 05/18/11 22:38, Marc Dietrich wrote: > > Hi, > > I tested the patches and got this during boot on a rt3070 chip: > > [ 14.173458] ------------[ cut here ]------------ > [ 14.173482] WARNING: at /home/marc/ac100/marvin24s-kernel/kernel/softirq.c:159 local_bh_enable_ip+0x4c/0xcc() > [ 14.173490] Modules linked in: binfmt_misc snd_soc_tegra_paz00 snd_soc_alc5632 snd_soc_tegra_i2s snd_soc_tegra_pcm > snd_soc_tegra_das rt2800usb snd_soc_core snd_pcm_oss rt2800lib rt2x00usb snd_mixer_oss rt2x00lib snd_pcm mac80211 > snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq cfg80211 snd_timer snd_seq_device uvcvideo rfkill cdc_acm snd > cdc_wdm videodev snd_soc_tegra_utils soundcore snd_page_alloc g_cdc btrfs > [ 14.173567] Backtrace: > [ 14.173607] [<c0043708>] (unwind_backtrace+0x0/0xe0) from [<c00753f8>] (warn_slowpath_common+0x4c/0x64) > [ 14.173628] [<c00753f8>] (warn_slowpath_common+0x4c/0x64) from [<c0075428>] (warn_slowpath_null+0x18/0x1c) > [ 14.173646] [<c0075428>] (warn_slowpath_null+0x18/0x1c) from [<c007bc80>] (local_bh_enable_ip+0x4c/0xcc) > [ 14.173676] [<c007bc80>] (local_bh_enable_ip+0x4c/0xcc) from [<bf40b9b4>] (rt2x00usb_interrupt_rxdone+0x30/0x70 > [rt2x00usb]) > [ 14.173723] [<bf40b9b4>] (rt2x00usb_interrupt_rxdone+0x30/0x70 [rt2x00usb]) from [<c02d9150>] > (usb_hcd_giveback_urb+0x74/0xbc) > [ 14.173752] [<c02d9150>] (usb_hcd_giveback_urb+0x74/0xbc) from [<c02e75f8>] (ehci_urb_done+0x90/0x9c) > [ 14.173775] [<c02e75f8>] (ehci_urb_done+0x90/0x9c) from [<c02eb284>] (qh_completions+0xb4/0x3ec) > [ 14.173795] [<c02eb284>] (qh_completions+0xb4/0x3ec) from [<c02ec4b8>] (ehci_work+0xb4/0x97c) > [ 14.173814] [<c02ec4b8>] (ehci_work+0xb4/0x97c) from [<c02ed3d0>] (ehci_irq+0x21c/0x24c) > [ 14.173830] [<c02ed3d0>] (ehci_irq+0x21c/0x24c) from [<c02d8b34>] (usb_hcd_irq+0x34/0x6c) > [ 14.173865] [<c02d8b34>] (usb_hcd_irq+0x34/0x6c) from [<c00bb840>] (handle_IRQ_event+0x9c/0x1b4) > [ 14.173884] [<c00bb840>] (handle_IRQ_event+0x9c/0x1b4) from [<c00bd4fc>] (handle_level_irq+0xd0/0x154) > [ 14.173910] [<c00bd4fc>] (handle_level_irq+0xd0/0x154) from [<c0037080>] (asm_do_IRQ+0x80/0xb4) > [ 14.173943] [<c0037080>] (asm_do_IRQ+0x80/0xb4) from [<c040d84c>] (__irq_svc+0x4c/0xe0) > [ 14.173954] Exception stack(0xdb84be10 to 0xdb84be58) > [ 14.173964] be00: db929800 db28dc60 00000000 dcc00000 > [ 14.173979] be20: db28dc60 dcd20000 00000000 00000010 db929800 00000008 00000010 db28dc98 > [ 14.173991] be40: 00000000 db84be58 c026c86c c026ef58 60000013 ffffffff > [ 14.174027] [<c040d84c>] (__irq_svc+0x4c/0xe0) from [<c026ef58>] (cfb_imageblit+0x54/0x43c) > [ 14.174047] [<c026ef58>] (cfb_imageblit+0x54/0x43c) from [<c026c86c>] (soft_cursor+0x1a0/0x1a8) > [ 14.174065] [<c026c86c>] (soft_cursor+0x1a0/0x1a8) from [<c026c254>] (bit_cursor+0x41c/0x42c) > [ 14.174083] [<c026c254>] (bit_cursor+0x41c/0x42c) from [<c0266d08>] (fb_flashcursor+0xfc/0x118) > [ 14.174114] [<c0266d08>] (fb_flashcursor+0xfc/0x118) from [<c008c9a0>] (process_one_work+0x274/0x43c) > [ 14.174136] [<c008c9a0>] (process_one_work+0x274/0x43c) from [<c008e698>] (worker_thread+0x1b8/0x2b4) > [ 14.174159] [<c008e698>] (worker_thread+0x1b8/0x2b4) from [<c0091d5c>] (kthread+0x7c/0x84) > [ 14.174190] [<c0091d5c>] (kthread+0x7c/0x84) from [<c003d470>] (kernel_thread_exit+0x0/0x8) > [ 14.174202] ---[ end trace 7b2804cb6c2b13fe ]--- > > Of course, this didn't happen before. > Hmm, OK. This is not caused by the patch you responded to, but it is indeed introduced by an other patch. I have no idea how this has escaped my testing, as I did test the patches on USB devices as well, but there seems to be exactly 1 instance in which the queue index spin lock is still used in IRQ context, which escaped my attention. So, patch 6 of the series should not be applied right now. --- Gertjan -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 445d681..562dc1d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -601,49 +601,6 @@ void rt2800_process_rxwi(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2800_process_rxwi); -static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) -{ - __le32 *txwi; - u32 word; - int wcid, ack, pid; - int tx_wcid, tx_ack, tx_pid; - - wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); - ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); - pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); - - /* - * This frames has returned with an IO error, - * so the status report is not intended for this - * frame. - */ - if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { - rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); - return false; - } - - /* - * Validate if this TX status report is intended for - * this entry by comparing the WCID/ACK/PID fields. - */ - txwi = rt2800_drv_get_txwi(entry); - - rt2x00_desc_read(txwi, 1, &word); - tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); - tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); - tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); - - if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { - WARNING(entry->queue->rt2x00dev, - "TX status report missed for queue %d entry %d\n", - entry->queue->qid, entry->entry_idx); - rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); - return false; - } - - return true; -} - void rt2800_txdone_entry(struct queue_entry *entry, u32 status) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; @@ -726,45 +683,6 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) } EXPORT_SYMBOL_GPL(rt2800_txdone_entry); -void rt2800_txdone(struct rt2x00_dev *rt2x00dev) -{ - struct data_queue *queue; - struct queue_entry *entry; - u32 reg; - u8 qid; - - while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { - - /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus - * qid is guaranteed to be one of the TX QIDs - */ - qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); - queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); - if (unlikely(!queue)) { - WARNING(rt2x00dev, "Got TX status for an unavailable " - "queue %u, dropping\n", qid); - continue; - } - - /* - * Inside each queue, we process each entry in a chronological - * order. We first check that the queue is not empty. - */ - entry = NULL; - while (!rt2x00queue_empty(queue)) { - entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - if (rt2800_txdone_entry_check(entry, reg)) - break; - } - - if (!entry || rt2x00queue_empty(queue)) - break; - - rt2800_txdone_entry(entry, reg); - } -} -EXPORT_SYMBOL_GPL(rt2800_txdone); - void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index f2d1594..69deb31 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -152,7 +152,6 @@ void rt2800_write_tx_data(struct queue_entry *entry, struct txentry_desc *txdesc); void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc); -void rt2800_txdone(struct rt2x00_dev *rt2x00dev); void rt2800_txdone_entry(struct queue_entry *entry, u32 status); void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index ba82c97..6e92298 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -457,6 +457,87 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry) /* * TX control handlers */ +static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) +{ + __le32 *txwi; + u32 word; + int wcid, ack, pid; + int tx_wcid, tx_ack, tx_pid; + + wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); + ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); + pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); + + /* + * This frames has returned with an IO error, + * so the status report is not intended for this + * frame. + */ + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + return false; + } + + /* + * Validate if this TX status report is intended for + * this entry by comparing the WCID/ACK/PID fields. + */ + txwi = rt2800usb_get_txwi(entry); + + rt2x00_desc_read(txwi, 1, &word); + tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); + tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); + tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); + + if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { + WARNING(entry->queue->rt2x00dev, + "TX status report missed for queue %d entry %d\n", + entry->queue->qid, entry->entry_idx); + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); + return false; + } + + return true; +} + +static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + struct queue_entry *entry; + u32 reg; + u8 qid; + + while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { + + /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus + * qid is guaranteed to be one of the TX QIDs + */ + qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); + if (unlikely(!queue)) { + WARNING(rt2x00dev, "Got TX status for an unavailable " + "queue %u, dropping\n", qid); + continue; + } + + /* + * Inside each queue, we process each entry in a chronological + * order. We first check that the queue is not empty. + */ + entry = NULL; + while (!rt2x00queue_empty(queue)) { + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + if (rt2800usb_txdone_entry_check(entry, reg)) + break; + } + + if (!entry || rt2x00queue_empty(queue)) + break; + + rt2800_txdone_entry(entry, reg); + } +} + static void rt2800usb_work_txdone(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = @@ -464,7 +545,7 @@ static void rt2800usb_work_txdone(struct work_struct *work) struct data_queue *queue; struct queue_entry *entry; - rt2800_txdone(rt2x00dev); + rt2800usb_txdone(rt2x00dev); /* * Process any trailing TX status reports for IO failures,