diff options
-rw-r--r-- | src/drivers/bus/usb.c | 6 | ||||
-rw-r--r-- | src/drivers/net/ncm.c | 4 | ||||
-rw-r--r-- | src/drivers/usb/usbhub.c | 2 | ||||
-rw-r--r-- | src/drivers/usb/xhci.c | 22 | ||||
-rw-r--r-- | src/include/ipxe/usb.h | 8 |
5 files changed, 28 insertions, 14 deletions
diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 5a338a5e..8900324a 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -451,9 +451,11 @@ int usb_message ( struct usb_endpoint *ep, unsigned int request, * * @v ep USB endpoint * @v iobuf I/O buffer + * @v terminate Terminate using a short packet * @ret rc Return status code */ -int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf ) { +int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf, + int terminate ) { struct usb_device *usb = ep->usb; struct usb_port *port = usb->port; int rc; @@ -467,7 +469,7 @@ int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf ) { return rc; /* Enqueue stream transfer */ - if ( ( rc = ep->host->stream ( ep, iobuf ) ) != 0 ) { + if ( ( rc = ep->host->stream ( ep, iobuf, terminate ) ) != 0 ) { DBGC ( usb, "USB %s %s could not enqueue stream transfer: %s\n", usb->name, usb_endpoint_name ( ep->address ), strerror ( rc ) ); diff --git a/src/drivers/net/ncm.c b/src/drivers/net/ncm.c index 0fc3ab79..e05559bb 100644 --- a/src/drivers/net/ncm.c +++ b/src/drivers/net/ncm.c @@ -145,7 +145,7 @@ static int ncm_rx_refill ( struct ncm_device *ncm, struct ncm_rx_ring *ring ) { iob_put ( iobuf, ( ring->mtu - iob_len ( iobuf ) ) ); /* Enqueue I/O buffer */ - if ( ( rc = usb_stream ( &ring->ep, iobuf ) ) != 0 ) { + if ( ( rc = usb_stream ( &ring->ep, iobuf, 0 ) ) != 0 ) { DBGC ( ncm, "NCM %p could not enqueue %s: %s\n", ncm, ncm_rx_name ( ncm, ring ), strerror ( rc ) ); /* Leave in recycled list and wait for next refill */ @@ -548,7 +548,7 @@ static int ncm_out_transmit ( struct ncm_device *ncm, memset ( &header->desc[1], 0, sizeof ( header->desc[1] ) ); /* Enqueue I/O buffer */ - if ( ( rc = usb_stream ( &ncm->out.ep, iobuf ) ) != 0 ) + if ( ( rc = usb_stream ( &ncm->out.ep, iobuf, 0 ) ) != 0 ) return rc; /* Increment sequence number */ diff --git a/src/drivers/usb/usbhub.c b/src/drivers/usb/usbhub.c index ecac460a..9c88531b 100644 --- a/src/drivers/usb/usbhub.c +++ b/src/drivers/usb/usbhub.c @@ -52,7 +52,7 @@ static void hub_refill ( struct usb_hub_device *hubdev ) { iob_put ( iobuf, ( mtu - iob_len ( iobuf ) ) ); /* Enqueue I/O buffer */ - if ( ( rc = usb_stream ( &hubdev->intr, iobuf ) ) != 0 ) { + if ( ( rc = usb_stream ( &hubdev->intr, iobuf, 0 ) ) != 0 ) { DBGC ( hubdev, "HUB %s could not enqueue interrupt: " "%s\n", hubdev->name, strerror ( rc ) ); /* Leave in available list and wait for next refill */ diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 49901275..bf8cf1c8 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -2457,27 +2457,37 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep, * * @v ep USB endpoint * @v iobuf I/O buffer + * @v terminate Terminate using a short packet * @ret rc Return status code */ static int xhci_endpoint_stream ( struct usb_endpoint *ep, - struct io_buffer *iobuf ) { + struct io_buffer *iobuf, int terminate ) { struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep ); - union xhci_trb trb; + union xhci_trb trbs[ 1 /* Normal */ + 1 /* Possible zero-length */ ]; + union xhci_trb *trb = trbs; struct xhci_trb_normal *normal; + size_t len = iob_len ( iobuf ); int rc; /* Profile stream transfers */ profile_start ( &xhci_stream_profiler ); /* Construct normal TRBs */ - normal = &trb.normal; + memset ( &trbs, 0, sizeof ( trbs ) ); + normal = &(trb++)->normal; normal->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) ); - normal->len = cpu_to_le32 ( iob_len ( iobuf ) ); - normal->flags = XHCI_TRB_IOC; + normal->len = cpu_to_le32 ( len ); normal->type = XHCI_TRB_NORMAL; + if ( terminate && ( ( len & ( ep->mtu - 1 ) ) == 0 ) ) { + normal->flags = XHCI_TRB_CH; + normal = &(trb++)->normal; + normal->type = XHCI_TRB_NORMAL; + } + normal->flags = XHCI_TRB_IOC; /* Enqueue TRBs */ - if ( ( rc = xhci_enqueue ( &endpoint->ring, iobuf, &trb ) ) != 0 ) + if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs, + ( trb - trbs ) ) ) != 0 ) return rc; /* Ring the doorbell */ diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index e21ca1c4..1f5a85ec 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -428,10 +428,11 @@ struct usb_endpoint_host_operations { * * @v ep USB endpoint * @v iobuf I/O buffer + * @v terminate Terminate using a short packet * @ret rc Return status code */ - int ( * stream ) ( struct usb_endpoint *ep, - struct io_buffer *iobuf ); + int ( * stream ) ( struct usb_endpoint *ep, struct io_buffer *iobuf, + int terminate ); }; /** USB endpoint driver operations */ @@ -547,7 +548,8 @@ extern void usb_endpoint_close ( struct usb_endpoint *ep ); extern int usb_message ( struct usb_endpoint *ep, unsigned int request, unsigned int value, unsigned int index, struct io_buffer *iobuf ); -extern int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf ); +extern int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf, + int terminate ); extern void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ); |