drivers/net/wireless/intel/iwlwifi/mld/notif.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/intel/iwlwifi/mld/notif.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/intel/iwlwifi/mld/notif.c
Extension
.c
Size
25156 bytes
Lines
743
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

struct iwl_async_handler_entry {
	struct list_head list;
	struct iwl_rx_cmd_buffer rxb;
	const struct iwl_rx_handler *rx_h;
};

static void
iwl_mld_log_async_handler_op(struct iwl_mld *mld, const char *op,
			     struct iwl_rx_cmd_buffer *rxb)
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);

	IWL_DEBUG_HC(mld,
		     "%s async handler for notif %s (%.2x.%2x, seq 0x%x)\n",
		     op, iwl_get_cmd_string(mld->trans,
		     WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)),
		     pkt->hdr.group_id, pkt->hdr.cmd,
		     le16_to_cpu(pkt->hdr.sequence));
}

static void iwl_mld_rx_notif(struct iwl_mld *mld,
			     struct iwl_rx_cmd_buffer *rxb,
			     struct iwl_rx_packet *pkt)
{
	union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt };

	for (int i = 0; i < ARRAY_SIZE(iwl_mld_rx_handlers); i++) {
		const struct iwl_rx_handler *rx_h = &iwl_mld_rx_handlers[i];
		struct iwl_async_handler_entry *entry;

		if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd))
			continue;

		if (!iwl_mld_notif_is_valid(mld, pkt, rx_h))
			return;

		if (rx_h->context == RX_HANDLER_SYNC) {
			rx_h->fn(mld, pkt);
			break;
		}

		entry = kzalloc_obj(*entry, GFP_ATOMIC);
		/* we can't do much... */
		if (!entry)
			return;

		/* Set the async handler entry */
		entry->rxb._page = rxb_steal_page(rxb);
		entry->rxb._offset = rxb->_offset;
		entry->rxb._rx_page_order = rxb->_rx_page_order;

		entry->rx_h = rx_h;

		/* Add it to the list and queue the work */
		spin_lock(&mld->async_handlers_lock);
		list_add_tail(&entry->list, &mld->async_handlers_list);
		spin_unlock(&mld->async_handlers_lock);

		wiphy_work_queue(mld->hw->wiphy,
				 &mld->async_handlers_wk);

		iwl_mld_log_async_handler_op(mld, "Queued", rxb);
		break;
	}

	iwl_notification_wait_notify(&mld->notif_wait, pkt);
	iwl_dbg_tlv_time_point(&mld->fwrt,
			       IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF, &tp_data);
}

void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi,
		struct iwl_rx_cmd_buffer *rxb)
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
	u16 cmd_id = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);

	if (likely(cmd_id == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD)))
		iwl_mld_rx_mpdu(mld, napi, rxb, 0);
	else if (cmd_id == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE))
		iwl_mld_handle_frame_release_notif(mld, napi, pkt, 0);
	else if (cmd_id == WIDE_ID(LEGACY_GROUP, BAR_FRAME_RELEASE))
		iwl_mld_handle_bar_frame_release_notif(mld, napi, pkt, 0);
	else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP,
					    RX_QUEUES_NOTIFICATION)))
		iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, 0);
#ifdef CONFIG_PM_SLEEP
	else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP,
					    RSC_NOTIF)))
		iwl_mld_handle_rsc_notif(mld, pkt, 0);

Annotation

Implementation Notes