diff options
author | Cheng, Huiming <Huiming.Cheng@dellteam.com> | 2022-12-15 22:30:11 +0000 |
---|---|---|
committer | Hans Petter Selasky <hselasky@FreeBSD.org> | 2023-01-13 10:18:19 +0000 |
commit | 8685d7b5cb759b4f688dea93dbe1c38f9e833e4e (patch) | |
tree | 0c9fda2b8fce94248bb7de0e67679f22184cee21 /sys/dev/usb | |
parent | e4611d26265fb9e3bd2a345cf4776863f49a2587 (diff) | |
download | src-8685d7b5cb759b4f688dea93dbe1c38f9e833e4e.tar.gz src-8685d7b5cb759b4f688dea93dbe1c38f9e833e4e.zip |
xhci(4): Make sure allocated bandwidth is freed in hardware by unconfiguring endpoint.
MFC after: 1 week
Sponsored by: NVIDIA Networking
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/controller/xhci.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index ba8360e54152..161f443631b2 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -4030,7 +4030,47 @@ xhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, static void xhci_ep_uninit(struct usb_device *udev, struct usb_endpoint *ep) { + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + const struct usb_endpoint_descriptor *edesc = ep->edesc; + struct usb_page_search buf_inp; + struct usb_page_cache *pcinp; + uint32_t mask; + uint8_t index; + uint8_t epno; + usb_error_t err; + + if (udev->parent_hub == NULL) { + /* root HUB has special endpoint handling */ + return; + } + + if ((edesc->bEndpointAddress & UE_ADDR) == 0) { + /* control endpoint is never unconfigured */ + return; + } + XHCI_CMD_LOCK(sc); + index = udev->controller_slot_id; + epno = XHCI_EPNO2EPID(edesc->bEndpointAddress); + mask = 1U << epno; + + if (sc->sc_hw.devs[index].ep_configured & mask) { + USB_BUS_LOCK(udev->bus); + xhci_configure_mask(udev, mask, 1); + USB_BUS_UNLOCK(udev->bus); + + pcinp = &sc->sc_hw.devs[index].input_pc; + usbd_get_page(pcinp, 0, &buf_inp); + err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index); + if (err) { + DPRINTF("Unconfiguring endpoint failed: %d\n", err); + } else { + USB_BUS_LOCK(udev->bus); + sc->sc_hw.devs[index].ep_configured &= ~mask; + USB_BUS_UNLOCK(udev->bus); + } + } + XHCI_CMD_UNLOCK(sc); } static void |