예제 #1
0
파일: rx.c 프로젝트: sosilent/kis_pc
/**
 * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
 *
 * If there are slots in the RX queue that need to be restocked,
 * and we have free pre-allocated buffers, fill the ranks as much
 * as we can, pulling from rx_free.
 *
 * This moves the 'write' index forward to catch up with 'processed', and
 * also updates the memory address in the firmware to reference the new
 * target buffer.
 */
static void iwl_rx_queue_restock(struct iwl_trans *trans)
{
    struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
    struct iwl_rx_queue *rxq = &trans_pcie->rxq;
    struct list_head *element;
    struct iwl_rx_mem_buffer *rxb;
    unsigned long flags;

    /*
     * If the device isn't enabled - not need to try to add buffers...
     * This can happen when we stop the device and still have an interrupt
     * pending. We stop the APM before we sync the interrupts / tasklets
     * because we have to (see comment there). On the other hand, since
     * the APM is stopped, we cannot access the HW (in particular not prph).
     * So don't try to restock if the APM has been already stopped.
     */
    if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status))
        return;

    spin_lock_irqsave(&rxq->lock, flags);
    while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
        /* The overwritten rxb must be a used one */
        rxb = rxq->queue[rxq->write];
        BUG_ON(rxb && rxb->page);

        /* Get next free Rx buffer, remove from free list */
        element = rxq->rx_free.next;
        rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
        list_del(element);

        /* Point to Rx buffer via next RBD in circular buffer */
        rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(rxb->page_dma);
        rxq->queue[rxq->write] = rxb;
        rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
        rxq->free_count--;
    }
    spin_unlock_irqrestore(&rxq->lock, flags);
    /* If the pre-allocated buffer pool is dropping low, schedule to
     * refill it */
    if (rxq->free_count <= RX_LOW_WATERMARK)
        schedule_work(&trans_pcie->rx_replenish);

    /* If we've added more space for the firmware to place data, tell it.
     * Increment device's write pointer in multiples of 8. */
    if (rxq->write_actual != (rxq->write & ~0x7)) {
        spin_lock_irqsave(&rxq->lock, flags);
        rxq->need_update = 1;
        spin_unlock_irqrestore(&rxq->lock, flags);
        iwl_rx_queue_update_write_ptr(trans, rxq);
    }
}
예제 #2
0
/**
 * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
 *
 * If there are slots in the RX queue that need to be restocked,
 * and we have free pre-allocated buffers, fill the ranks as much
 * as we can, pulling from rx_free.
 *
 * This moves the 'write' index forward to catch up with 'processed', and
 * also updates the memory address in the firmware to reference the new
 * target buffer.
 */
int iwl_rx_queue_restock(struct iwl_priv *priv)
{
	struct iwl_rx_queue *rxq = &priv->rxq;
	struct list_head *element;
	struct iwl_rx_mem_buffer *rxb;
	unsigned long flags;
	int write;
	int ret = 0;

	spin_lock_irqsave(&rxq->lock, flags);
	write = rxq->write & ~0x7;
	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
		/* Get next free Rx buffer, remove from free list */
		element = rxq->rx_free.next;
		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
		list_del(element);

		/* Point to Rx buffer via next RBD in circular buffer */
		rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->aligned_dma_addr);
		rxq->queue[rxq->write] = rxb;
		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
		rxq->free_count--;
	}
	spin_unlock_irqrestore(&rxq->lock, flags);
	/* If the pre-allocated buffer pool is dropping low, schedule to
	 * refill it */
	if (rxq->free_count <= RX_LOW_WATERMARK)
		queue_work(priv->workqueue, &priv->rx_replenish);


	/* If we've added more space for the firmware to place data, tell it.
	 * Increment device's write pointer in multiples of 8. */
	if (rxq->write_actual != (rxq->write & ~0x7)) {
		spin_lock_irqsave(&rxq->lock, flags);
		rxq->need_update = 1;
		spin_unlock_irqrestore(&rxq->lock, flags);
		ret = iwl_rx_queue_update_write_ptr(priv, rxq);
	}

	return ret;
}