spin_lock_irq(&hci->lock);
+ while (unlikely(hci->enqueue_blocked)) {
+ spin_unlock_irq(&hci->lock);
+ wait_event(hci->enqueue_wait_queue, !READ_ONCE(hci->enqueue_blocked));
+ spin_lock_irq(&hci->lock);
+ }
+
if (n > rh->xfer_space) {
spin_unlock_irq(&hci->lock);
hci_dma_unmap_xfer(hci, xfer_list, n);
return 0;
}
+static void hci_dma_unblock_enqueue(struct i3c_hci *hci)
+{
+ if (hci->enqueue_blocked) {
+ hci->enqueue_blocked = false;
+ wake_up_all(&hci->enqueue_wait_queue);
+ }
+}
+
static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
struct hci_xfer *xfer_list, int n)
{
guard(mutex)(&hci->control_mutex);
+ spin_lock_irq(&hci->lock);
+
ring_status = rh_reg_read(RING_STATUS);
if (ring_status & RING_STATUS_RUNNING) {
+ hci->enqueue_blocked = true;
+ spin_unlock_irq(&hci->lock);
/* stop the ring */
reinit_completion(&rh->op_done);
rh_reg_write(RING_CONTROL, rh_reg_read(RING_CONTROL) | RING_CTRL_ABORT);
wait_for_completion_timeout(&rh->op_done, HZ);
+ spin_lock_irq(&hci->lock);
ring_status = rh_reg_read(RING_STATUS);
if (ring_status & RING_STATUS_RUNNING) {
/*
}
}
- spin_lock_irq(&hci->lock);
-
for (i = 0; i < n; i++) {
struct hci_xfer *xfer = xfer_list + i;
int idx = xfer->ring_entry;
rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE);
rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_RUN_STOP);
+ hci_dma_unblock_enqueue(hci);
+
spin_unlock_irq(&hci->lock);
return did_unqueue;
}
if (xfer->completion)
complete(xfer->completion);
+ if (RESP_STATUS(resp))
+ hci->enqueue_blocked = true;
}
done_ptr = (done_ptr + 1) % rh->xfer_entries;