Patch "usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers" has been added to the 4.2-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers
to the 4.2-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
usb-xhci-add-support-for-urb_zero_packet-to-bulk-sg-transfers.patch
and it can be found in the queue-4.2 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
4758dcd19a7d9ba9610b38fecb93f65f56f86346Mon Sep 17 00:00:00 2001
From: Reyad Attiyat <[email protected]>
Date: Thu, 6 Aug 2015 19:23:58 +0300
Subject: usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers
From: Reyad Attiyat <[email protected]>
commit 4758dcd19a7d9ba9610b38fecb93f65f56f86346 upstream.
This commit checks for the URB_ZERO_PACKET flag and creates an extra zero-length td if the urb transfer length is a multiple of the endpoint's max packet length.
--- drivers/usb/host/xhci-ring.c | 66 +++++++++++++++++++++++++++++++++---------- drivers/usb/host/xhci.c | 5 +++ 2 files changed, 57 insertions(+), 14 deletions(-)
drivers/usb/host/xhci-ring.c +52 -14
@@ -3050,9 +3050,11 @@ static int queue_bulk_sg_tx(struct xhci_struct xhci_td *td;struct scatterlist *sg;int num_sgs; -int trb_buff_len, this_sg_len, running_total; +int trb_buff_len, this_sg_len, running_total, ret;unsigned int total_packet_count; +bool zero_length_needed;bool first_trb; +int last_trb_num;u64 addr;bool more_trbs_coming;
@@ -3068,13 +3070,27 @@ static int queue_bulk_sg_tx(struct xhci_ total_packet_count =DIV_ROUND_UP (urb->transfer_buffer_length,usb_endpoint_maxp (&urb->ep->desc)); - trb_buff_len =prepare_transfer (xhci, xhci->devs[slot_id], + ret =prepare_transfer (xhci, xhci->devs[slot_id], ep_index, urb->stream_id, num_trbs, urb,0 , mem_flags); -if (trb_buff_len <0 ) -return trb_buff_len; +if (ret <0 ) +return ret; urb_priv = urb->hcpriv; + +/* Deal with URB_ZERO_PACKET - need one more td/trb */ + zero_length_needed = urb->transfer_flags &URB_ZERO_PACKET && + urb_priv->length ==2 ; +if (zero_length_needed) { + num_trbs++; +xhci_dbg (xhci,"Creating zero length td.\n" ); + ret =prepare_transfer (xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, +1 , urb,1 , mem_flags); +if (ret <0 ) +return ret; + } + td = urb_priv->td[0 ];/*
@@ -3104,6 +3120,7 @@ static int queue_bulk_sg_tx(struct xhci_ trb_buff_len = urb->transfer_buffer_length; first_trb = true; + last_trb_num = zero_length_needed ?2 :1 ;/* Queue the first TRB, even if it's zero-length */ do { u32 field = 0;
@@ -3121,12 +3138,15 @@ static int queue_bulk_sg_tx(struct xhci_/* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ -if (num_trbs >1 ) { +if (num_trbs > last_trb_num) { field |=TRB_CHAIN ; - }else { -/* FIXME - add check for ZERO_PACKET flag before this */ + }else if (num_trbs == last_trb_num) { td->last_trb = ep_ring->enqueue; field |=TRB_IOC ; + }else if (zero_length_needed && num_trbs ==1 ) { + trb_buff_len =0 ; + urb_priv->td[1 ]->last_trb = ep_ring->enqueue; + field |=TRB_IOC ; }/* Only set interrupt on short packet for IN endpoints */
@@ -3188,7 +3208,7 @@ static int queue_bulk_sg_tx(struct xhci_if (running_total + trb_buff_len > urb->transfer_buffer_length) trb_buff_len = urb->transfer_buffer_length - running_total; - }while (running_total < urb->transfer_buffer_length); + }while (num_trbs >0 );check_trb_math (urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
@@ -3206,7 +3226,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *int num_trbs;struct xhci_generic_trb *start_trb;bool first_trb; +int last_trb_num;bool more_trbs_coming; +bool zero_length_needed;int start_cycle;u32 field, length_field;
@@ -3237,7 +3259,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd * num_trbs++; running_total +=TRB_MAX_BUFF_SIZE ; } -/* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */ ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id,
@@ -3246,6 +3267,20 @@ int xhci_queue_bulk_tx(struct xhci_hcd *return ret; urb_priv = urb->hcpriv; + +/* Deal with URB_ZERO_PACKET - need one more td/trb */ + zero_length_needed = urb->transfer_flags &URB_ZERO_PACKET && + urb_priv->length ==2 ; +if (zero_length_needed) { + num_trbs++; +xhci_dbg (xhci,"Creating zero length td.\n" ); + ret =prepare_transfer (xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, +1 , urb,1 , mem_flags); +if (ret <0 ) +return ret; + } + td = urb_priv->td[0 ];/*
@@ -3267,7 +3302,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd * trb_buff_len = urb->transfer_buffer_length; first_trb = true; - + last_trb_num = zero_length_needed ?2 :1 ;/* Queue the first TRB, even if it's zero-length */ do { u32 remainder = 0;
@@ -3284,12 +3319,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd */* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ -if (num_trbs >1 ) { +if (num_trbs > last_trb_num) { field |=TRB_CHAIN ; - }else { -/* FIXME - add check for ZERO_PACKET flag before this */ + }else if (num_trbs == last_trb_num) { td->last_trb = ep_ring->enqueue; field |=TRB_IOC ; + }else if (zero_length_needed && num_trbs ==1 ) { + trb_buff_len =0 ; + urb_priv->td[1 ]->last_trb = ep_ring->enqueue; + field |=TRB_IOC ; }/* Only set interrupt on short packet for IN endpoints */
@@ -3327,7 +3365,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd * trb_buff_len = urb->transfer_buffer_length - running_total;if (trb_buff_len >TRB_MAX_BUFF_SIZE ) trb_buff_len =TRB_MAX_BUFF_SIZE ; - }while (running_total < urb->transfer_buffer_length); + }while (num_trbs >0 );check_trb_math (urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
drivers/usb/host/xhci.c +5 -0
@@ -1335,6 +1335,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcdif (usb_endpoint_xfer_isoc (&urb->ep->desc)) size = urb->number_of_packets; +else if (usb_endpoint_is_bulk_out (&urb->ep->desc) && + urb->transfer_buffer_length >0 && + urb->transfer_flags &URB_ZERO_PACKET && + !(urb->transfer_buffer_length %usb_endpoint_maxp (&urb->ep->desc))) + size =2 ;else size =1 ;
Patches currently in stable-queue which might be from [email protected] are
queue-4.2/usb-xhci-add-support-for-urb_zero_packet-to-bulk-sg-transfers.patch