git: e8018942942e - main - apple_bce: initiate IN data phase for control transfers
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 06 Sep 2026 19:48:34 UTC
The branch main has been updated by seuros:
URL: https://cgit.FreeBSD.org/src/commit/?id=e8018942942e212ba5a664f0265f1101e6c48930
commit e8018942942e212ba5a664f0265f1101e6c48930
Author: Abdelkader Boudih <seuros@FreeBSD.org>
AuthorDate: 2026-09-06 19:47:34 +0000
Commit: Abdelkader Boudih <seuros@FreeBSD.org>
CommitDate: 2026-09-06 19:47:44 +0000
apple_bce: initiate IN data phase for control transfers
For IN control transfers, the firmware does
not send TRANSFER_REQUEST for the data phase
the host must send BCE_VHCI_CMD_TRANSFER_REQUEST
with an IN DMA buffer once the setup phase completes.
Reviewed by: adrian
Differential Revision: https://reviews.freebsd.org/D58872
---
sys/dev/apple_bce/apple_bce_vhci.c | 70 ++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/sys/dev/apple_bce/apple_bce_vhci.c b/sys/dev/apple_bce/apple_bce_vhci.c
index 56d519e715c1..e8bef8566cd6 100644
--- a/sys/dev/apple_bce/apple_bce_vhci.c
+++ b/sys/dev/apple_bce/apple_bce_vhci.c
@@ -176,6 +176,8 @@ static void bce_vhci_handle_transfer_request(struct bce_vhci_softc *vhci,
struct bce_vhci_message *msg);
static void bce_vhci_complete_ctrl_locked(struct bce_vhci_softc *vhci,
struct bce_vhci_transfer_queue *tq, struct bce_vhci_message *msg);
+static void bce_vhci_ctrl_start_in_data(struct bce_vhci_softc *vhci,
+ struct bce_vhci_transfer_queue *tq);
static void bce_vhci_handle_ctrl_status(struct bce_vhci_softc *vhci,
struct bce_vhci_message *msg);
static uint16_t bce_vhci_handle_endpoint_req_state(struct bce_vhci_softc *vhci,
@@ -1643,6 +1645,71 @@ bce_vhci_submit_pending_out(struct bce_vhci_softc *vhci,
}
}
+static void
+bce_vhci_ctrl_start_in_data(struct bce_vhci_softc *vhci,
+ struct bce_vhci_transfer_queue *tq)
+{
+ struct bce_vhci_message treq;
+ struct bce_qe_submission *si;
+ struct usb_xfer *xfer;
+ uint32_t dlen;
+
+ dlen = tq->ctrl_data_len;
+ if (dlen > BCE_VHCI_XFER_BUFSZ)
+ dlen = BCE_VHCI_XFER_BUFSZ;
+
+ xfer = tq->active_xfer;
+ tq->ctrl_state = BCE_VHCI_CTRL_STATUS;
+ USB_BUS_UNLOCK(&vhci->sc_bus);
+
+ memset(&treq, 0, sizeof(treq));
+ treq.cmd = BCE_VHCI_CMD_TRANSFER_REQUEST;
+ treq.param1 = ((uint32_t)tq->endp_addr << 8) | tq->dev_addr;
+ treq.param2 = dlen;
+
+ bus_dmamap_sync(tq->dma_tag, tq->dma_map, BUS_DMASYNC_PREREAD);
+
+ mtx_lock_spin(&vhci->sc_async_lock);
+ if (bce_reserve_submission(vhci->msg_asynchronous.sq) != 0) {
+ mtx_unlock_spin(&vhci->sc_async_lock);
+ goto fail;
+ }
+ mtx_unlock_spin(&vhci->sc_async_lock);
+
+ mtx_lock_spin(&tq->lock);
+ if (bce_reserve_submission(tq->sq_in) != 0) {
+ mtx_unlock_spin(&tq->lock);
+ mtx_lock_spin(&vhci->sc_async_lock);
+ atomic_add_int(
+ &vhci->msg_asynchronous.sq->available_commands, 1);
+ mtx_unlock_spin(&vhci->sc_async_lock);
+ goto fail;
+ }
+ si = bce_next_submission(tq->sq_in);
+ si->addr = tq->dma_addr;
+ si->length = dlen;
+ si->segl_addr = 0;
+ si->segl_length = 0;
+ bce_submit_to_device(vhci->sc_bce, tq->sq_in);
+ mtx_unlock_spin(&tq->lock);
+
+ mtx_lock_spin(&vhci->sc_async_lock);
+ bce_vhci_msg_queue_write(vhci, &vhci->msg_asynchronous, &treq);
+ mtx_unlock_spin(&vhci->sc_async_lock);
+
+ USB_BUS_LOCK(&vhci->sc_bus);
+ return;
+
+fail:
+ USB_BUS_LOCK(&vhci->sc_bus);
+ if (tq->active_xfer == xfer) {
+ tq->active_xfer = NULL;
+ tq->dma_inflight = 0;
+ tq->ctrl_state = BCE_VHCI_CTRL_IDLE;
+ usbd_transfer_done(xfer, USB_ERR_IOERROR);
+ }
+}
+
/*
* Transfer queue DMA completion callback. Fires when the firmware
* has consumed (OUT) or filled (IN) a DMA buffer we submitted.
@@ -1791,6 +1858,9 @@ bce_vhci_tq_completion(struct bce_queue_sq *sq)
vhci, tq,
&tq->ctrl_status_msg);
}
+ if (tq->ctrl_state == BCE_VHCI_CTRL_DATA &&
+ tq->ctrl_dir == UE_DIR_IN)
+ bce_vhci_ctrl_start_in_data(vhci, tq);
} else if (tq->ctrl_state ==
BCE_VHCI_CTRL_STATUS &&
tq->ctrl_dir == UE_DIR_OUT) {