in master/mipi-i3c-hci/pio.c [621:681]
static bool hci_pio_dequeue_xfer_common(struct i3c_hci *hci,
struct hci_pio_data *pio,
struct hci_xfer *xfer, int n)
{
struct hci_xfer *p, **p_prev_next;
int i;
/*
* To safely dequeue a transfer request, it must be either entirely
* processed, or not yet processed at all. If our request tail is
* reachable from either the data or resp list that means the command
* was submitted and not yet completed.
*/
for (p = pio->curr_resp; p; p = p->next_resp)
for (i = 0; i < n; i++)
if (p == &xfer[i])
goto pio_screwed;
for (p = pio->curr_rx; p; p = p->next_data)
for (i = 0; i < n; i++)
if (p == &xfer[i])
goto pio_screwed;
for (p = pio->curr_tx; p; p = p->next_data)
for (i = 0; i < n; i++)
if (p == &xfer[i])
goto pio_screwed;
/*
* The command was completed, or wasn't yet submitted.
* Unlink it from the que if the later.
*/
p_prev_next = &pio->curr_xfer;
for (p = pio->curr_xfer; p; p = p->next_xfer) {
if (p == &xfer[0]) {
*p_prev_next = xfer[n - 1].next_xfer;
break;
}
p_prev_next = &p->next_xfer;
}
/* return true if we actually unqueued something */
return !!p;
pio_screwed:
/*
* Life is tough. We must invalidate the hardware state and
* discard everything that is still queued.
*/
for (p = pio->curr_resp; p; p = p->next_resp) {
p->response = FIELD_PREP(RESP_ERR_FIELD, RESP_ERR_HC_TERMINATED);
if (p->completion)
complete(p->completion);
}
for (p = pio->curr_xfer; p; p = p->next_xfer) {
p->response = FIELD_PREP(RESP_ERR_FIELD, RESP_ERR_HC_TERMINATED);
if (p->completion)
complete(p->completion);
}
pio->curr_xfer = pio->curr_rx = pio->curr_tx = pio->curr_resp = NULL;
return true;
}