in master/i3c-master-cdns.c [1305:1357]
static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
u32 ibir)
{
struct cdns_i3c_i2c_dev_data *data;
bool data_consumed = false;
struct i3c_ibi_slot *slot;
u32 id = IBIR_SLVID(ibir);
struct i3c_dev_desc *dev;
size_t nbytes;
u8 *buf;
/*
* FIXME: maybe we should report the FIFO OVF errors to the upper
* layer.
*/
if (id >= master->ibi.num_slots || (ibir & IBIR_ERROR))
goto out;
dev = master->ibi.slots[id];
spin_lock(&master->ibi.lock);
data = i3c_dev_get_master_data(dev);
slot = i3c_generic_ibi_get_free_slot(data->ibi_pool);
if (!slot)
goto out_unlock;
buf = slot->data;
nbytes = IBIR_XFER_BYTES(ibir);
readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4);
if (nbytes % 3) {
u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO);
memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
}
slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir),
dev->ibi->max_payload_len);
i3c_master_queue_ibi(dev, slot);
data_consumed = true;
out_unlock:
spin_unlock(&master->ibi.lock);
out:
/* Consume data from the FIFO if it's not been done already. */
if (!data_consumed) {
int i;
for (i = 0; i < IBIR_XFER_BYTES(ibir); i += 4)
readl(master->regs + IBI_DATA_FIFO);
}
}