in master/mipi-i3c-hci/pio.c [873:939]
static bool hci_pio_process_ibi(struct i3c_hci *hci, struct hci_pio_data *pio)
{
struct hci_pio_ibi_data *ibi = &pio->ibi;
if (!ibi->slot && !ibi->seg_cnt && ibi->last_seg)
if (!hci_pio_prep_new_ibi(hci, pio))
return false;
for (;;) {
u32 ibi_status;
unsigned int ibi_addr;
if (ibi->slot) {
if (!hci_pio_get_ibi_segment(hci, pio))
return false;
ibi->slot->len += ibi->seg_len;
ibi->data_ptr += ibi->seg_len;
if (ibi->last_seg) {
/* was the last segment: submit it and leave */
i3c_master_queue_ibi(ibi->slot->dev, ibi->slot);
ibi->slot = NULL;
hci_pio_set_ibi_thresh(hci, pio, 1);
return true;
}
} else if (ibi->seg_cnt) {
/*
* No slot but a non-zero count. This is the result
* of some error and the payload must be drained.
* This normally does not happen therefore no need
* to be extra optimized here.
*/
hci_pio_set_ibi_thresh(hci, pio, 1);
do {
if (!(pio_reg_read(INTR_STATUS) & STAT_IBI_STATUS_THLD))
return false;
pio_reg_read(IBI_PORT);
} while (--ibi->seg_cnt);
if (ibi->last_seg)
return true;
}
/* try to move to the next segment right away */
hci_pio_set_ibi_thresh(hci, pio, 1);
if (!(pio_reg_read(INTR_STATUS) & STAT_IBI_STATUS_THLD))
return false;
ibi_status = pio_reg_read(IBI_PORT);
ibi_addr = FIELD_GET(IBI_TARGET_ADDR, ibi_status);
if (ibi->addr != ibi_addr) {
/* target address changed before last segment */
dev_err(&hci->master.dev,
"unexp IBI address changed from %d to %d\n",
ibi->addr, ibi_addr);
hci_pio_free_ibi_slot(hci, pio);
}
ibi->last_seg = ibi_status & IBI_LAST_STATUS;
ibi->seg_len = FIELD_GET(IBI_DATA_LENGTH, ibi_status);
ibi->seg_cnt = ibi->seg_len;
if (ibi->slot && ibi->slot->len + ibi->seg_len > ibi->max_len) {
dev_err(&hci->master.dev,
"IBI payload too big (%d > %d)\n",
ibi->slot->len + ibi->seg_len, ibi->max_len);
hci_pio_free_ibi_slot(hci, pio);
}
}
return false;
}