static void cdns_i3c_master_end_xfer_locked()

in master/i3c-master-cdns.c [557:629]


static void cdns_i3c_master_end_xfer_locked(struct cdns_i3c_master *master,
					    u32 isr)
{
	struct cdns_i3c_xfer *xfer = master->xferqueue.cur;
	int i, ret = 0;
	u32 status0;

	if (!xfer)
		return;

	if (!(isr & MST_INT_CMDD_EMP))
		return;

	writel(MST_INT_CMDD_EMP, master->regs + MST_IDR);

	for (status0 = readl(master->regs + MST_STATUS0);
	     !(status0 & MST_STATUS0_CMDR_EMP);
	     status0 = readl(master->regs + MST_STATUS0)) {
		struct cdns_i3c_cmd *cmd;
		u32 cmdr, rx_len, id;

		cmdr = readl(master->regs + CMDR);
		id = CMDR_CMDID(cmdr);
		if (id == CMDR_CMDID_HJACK_DISEC ||
		    id == CMDR_CMDID_HJACK_ENTDAA ||
		    WARN_ON(id >= xfer->ncmds))
			continue;

		cmd = &xfer->cmds[CMDR_CMDID(cmdr)];
		rx_len = min_t(u32, CMDR_XFER_BYTES(cmdr), cmd->rx_len);
		cdns_i3c_master_rd_from_rx_fifo(master, cmd->rx_buf, rx_len);
		cmd->error = CMDR_ERROR(cmdr);
	}

	for (i = 0; i < xfer->ncmds; i++) {
		switch (xfer->cmds[i].error) {
		case CMDR_NO_ERROR:
			break;

		case CMDR_DDR_PREAMBLE_ERROR:
		case CMDR_DDR_PARITY_ERROR:
		case CMDR_M0_ERROR:
		case CMDR_M1_ERROR:
		case CMDR_M2_ERROR:
		case CMDR_MST_ABORT:
		case CMDR_NACK_RESP:
		case CMDR_DDR_DROPPED:
			ret = -EIO;
			break;

		case CMDR_DDR_RX_FIFO_OVF:
		case CMDR_DDR_TX_FIFO_UNF:
			ret = -ENOSPC;
			break;

		case CMDR_INVALID_DA:
		default:
			ret = -EINVAL;
			break;
		}
	}

	xfer->ret = ret;
	complete(&xfer->comp);

	xfer = list_first_entry_or_null(&master->xferqueue.list,
					struct cdns_i3c_xfer, node);
	if (xfer)
		list_del_init(&xfer->node);

	master->xferqueue.cur = xfer;
	cdns_i3c_master_start_xfer_locked(master);
}