static void cdns_i3c_master_handle_ibi()

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