/* * TX control handlers */ static void rt2800usb_work_txdone(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, txdone_work); struct data_queue *queue; struct queue_entry *entry; rt2800_txdone(rt2x00dev); /* * Process any trailing TX status reports for IO failures, * we loop until we find the first non-IO error entry. This * can either be a frame which is free, is being uploaded, * or has completed the upload but didn't have an entry * in the TX_STAT_FIFO register yet. */ tx_queue_for_each(rt2x00dev, queue) { while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) break; if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); else if (rt2x00queue_status_timeout(entry)) rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); else break; } } /* * The hw may delay sending the packet after DMA complete * if the medium is busy, thus the TX_STA_FIFO entry is * also delayed -> use a timer to retrieve it. */ if (rt2800usb_txstatus_pending(rt2x00dev)) mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); }
static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, int urb_status, u32 tx_status) { if (urb_status) { WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status); return false; } /* try to read all TX_STA_FIFO entries before scheduling txdone_work */ if (rt2x00_get_field32(tx_status, TX_STA_FIFO_VALID)) { if (!kfifo_put(&rt2x00dev->txstatus_fifo, &tx_status)) { WARNING(rt2x00dev, "TX status FIFO overrun, " "drop tx status report.\n"); queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } else return true; } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } else if (rt2800usb_txstatus_pending(rt2x00dev)) { mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); } return false; }