/** * All queues have been kicked, now wait for each queue * to become empty. With a bit of luck, we only have to wait * for the first queue to become empty, because while waiting * for the that queue, the other queues will have transmitted * all their frames as well (since they were already kicked). */ tx_queue_for_each(rt2x00dev, queue) { for (i = 0; i < 10; i++) { if (rt2x00queue_empty(queue)) break; msleep(100); } if (!rt2x00queue_empty(queue)) WARNING(rt2x00dev, "Failed to flush queue %d", queue->qid); }
/* * 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_IO_FAILED, &entry->flags)) break; rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); } } }
/* * RX data handlers. */ static void rt2x00usb_work_rxdone(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, rxdone_work); struct queue_entry *entry; struct skb_frame_desc *skbdesc; u8 rxd[32]; while (!rt2x00queue_empty(rt2x00dev->rx)) { entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE); if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) break; /* * Fill in desc fields of the skb descriptor */ skbdesc = get_skb_frame_desc(entry->skb); skbdesc->desc = rxd; skbdesc->desc_len = entry->queue->desc_size; /* * Send the frame to rt2x00lib for further processing. */ rt2x00lib_rxdone(entry, GFP_KERNEL); } }
void rt2x00usb_kick_queue(struct data_queue *queue) { switch (queue->qid) { case QID_AC_VO: case QID_AC_VI: case QID_AC_BE: case QID_AC_BK: if (!rt2x00queue_empty(queue)) rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, rt2x00usb_kick_tx_entry); break; case QID_RX: if (!rt2x00queue_full(queue)) rt2x00queue_for_each_entry(queue, Q_INDEX, Q_INDEX_DONE, NULL, rt2x00usb_kick_rx_entry); break; default: break; } }
void rt2x00pci_flush_queue(struct data_queue *queue, bool drop) { unsigned int i; for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++) msleep(10); }
/* * Interrupt functions. */ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const enum ieee80211_tx_queue queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); struct queue_entry_priv_pci_tx *priv_tx; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); priv_tx = entry->priv_data; rt2x00_desc_read(priv_tx->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) break; /* * Obtain the status about this packet. */ txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); rt2x00pci_txdone(rt2x00dev, entry, &txdesc); } }
static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); struct queue_entry_priv_pci *entry_priv; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry_priv = entry->priv_data; rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) break; txdesc.flags = 0; switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { case 0: case 1: __set_bit(TXDONE_SUCCESS, &txdesc.flags); break; case 2: __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); default: __set_bit(TXDONE_FAILURE, &txdesc.flags); } txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); rt2x00lib_txdone(entry, &txdesc); } }
/* * Interrupt functions. */ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) { struct ieee80211_conf conf = { .flags = 0 }; struct rt2x00lib_conf libconf = { .conf = &conf }; rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; u32 status; u8 qid; while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); if (qid >= QID_RX) { /* * Unknown queue, this shouldn't happen. Just drop * this tx status. */ WARNING(rt2x00dev, "Got TX status report with " "unexpected pid %u, dropping\n", qid); break; } queue = rt2x00queue_get_queue(rt2x00dev, qid); if (unlikely(queue == NULL)) { /* * The queue is NULL, this shouldn't happen. Stop * processing here and drop the tx status */ WARNING(rt2x00dev, "Got TX status for an unavailable " "queue %u, dropping\n", qid); break; } if (rt2x00queue_empty(queue)) { /* * The queue is empty. Stop processing here * and drop the tx status. */ WARNING(rt2x00dev, "Got TX status for an empty " "queue %u, dropping\n", qid); break; } entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); rt2800_txdone_entry(entry, status); } } static void rt2800pci_txstatus_tasklet(unsigned long data) { rt2800pci_txdone((struct rt2x00_dev *)data); }
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; tx_queue_for_each(rt2x00dev, queue) { if (!rt2x00queue_empty(queue)) { if (rt2x00usb_dma_timeout(queue)) rt2x00usb_watchdog_tx_dma(queue); } } }
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, rt2800usb_get_txwi(entry)); } }
void rt2x00usb_flush_queue(struct data_queue *queue, bool drop) { struct work_struct *completion; unsigned int i; if (drop) rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, rt2x00usb_flush_entry); /* * Obtain the queue completion handler */ switch (queue->qid) { case QID_AC_VO: case QID_AC_VI: case QID_AC_BE: case QID_AC_BK: completion = &queue->rt2x00dev->txdone_work; break; case QID_RX: completion = &queue->rt2x00dev->rxdone_work; break; default: return; } for (i = 0; i < 10; i++) { /* * Check if the driver is already done, otherwise we * have to sleep a little while to give the driver/hw * the oppurtunity to complete interrupt process itself. */ if (rt2x00queue_empty(queue)) break; /* * Schedule the completion handler manually, when this * worker function runs, it should cleanup the queue. */ queue_work(queue->rt2x00dev->workqueue, completion); /* * Wait for a little while to give the driver * the oppurtunity to recover itself. */ msleep(10); } }
static void rt2x00usb_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; 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)) break; rt2x00usb_work_txdone_entry(entry); } } }
/* * 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)); }
/* * Interrupt functions. */ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue_idx) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); struct queue_entry_priv_pci *entry_priv; struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry_priv = entry->priv_data; rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) break; /* * Obtain the status about this packet. */ txdesc.flags = 0; switch (rt2x00_get_field32(word, TXD_W0_RESULT)) { case 0: /* Success */ case 1: /* Success with retry */ __set_bit(TXDONE_SUCCESS, &txdesc.flags); break; case 2: /* Failure, excessive retries */ __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags); /* Don't break, this is a failed frame! */ default: /* Failure */ __set_bit(TXDONE_FAILURE, &txdesc.flags); } txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); rt2x00lib_txdone(entry, &txdesc); } }
static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue) { struct queue_entry_priv_usb *entry_priv; unsigned short threshold = queue->threshold; WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid); /* * Temporarily disable the TX queue, this will force mac80211 * to use the other queues until this queue has been restored. * * Set the queue threshold to the queue limit. This prevents the * queue from being enabled during the txdone handler. */ queue->threshold = queue->limit; ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid); /* * Reset all currently uploaded TX frames. */ while (!rt2x00queue_empty(queue)) { entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data; usb_kill_urb(entry_priv->urb); /* * We need a short delay here to wait for * the URB to be canceled and invoked the tx_done handler. */ udelay(200); } /* * The queue has been reset, and mac80211 is allowed to use the * queue again. */ queue->threshold = threshold; ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid); }
static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; u32 status; u8 qid; int max_tx_done = 16; while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); if (unlikely(qid >= QID_RX)) { /* * Unknown queue, this shouldn't happen. Just drop * this tx status. */ rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n", qid); break; } queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); if (unlikely(queue == NULL)) { /* * The queue is NULL, this shouldn't happen. Stop * processing here and drop the tx status */ rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n", qid); break; } if (unlikely(rt2x00queue_empty(queue))) { /* * The queue is empty. Stop processing here * and drop the tx status. */ rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n", qid); break; } /* * Let's associate this tx status with the first * matching frame. */ if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, &status, rt2800pci_txdone_find_entry)) { /* * We cannot match the tx status to any frame, so just * use the first one. */ if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, &status, rt2800pci_txdone_match_first)) { rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n", qid); break; } } /* * Release all frames with a valid tx status. */ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, rt2800pci_txdone_release_entries); if (--max_tx_done == 0) break; } return !max_tx_done; }
/* * Interrupt functions. */ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) { struct ieee80211_conf conf = { .flags = 0 }; struct rt2x00lib_conf libconf = { .conf = &conf }; rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; u32 status; u8 qid; int max_tx_done = 16; while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); if (unlikely(qid >= QID_RX)) { /* * Unknown queue, this shouldn't happen. Just drop * this tx status. */ WARNING(rt2x00dev, "Got TX status report with " "unexpected pid %u, dropping\n", qid); break; } queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); if (unlikely(queue == NULL)) { /* * The queue is NULL, this shouldn't happen. Stop * processing here and drop the tx status */ WARNING(rt2x00dev, "Got TX status for an unavailable " "queue %u, dropping\n", qid); break; } if (unlikely(rt2x00queue_empty(queue))) { /* * The queue is empty. Stop processing here * and drop the tx status. */ WARNING(rt2x00dev, "Got TX status for an empty " "queue %u, dropping\n", qid); break; } entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); rt2800_txdone_entry(entry, status, rt2800pci_get_txwi(entry)); if (--max_tx_done == 0) break; } return !max_tx_done; } static inline void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, struct rt2x00_field32 irq_field) { u32 reg; /* * Enable a single interrupt. The interrupt mask register * access needs locking. */ spin_lock_irq(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, irq_field, 1); rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock_irq(&rt2x00dev->irqmask_lock); }