drivers/net/wireless/marvell/mwifiex/pcie.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/marvell/mwifiex/pcie.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/marvell/mwifiex/pcie.c
Extension
.c
Size
89980 bytes
Lines
3284
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static struct pci_driver mwifiex_pcie = {
	.name     = "mwifiex_pcie",
	.id_table = mwifiex_ids,
	.probe    = mwifiex_pcie_probe,
	.remove   = mwifiex_pcie_remove,
	.driver   = {
		.coredump = mwifiex_pcie_coredump,
#ifdef CONFIG_PM_SLEEP
		.pm = &mwifiex_pcie_pm_ops,
#endif
	},
	.shutdown = mwifiex_pcie_shutdown,
	.err_handler = &mwifiex_pcie_err_handler,
};

/*
 * This function adds delay loop to ensure FW is awake before proceeding.
 */
static void mwifiex_pcie_dev_wakeup_delay(struct mwifiex_adapter *adapter)
{
	int i = 0;

	while (mwifiex_pcie_ok_to_access_hw(adapter)) {
		i++;
		usleep_range(10, 20);
		/* 50ms max wait */
		if (i == 5000)
			break;
	}

	return;
}

static void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter,
					   u32 max_delay_loop_cnt)
{
	struct pcie_service_card *card = adapter->card;
	u8 *buffer;
	u32 sleep_cookie, count;
	struct sk_buff *cmdrsp = card->cmdrsp_buf;

	for (count = 0; count < max_delay_loop_cnt; count++) {
		dma_sync_single_for_cpu(&card->dev->dev,
					MWIFIEX_SKB_DMA_ADDR(cmdrsp),
					sizeof(sleep_cookie), DMA_FROM_DEVICE);
		buffer = cmdrsp->data;
		sleep_cookie = get_unaligned_le32(buffer);

		if (sleep_cookie == MWIFIEX_DEF_SLEEP_COOKIE) {
			mwifiex_dbg(adapter, INFO,
				    "sleep cookie found at count %d\n", count);
			break;
		}
		dma_sync_single_for_device(&card->dev->dev,
					   MWIFIEX_SKB_DMA_ADDR(cmdrsp),
					   sizeof(sleep_cookie),
					   DMA_FROM_DEVICE);
		usleep_range(20, 30);
	}

	if (count >= max_delay_loop_cnt)
		mwifiex_dbg(adapter, INFO,
			    "max count reached while accessing sleep cookie\n");
}

#define N_WAKEUP_TRIES_SHORT_INTERVAL 15
#define N_WAKEUP_TRIES_LONG_INTERVAL 35

/* This function wakes up the card by reading fw_status register. */
static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
{
	struct pcie_service_card *card = adapter->card;
	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
	int retval __maybe_unused;

	mwifiex_dbg(adapter, EVENT,
		    "event: Wakeup device...\n");

	if (reg->sleep_cookie)
		mwifiex_pcie_dev_wakeup_delay(adapter);

	/* The 88W8897 PCIe+USB firmware (latest version 15.68.19.p21) sometimes
	 * appears to ignore or miss our wakeup request, so we continue trying
	 * until we receive an interrupt from the card.
	 */
	if (read_poll_timeout(mwifiex_write_reg_rpt, retval,
			      READ_ONCE(adapter->int_status) != 0,
			      500, 500 * N_WAKEUP_TRIES_SHORT_INTERVAL,
			      false,
			      adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {

Annotation

Implementation Notes