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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/silabs/wfx/hif_tx.c
Extension
.c
Size
15924 bytes
Lines
538
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 (rates & BIT(i)) {
			if (i >= sband->n_bitrates)
				dev_warn(wdev->dev, "unsupported basic rate\n");
			else
				ret |= BIT(sband->bitrates[i].hw_value);
		}
	}
	return ret;
}

int wfx_cmd_send(struct wfx_dev *wdev, struct wfx_hif_msg *request,
		 void *reply, size_t reply_len, bool no_reply)
{
	const char *mib_name = "";
	const char *mib_sep = "";
	int cmd = request->id;
	int vif = request->interface;
	int ret;

	/* Do not wait for any reply if chip is frozen */
	if (wdev->chip_frozen)
		return -ETIMEDOUT;

	mutex_lock(&wdev->hif_cmd.lock);
	WARN(wdev->hif_cmd.buf_send, "data locking error");

	/* Note: call to complete() below has an implicit memory barrier that hopefully protect
	 * buf_send
	 */
	wdev->hif_cmd.buf_send = request;
	wdev->hif_cmd.buf_recv = reply;
	wdev->hif_cmd.len_recv = reply_len;
	complete(&wdev->hif_cmd.ready);

	wfx_bh_request_tx(wdev);

	if (no_reply) {
		/* Chip won't reply. Ensure the wq has send the buffer before to continue. */
		flush_workqueue(wdev->bh_wq);
		ret = 0;
		goto end;
	}

	if (wdev->poll_irq)
		wfx_bh_poll_irq(wdev);

	ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ);
	if (!ret) {
		dev_err(wdev->dev, "chip is abnormally long to answer\n");
		reinit_completion(&wdev->hif_cmd.ready);
		ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ);
	}
	if (!ret) {
		dev_err(wdev->dev, "chip did not answer\n");
		wfx_pending_dump_old_frames(wdev, 3000);
		wdev->chip_frozen = true;
		reinit_completion(&wdev->hif_cmd.done);
		ret = -ETIMEDOUT;
	} else {
		ret = wdev->hif_cmd.ret;
	}

end:
	wdev->hif_cmd.buf_send = NULL;
	mutex_unlock(&wdev->hif_cmd.lock);

	if (ret &&
	    (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) {
		mib_name = wfx_get_mib_name(((u16 *)request)[2]);
		mib_sep = "/";
	}
	if (ret < 0)
		dev_err(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned error %d\n",
			wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
	if (ret > 0)
		dev_warn(wdev->dev, "hardware request %s%s%s (%#.2x) on vif %d returned status %d\n",
			 wfx_get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);

	return ret;
}

/* This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any request anymore.
 * Obviously, only call this function during device unregister.
 */
int wfx_hif_shutdown(struct wfx_dev *wdev)
{
	int ret;
	struct wfx_hif_msg *hif;

	wfx_alloc_hif(0, &hif);

Annotation

Implementation Notes