From 9e88194655c7d074fb7eeab834db97353c47282d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Mar 2015 15:59:51 +0000 Subject: [PATCH] [usb] Add clear_tt() hub method to clear transaction translator buffer Signed-off-by: Michael Brown --- src/drivers/usb/ehci.c | 24 ++++++++++++++++++++++-- src/drivers/usb/usbhub.c | 30 ++++++++++++++++++++++++++++++ src/drivers/usb/usbhub.h | 33 +++++++++++++++++++++++++++++++++ src/drivers/usb/xhci.c | 20 ++++++++++++++++++++ src/include/ipxe/usb.h | 9 +++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c index 4436c982..83635f45 100644 --- a/src/drivers/usb/ehci.c +++ b/src/drivers/usb/ehci.c @@ -1022,7 +1022,7 @@ static void ehci_endpoint_close ( struct usb_endpoint *ep ) { /* No way to prevent hardware from continuing to * access the memory, so leak it. */ - DBGC ( ehci, "EHCI %p %s endpoint %d could not unschedule: " + DBGC ( ehci, "EHCI %p %s endpoint %02x could not unschedule: " "%s\n", ehci, usb->name, ep->address, strerror ( rc ) ); return; } @@ -1217,7 +1217,7 @@ static void ehci_endpoint_poll ( struct ehci_endpoint *endpoint ) { */ if ( status & EHCI_STATUS_HALTED ) { rc = -EIO_STATUS ( status ); - DBGC ( ehci, "EHCI %p %s endpoint %d completion %d " + DBGC ( ehci, "EHCI %p %s endpoint %02x completion %d " "failed (status %02x): %s\n", ehci, usb->name, ep->address, index, status, strerror ( rc ) ); while ( ! iobuf ) @@ -1496,6 +1496,25 @@ static int ehci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) { return 0; } +/** + * Clear transaction translator buffer + * + * @v hub USB hub + * @v port USB port + * @v ep USB endpoint + * @ret rc Return status code + */ +static int ehci_hub_clear_tt ( struct usb_hub *hub, struct usb_port *port, + struct usb_endpoint *ep ) { + struct ehci_device *ehci = usb_hub_get_drvdata ( hub ); + + /* Should never be called; this is a root hub */ + DBGC ( ehci, "EHCI %p port %d nonsensical CLEAR_TT for %s endpoint " + "%02x\n", ehci, port->address, ep->usb->name, ep->address ); + + return -ENOTSUP; +} + /** * Poll for port status changes * @@ -1706,6 +1725,7 @@ static struct usb_host_operations ehci_operations = { .enable = ehci_hub_enable, .disable = ehci_hub_disable, .speed = ehci_hub_speed, + .clear_tt = ehci_hub_clear_tt, }, }; diff --git a/src/drivers/usb/usbhub.c b/src/drivers/usb/usbhub.c index a2841089..6d0cdba4 100644 --- a/src/drivers/usb/usbhub.c +++ b/src/drivers/usb/usbhub.c @@ -338,6 +338,35 @@ static int hub_speed ( struct usb_hub *hub, struct usb_port *port ) { return 0; } +/** + * Clear transaction translator buffer + * + * @v hub USB hub + * @v port USB port + * @v ep USB endpoint + * @ret rc Return status code + */ +static int hub_clear_tt ( struct usb_hub *hub, struct usb_port *port, + struct usb_endpoint *ep ) { + struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub ); + struct usb_device *usb = hubdev->usb; + int rc; + + /* Clear transaction translator buffer. All hubs must support + * single-TT operation; we simplify our code by supporting + * only this configuration. + */ + if ( ( rc = usb_hub_clear_tt_buffer ( usb, ep->usb->address, + ep->address, ep->attributes, + USB_HUB_TT_SINGLE ) ) != 0 ) { + DBGC ( hubdev, "HUB %s port %d could not clear TT buffer: %s\n", + hubdev->name, port->address, strerror ( rc ) ); + return rc; + } + + return 0; +} + /** USB hub operations */ static struct usb_hub_driver_operations hub_operations = { .open = hub_open, @@ -345,6 +374,7 @@ static struct usb_hub_driver_operations hub_operations = { .enable = hub_enable, .disable = hub_disable, .speed = hub_speed, + .clear_tt = hub_clear_tt, }; /** diff --git a/src/drivers/usb/usbhub.h b/src/drivers/usb/usbhub.h index 0713e5bc..d7d8f961 100644 --- a/src/drivers/usb/usbhub.h +++ b/src/drivers/usb/usbhub.h @@ -129,6 +129,11 @@ struct usb_hub_port_status { ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE | \ USB_REQUEST_TYPE ( 12 ) ) +/** Clear transaction translator buffer */ +#define USB_HUB_CLEAR_TT_BUFFER \ + ( USB_DIR_OUT | USB_TYPE_CLASS | USB_HUB_RECIP_PORT | \ + USB_REQUEST_TYPE ( 8 ) ) + /** * Get hub descriptor * @@ -214,6 +219,34 @@ usb_hub_set_hub_depth ( struct usb_device *usb, unsigned int depth ) { return usb_control ( usb, USB_HUB_SET_HUB_DEPTH, depth, 0, NULL, 0 ); } +/** + * Clear transaction translator buffer + * + * @v usb USB device + * @v device Device address + * @v endpoint Endpoint address + * @v attributes Endpoint attributes + * @v tt_port Transaction translator port (or 1 for single-TT hubs) + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +usb_hub_clear_tt_buffer ( struct usb_device *usb, unsigned int device, + unsigned int endpoint, unsigned int attributes, + unsigned int tt_port ) { + unsigned int value; + + /* Calculate value */ + value = ( ( ( endpoint & USB_ENDPOINT_MAX ) << 0 ) | ( device << 4 ) | + ( ( attributes & USB_ENDPOINT_ATTR_TYPE_MASK ) << 11 ) | + ( ( endpoint & USB_ENDPOINT_IN ) << 8 ) ); + + return usb_control ( usb, USB_HUB_CLEAR_TT_BUFFER, value, + tt_port, NULL, 0 ); +} + +/** Transaction translator port value for single-TT hubs */ +#define USB_HUB_TT_SINGLE 1 + /** A USB hub device */ struct usb_hub_device { /** Name */ diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index a940a73a..69d621d9 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -2992,6 +2992,25 @@ static int xhci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) { return 0; } +/** + * Clear transaction translator buffer + * + * @v hub USB hub + * @v port USB port + * @v ep USB endpoint + * @ret rc Return status code + */ +static int xhci_hub_clear_tt ( struct usb_hub *hub, struct usb_port *port, + struct usb_endpoint *ep ) { + struct ehci_device *ehci = usb_hub_get_drvdata ( hub ); + + /* Should never be called; this is a root hub */ + DBGC ( ehci, "XHCI %p port %d nonsensical CLEAR_TT for %s endpoint " + "%02x\n", ehci, port->address, ep->usb->name, ep->address ); + + return -ENOTSUP; +} + /****************************************************************************** * * PCI interface @@ -3025,6 +3044,7 @@ static struct usb_host_operations xhci_operations = { .enable = xhci_hub_enable, .disable = xhci_hub_disable, .speed = xhci_hub_speed, + .clear_tt = xhci_hub_clear_tt, }, }; diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index 5b95c20c..ee4004e9 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -820,6 +820,15 @@ struct usb_hub_driver_operations { * @ret rc Return status code */ int ( * speed ) ( struct usb_hub *hub, struct usb_port *port ); + /** Clear transaction translator buffer + * + * @v hub USB hub + * @v port USB port + * @v ep USB endpoint + * @ret rc Return status code + */ + int ( * clear_tt ) ( struct usb_hub *hub, struct usb_port *port, + struct usb_endpoint *ep ); }; /**