[ehci] Support USB1 devices attached via transaction translators
Support low-speed and full-speed devices attached to a USB2 hub. Such devices use a transaction translator (TT) within the USB2 hub, which asynchronously initiates transactions on the lower-speed bus and returns the result via a split completion on the high-speed bus. We make the simplifying assumption that there will never be more than sixteen active interrupt endpoints behind a single transaction translator; this assumption allows us to schedule all periodic start splits in microframe 0 and all periodic split completions in microframes 2 and 3. (We do not handle isochronous endpoints.) Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
5486c947e2
commit
b418af26d9
@ -545,7 +545,7 @@ static int ehci_enqueue ( struct ehci_device *ehci, struct ehci_ring *ring,
|
|||||||
assert ( xfer->len <= EHCI_LEN_MASK );
|
assert ( xfer->len <= EHCI_LEN_MASK );
|
||||||
assert ( EHCI_FL_TOGGLE == EHCI_LEN_TOGGLE );
|
assert ( EHCI_FL_TOGGLE == EHCI_LEN_TOGGLE );
|
||||||
desc->len = cpu_to_le16 ( xfer->len | toggle );
|
desc->len = cpu_to_le16 ( xfer->len | toggle );
|
||||||
desc->flags = xfer->flags;
|
desc->flags = ( xfer->flags | EHCI_FL_CERR_MAX );
|
||||||
|
|
||||||
/* Copy data to immediate data buffer (if requested) */
|
/* Copy data to immediate data buffer (if requested) */
|
||||||
data = xfer->data;
|
data = xfer->data;
|
||||||
@ -902,19 +902,16 @@ static uint32_t ehci_endpoint_characteristics ( struct usb_endpoint *ep ) {
|
|||||||
chr |= EHCI_CHR_TOGGLE;
|
chr |= EHCI_CHR_TOGGLE;
|
||||||
|
|
||||||
/* Determine endpoint speed */
|
/* Determine endpoint speed */
|
||||||
switch ( usb->port->speed ) {
|
if ( usb->port->speed == USB_SPEED_HIGH ) {
|
||||||
case USB_SPEED_HIGH :
|
|
||||||
chr |= EHCI_CHR_EPS_HIGH;
|
chr |= EHCI_CHR_EPS_HIGH;
|
||||||
break;
|
} else {
|
||||||
case USB_SPEED_FULL :
|
if ( usb->port->speed == USB_SPEED_FULL ) {
|
||||||
chr |= EHCI_CHR_EPS_FULL;
|
chr |= EHCI_CHR_EPS_FULL;
|
||||||
break;
|
} else {
|
||||||
default:
|
chr |= EHCI_CHR_EPS_LOW;
|
||||||
assert ( usb->port->speed == USB_SPEED_LOW );
|
}
|
||||||
chr |= EHCI_CHR_EPS_LOW;
|
|
||||||
if ( attr == USB_ENDPOINT_ATTR_CONTROL )
|
if ( attr == USB_ENDPOINT_ATTR_CONTROL )
|
||||||
chr |= EHCI_CHR_CONTROL;
|
chr |= EHCI_CHR_CONTROL;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return chr;
|
return chr;
|
||||||
@ -927,6 +924,8 @@ static uint32_t ehci_endpoint_characteristics ( struct usb_endpoint *ep ) {
|
|||||||
* @ret cap Endpoint capabilities
|
* @ret cap Endpoint capabilities
|
||||||
*/
|
*/
|
||||||
static uint32_t ehci_endpoint_capabilities ( struct usb_endpoint *ep ) {
|
static uint32_t ehci_endpoint_capabilities ( struct usb_endpoint *ep ) {
|
||||||
|
struct usb_device *usb = ep->usb;
|
||||||
|
struct usb_port *tt = usb_transaction_translator ( usb );
|
||||||
unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
|
unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
|
||||||
uint32_t cap;
|
uint32_t cap;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@ -943,6 +942,15 @@ static uint32_t ehci_endpoint_capabilities ( struct usb_endpoint *ep ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set transaction translator hub address and port, if applicable */
|
||||||
|
if ( tt ) {
|
||||||
|
assert ( tt->hub->usb );
|
||||||
|
cap |= ( EHCI_CAP_TT_HUB ( tt->hub->usb->address ) |
|
||||||
|
EHCI_CAP_TT_PORT ( tt->address ) );
|
||||||
|
if ( attr == USB_ENDPOINT_ATTR_INTERRUPT )
|
||||||
|
cap |= EHCI_CAP_SPLIT_SCHED_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
return cap;
|
return cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,6 +285,12 @@ struct ehci_transfer_descriptor {
|
|||||||
/** SETUP token */
|
/** SETUP token */
|
||||||
#define EHCI_FL_PID_SETUP EHCI_FL_PID ( 2 )
|
#define EHCI_FL_PID_SETUP EHCI_FL_PID ( 2 )
|
||||||
|
|
||||||
|
/** Error counter */
|
||||||
|
#define EHCI_FL_CERR( count ) ( (count) << 2 )
|
||||||
|
|
||||||
|
/** Error counter maximum value */
|
||||||
|
#define EHCI_FL_CERR_MAX EHCI_FL_CERR ( 3 )
|
||||||
|
|
||||||
/** Interrupt on completion */
|
/** Interrupt on completion */
|
||||||
#define EHCI_FL_IOC 0x80
|
#define EHCI_FL_IOC 0x80
|
||||||
|
|
||||||
@ -341,6 +347,34 @@ struct ehci_queue_head {
|
|||||||
/** Interrupt schedule mask */
|
/** Interrupt schedule mask */
|
||||||
#define EHCI_CAP_INTR_SCHED( uframe ) ( 1 << ( (uframe) + 0 ) )
|
#define EHCI_CAP_INTR_SCHED( uframe ) ( 1 << ( (uframe) + 0 ) )
|
||||||
|
|
||||||
|
/** Split completion schedule mask */
|
||||||
|
#define EHCI_CAP_SPLIT_SCHED( uframe ) ( 1 << ( (uframe) + 8 ) )
|
||||||
|
|
||||||
|
/** Default split completion schedule mask
|
||||||
|
*
|
||||||
|
* We schedule all split starts in microframe 0, on the assumption
|
||||||
|
* that we will never have to deal with more than sixteen actively
|
||||||
|
* interrupting devices via the same transaction translator. We
|
||||||
|
* schedule split completions for all remaining microframes after
|
||||||
|
* microframe 1 (in which the low-speed or full-speed transaction is
|
||||||
|
* assumed to execute). This is a very crude approximation designed
|
||||||
|
* to avoid the need for calculating exactly when low-speed and
|
||||||
|
* full-speed transactions will execute. Since we only ever deal with
|
||||||
|
* interrupt endpoints (rather than isochronous endpoints), the volume
|
||||||
|
* of periodic traffic is extremely low, and this approximation should
|
||||||
|
* remain valid.
|
||||||
|
*/
|
||||||
|
#define EHCI_CAP_SPLIT_SCHED_DEFAULT \
|
||||||
|
( EHCI_CAP_SPLIT_SCHED ( 2 ) | EHCI_CAP_SPLIT_SCHED ( 3 ) | \
|
||||||
|
EHCI_CAP_SPLIT_SCHED ( 4 ) | EHCI_CAP_SPLIT_SCHED ( 5 ) | \
|
||||||
|
EHCI_CAP_SPLIT_SCHED ( 6 ) | EHCI_CAP_SPLIT_SCHED ( 7 ) )
|
||||||
|
|
||||||
|
/** Transaction translator hub address */
|
||||||
|
#define EHCI_CAP_TT_HUB( address ) ( (address) << 16 )
|
||||||
|
|
||||||
|
/** Transaction translator port number */
|
||||||
|
#define EHCI_CAP_TT_PORT( port ) ( (port) << 23 )
|
||||||
|
|
||||||
/** High-bandwidth pipe multiplier */
|
/** High-bandwidth pipe multiplier */
|
||||||
#define EHCI_CAP_MULT( mult ) ( (mult) << 30 )
|
#define EHCI_CAP_MULT( mult ) ( (mult) << 30 )
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user