mirror of https://github.com/ipxe/ipxe.git
[xhci] Support arbitrarily large transfers
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/41/head
parent
8f418ee477
commit
4a7d691697
|
@ -2541,6 +2541,26 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate number of TRBs
|
||||
*
|
||||
* @v len Length of data
|
||||
* @v zlp Append a zero-length packet
|
||||
* @ret count Number of transfer descriptors
|
||||
*/
|
||||
static unsigned int xhci_endpoint_count ( size_t len, int zlp ) {
|
||||
unsigned int count;
|
||||
|
||||
/* Split into 64kB TRBs */
|
||||
count = ( ( len + XHCI_MTU - 1 ) / XHCI_MTU );
|
||||
|
||||
/* Append a zero-length TRB if applicable */
|
||||
if ( zlp || ( count == 0 ) )
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue stream transfer
|
||||
*
|
||||
|
@ -2552,10 +2572,14 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep,
|
|||
static int xhci_endpoint_stream ( struct usb_endpoint *ep,
|
||||
struct io_buffer *iobuf, int zlp ) {
|
||||
struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
|
||||
union xhci_trb trbs[ 1 /* Normal */ + 1 /* Possible zero-length */ ];
|
||||
void *data = iobuf->data;
|
||||
size_t len = iob_len ( iobuf );
|
||||
unsigned int count = xhci_endpoint_count ( len, zlp );
|
||||
union xhci_trb trbs[count];
|
||||
union xhci_trb *trb = trbs;
|
||||
struct xhci_trb_normal *normal;
|
||||
size_t len = iob_len ( iobuf );
|
||||
unsigned int i;
|
||||
size_t trb_len;
|
||||
int rc;
|
||||
|
||||
/* Profile stream transfers */
|
||||
|
@ -2563,20 +2587,30 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep,
|
|||
|
||||
/* Construct normal TRBs */
|
||||
memset ( &trbs, 0, sizeof ( trbs ) );
|
||||
normal = &(trb++)->normal;
|
||||
normal->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) );
|
||||
normal->len = cpu_to_le32 ( len );
|
||||
for ( i = 0 ; i < count ; i ++ ) {
|
||||
|
||||
/* Calculate TRB length */
|
||||
trb_len = XHCI_MTU;
|
||||
if ( trb_len > len )
|
||||
trb_len = len;
|
||||
|
||||
/* Construct normal TRB */
|
||||
normal = &trb->normal;
|
||||
normal->data = cpu_to_le64 ( virt_to_phys ( data ) );
|
||||
normal->len = cpu_to_le32 ( trb_len );
|
||||
normal->type = XHCI_TRB_NORMAL;
|
||||
if ( zlp ) {
|
||||
normal->flags = XHCI_TRB_CH;
|
||||
normal = &(trb++)->normal;
|
||||
normal->type = XHCI_TRB_NORMAL;
|
||||
|
||||
/* Move to next TRB */
|
||||
data += trb_len;
|
||||
len -= trb_len;
|
||||
trb++;
|
||||
}
|
||||
normal->flags = XHCI_TRB_IOC;
|
||||
trb[-1].normal.flags = XHCI_TRB_IOC;
|
||||
|
||||
/* Enqueue TRBs */
|
||||
if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs,
|
||||
( trb - trbs ) ) ) != 0 )
|
||||
count ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Ring the doorbell */
|
||||
|
|
Loading…
Reference in New Issue