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);
}