drivers/i3c/master/mipi-i3c-hci/core.c

Source file repositories/reference/linux-study-clean/drivers/i3c/master/mipi-i3c-hci/core.c

File Facts

System
Linux kernel
Corpus path
drivers/i3c/master/mipi-i3c-hci/core.c
Extension
.c
Size
33197 bytes
Lines
1231
Domain
Driver Families
Bucket
drivers/i3c
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

scoped_guard(spinlock_irqsave, &hci->lock) {
			started = xfer[0].started;
			time_taken = jiffies - xfer[0].start_jiffies;
		}
		/* Keep waiting if xfer has not started */
		if (!started)
			continue;
		/* Recalculate timeout based on actual start time */
		if (time_taken < timeout) {
			remaining_timeout = timeout - time_taken;
			continue;
		}
		if (hci->io->dequeue_xfer(hci, xfer, n)) {
			dev_err(&hci->master.dev, "%s: timeout error\n", __func__);
			return -ETIMEDOUT;
		}
		return 0;
	}

	if (hci->io->handle_error) {
		bool error = false;

		for (int i = 0; i < n && !error; i++)
			error = RESP_STATUS(xfer[i].response);
		if (error)
			return hci->io->handle_error(hci, xfer, n);
	}

	return 0;
}

static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
				struct i3c_ccc_cmd *ccc)
{
	struct i3c_hci *hci = to_i3c_hci(m);
	struct hci_xfer *xfer;
	bool raw = !!(hci->quirks & HCI_QUIRK_RAW_CCC);
	bool prefixed = raw && !!(ccc->id & I3C_CCC_DIRECT);
	unsigned int nxfers = ccc->ndests + prefixed;
	DECLARE_COMPLETION_ONSTACK(done);
	int i, last, ret = 0;

	dev_dbg(&hci->master.dev, "cmd=%#x rnw=%d ndests=%d data[0].len=%d",
		ccc->id, ccc->rnw, ccc->ndests, ccc->dests[0].payload.len);

	xfer = hci_alloc_xfer(nxfers);
	if (!xfer)
		return -ENOMEM;

	if (prefixed) {
		xfer->data = NULL;
		xfer->data_len = 0;
		xfer->rnw = false;
		hci->cmd->prep_ccc(hci, xfer, I3C_BROADCAST_ADDR,
				   ccc->id, true);
		xfer++;
	}

	for (i = 0; i < nxfers - prefixed; i++) {
		xfer[i].data = ccc->dests[i].payload.data;
		xfer[i].data_len = ccc->dests[i].payload.len;
		xfer[i].rnw = ccc->rnw;
		ret = hci->cmd->prep_ccc(hci, &xfer[i], ccc->dests[i].addr,
					 ccc->id, raw);
		if (ret)
			goto out;
		xfer[i].cmd_desc[0] |= CMD_0_ROC;
	}
	last = i - 1;
	xfer[last].cmd_desc[0] |= CMD_0_TOC;
	xfer[last].completion = &done;
	xfer[last].timeout = HZ;

	if (prefixed)
		xfer--;

	ret = i3c_hci_process_xfer(hci, xfer, nxfers);
	if (ret)
		goto out;
	for (i = prefixed; i < nxfers; i++) {
		if (ccc->rnw)
			ccc->dests[i - prefixed].payload.len =
				RESP_DATA_LENGTH(xfer[i].response);
		switch (RESP_STATUS(xfer[i].response)) {
		case RESP_SUCCESS:
			continue;
		case RESP_ERR_ADDR_HEADER:
		case RESP_ERR_NACK:
			ccc->err = I3C_ERROR_M2;
			fallthrough;

Annotation

Implementation Notes