drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/rx.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/rx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/rx.c
Extension
.c
Size
73921 bytes
Lines
2486
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

test_bit(STATUS_TPOWER_PMI, &trans->status)) {
		reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);

		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
			IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup, GP1 = 0x%x\n",
				       reg);
			iwl_set_bit(trans, CSR_GP_CNTRL,
				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
			rxq->need_update = true;
			return;
		}
	}

	rxq->write_actual = round_down(rxq->write, 8);
	if (!trans->mac_cfg->mq_rx_supported)
		iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
	else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
		iwl_write32(trans, HBUS_TARG_WRPTR, rxq->write_actual |
			    HBUS_TARG_WRPTR_RX_Q(rxq->id));
	else
		iwl_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id),
			    rxq->write_actual);
}

static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
{
	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
	int i;

	for (i = 0; i < trans->info.num_rxqs; i++) {
		struct iwl_rxq *rxq = &trans_pcie->rxq[i];

		if (!rxq->need_update)
			continue;
		spin_lock_bh(&rxq->lock);
		iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
		rxq->need_update = false;
		spin_unlock_bh(&rxq->lock);
	}
}

static void iwl_pcie_restock_bd(struct iwl_trans *trans,
				struct iwl_rxq *rxq,
				struct iwl_rx_mem_buffer *rxb)
{
	if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
		struct iwl_rx_transfer_desc *bd = rxq->bd;

		BUILD_BUG_ON(sizeof(*bd) != 2 * sizeof(u64));

		bd[rxq->write].addr = cpu_to_le64(rxb->page_dma);
		bd[rxq->write].rbid = cpu_to_le16(rxb->vid);
	} else {
		__le64 *bd = rxq->bd;

		bd[rxq->write] = cpu_to_le64(rxb->page_dma | rxb->vid);
	}

	IWL_DEBUG_RX(trans, "Assigned virtual RB ID %u to queue %d index %d\n",
		     (u32)rxb->vid, rxq->id, rxq->write);
}

/*
 * iwl_pcie_rxmq_restock - restock implementation for multi-queue rx
 */
static void iwl_pcie_rxmq_restock(struct iwl_trans *trans,
				  struct iwl_rxq *rxq)
{
	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
	struct iwl_rx_mem_buffer *rxb;

	/*
	 * If the device isn't enabled - no 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 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->status))
		return;

	spin_lock_bh(&rxq->lock);
	while (rxq->free_count) {
		/* Get next free Rx buffer, remove from free list */
		rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer,
				       list);
		list_del(&rxb->list);
		rxb->invalid = false;
		/* some low bits are expected to be unset (depending on hw) */

Annotation

Implementation Notes