in master/mipi-i3c-hci/pio.c [394:471]
static void hci_pio_push_to_next_rx(struct i3c_hci *hci, struct hci_xfer *xfer,
unsigned int words_to_keep)
{
u32 *from = xfer->data;
u32 from_last;
unsigned int received, count;
received = (xfer->data_len - xfer->data_left) / 4;
if ((xfer->data_len - xfer->data_left) & 3) {
from_last = xfer->data_word_before_partial;
received += 1;
} else {
from_last = from[received];
}
from += words_to_keep;
count = received - words_to_keep;
while (count) {
unsigned int room, left, chunk, bytes_to_move;
u32 last_word;
xfer = xfer->next_data;
if (!xfer) {
dev_err(&hci->master.dev, "pushing RX data to unexistent xfer\n");
return;
}
room = DIV_ROUND_UP(xfer->data_len, 4);
left = DIV_ROUND_UP(xfer->data_left, 4);
chunk = min(count, room);
if (chunk > left) {
hci_pio_push_to_next_rx(hci, xfer, chunk - left);
left = chunk;
xfer->data_left = left * 4;
}
bytes_to_move = xfer->data_len - xfer->data_left;
if (bytes_to_move & 3) {
/* preserve word to become partial */
u32 *p = xfer->data;
xfer->data_word_before_partial = p[bytes_to_move / 4];
}
memmove(xfer->data + chunk, xfer->data, bytes_to_move);
/* treat last word specially because of partial word issues */
chunk -= 1;
memcpy(xfer->data, from, chunk * 4);
xfer->data_left -= chunk * 4;
from += chunk;
count -= chunk;
last_word = (count == 1) ? from_last : *from++;
if (xfer->data_left < 4) {
/*
* Like in hci_pio_do_trailing_rx(), preserve original
* word to be stored partially then store bytes it
* in an endian independent way.
*/
u8 *p_byte = xfer->data;
p_byte += chunk * 4;
xfer->data_word_before_partial = last_word;
last_word = (__force u32) cpu_to_le32(last_word);
while (xfer->data_left--) {
*p_byte++ = last_word;
last_word >>= 8;
}
} else {
u32 *p = xfer->data;
p[chunk] = last_word;
xfer->data_left -= 4;
}
count--;
}
}