Ejemplo n.º 1
0
	/**
	 * 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);
	}
Ejemplo n.º 2
0
/*
 * 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);
		}
	}
}
Ejemplo n.º 3
0
/*
 * 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);
    }
}
Ejemplo n.º 4
0
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;
    }
}
Ejemplo n.º 5
0
void rt2x00pci_flush_queue(struct data_queue *queue, bool drop)
{
	unsigned int i;

	for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
		msleep(10);
}
Ejemplo n.º 6
0
/*
 * 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);
	}
}
Ejemplo n.º 8
0
/*
 * 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);
}
Ejemplo n.º 9
0
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);
        }
    }
}
Ejemplo n.º 10
0
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, &reg)) {

		/* 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));
	}
}
Ejemplo n.º 11
0
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);
    }
}
Ejemplo n.º 12
0
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);
		}
	}
}
Ejemplo n.º 13
0
/*
 * 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));
}
Ejemplo n.º 14
0
/*
 * 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);
	}
}
Ejemplo n.º 15
0
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);
}
Ejemplo n.º 16
0
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;
}
Ejemplo n.º 17
0
/*
 * 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, &reg);
    rt2x00_set_field32(&reg, irq_field, 1);
    rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
    spin_unlock_irq(&rt2x00dev->irqmask_lock);
}