drivers/net/wireless/silabs/wfx/bh.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/silabs/wfx/bh.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/silabs/wfx/bh.c
Extension
.c
Size
8840 bytes
Lines
325
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

if (wait_for_completion_timeout(&wdev->hif.ctrl_ready, msecs_to_jiffies(2))) {
			complete(&wdev->hif.ctrl_ready);
			return;
		} else if (max_retry-- > 0) {
			/* Older firmwares have a race in sleep/wake-up process.  Redo the process
			 * is sufficient to unfreeze the chip.
			 */
			dev_err(wdev->dev, "timeout while wake up chip\n");
			gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0);
			usleep_range(2000, 2500);
		} else {
			dev_err(wdev->dev, "max wake-up retries reached\n");
			return;
		}
	}
}

static void device_release(struct wfx_dev *wdev)
{
	if (!wdev->pdata.gpio_wakeup)
		return;

	gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0);
}

static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
{
	struct sk_buff *skb;
	struct wfx_hif_msg *hif;
	size_t alloc_len;
	size_t computed_len;
	int release_count;
	int piggyback = 0;

	WARN(read_len > round_down(0xFFF, 2) * sizeof(u16), "request exceed the chip capability");

	/* Add 2 to take into account piggyback size */
	alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2);
	skb = dev_alloc_skb(alloc_len);
	if (!skb)
		return -ENOMEM;

	if (wfx_data_read(wdev, skb->data, alloc_len))
		goto err;

	piggyback = le16_to_cpup((__le16 *)(skb->data + alloc_len - 2));
	_trace_piggyback(piggyback, false);

	hif = (struct wfx_hif_msg *)skb->data;
	WARN(hif->encrypted & 0x3, "encryption is unsupported");
	if (WARN(read_len < sizeof(struct wfx_hif_msg), "corrupted read"))
		goto err;
	computed_len = le16_to_cpu(hif->len);
	computed_len = round_up(computed_len, 2);
	if (computed_len != read_len) {
		dev_err(wdev->dev, "inconsistent message length: %zu != %zu\n",
			computed_len, read_len);
		print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, 16, 1,
			       hif, read_len, true);
		goto err;
	}

	if (!(hif->id & HIF_ID_IS_INDICATION)) {
		(*is_cnf)++;
		if (hif->id == HIF_CNF_ID_MULTI_TRANSMIT)
			release_count =
				((struct wfx_hif_cnf_multi_transmit *)hif->body)->num_tx_confs;
		else
			release_count = 1;
		WARN(wdev->hif.tx_buffers_used < release_count, "corrupted buffer counter");
		wdev->hif.tx_buffers_used -= release_count;
	}
	_trace_hif_recv(hif, wdev->hif.tx_buffers_used);

	if (hif->id != HIF_IND_ID_EXCEPTION && hif->id != HIF_IND_ID_ERROR) {
		if (hif->seqnum != wdev->hif.rx_seqnum)
			dev_warn(wdev->dev, "wrong message sequence: %d != %d\n",
				 hif->seqnum, wdev->hif.rx_seqnum);
		wdev->hif.rx_seqnum = (hif->seqnum + 1) % (HIF_COUNTER_MAX + 1);
	}

	skb_put(skb, le16_to_cpu(hif->len));
	/* wfx_handle_rx takes care on SKB livetime */
	wfx_handle_rx(wdev, skb);
	if (!wdev->hif.tx_buffers_used)
		wake_up(&wdev->hif.tx_buffers_empty);

	return piggyback;

err:

Annotation

Implementation Notes