lkml.org 
[lkml]   [2015]   [Sep]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: [PATCH] xhci: create one unified function to calculate TRB TD remainder.
    From
    Date
    Hi,

    It works ok when I add MTK's quirk into xhci_td_remainder(), and test it
    by usb camera, udisk, usb ethernet adapter, and hub.


    On Tue, 2015-09-08 at 14:09 +0300, Mathias Nyman wrote:
    > xhci versions 1.0 and later report the untransferred data remaining in a
    > TD a bit differently than older hosts.
    >
    > We used to have separate functions for these, and needed to check host
    > version before calling the right function.
    >
    > Now Mediatek host has an additional quirk on how it uses the TD Size
    > field for remaining data. To prevent yet another function for calculating
    > remainder we instead want to make one quirk friendly unified function.
    >
    > Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
    > ---
    > drivers/usb/host/xhci-ring.c | 106 ++++++++++++++++++-------------------------
    > drivers/usb/host/xhci.h | 2 +
    > 2 files changed, 46 insertions(+), 62 deletions(-)
    >
    > diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
    > index a47a1e8..57f40a1 100644
    > --- a/drivers/usb/host/xhci-ring.c
    > +++ b/drivers/usb/host/xhci-ring.c
    > @@ -3020,21 +3020,6 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
    > }
    >
    > /*
    > - * The TD size is the number of bytes remaining in the TD (including this TRB),
    > - * right shifted by 10.
    > - * It must fit in bits 21:17, so it can't be bigger than 31.
    > - */
    > -static u32 xhci_td_remainder(unsigned int remainder)
    > -{
    > - u32 max = (1 << (21 - 17 + 1)) - 1;
    > -
    > - if ((remainder >> 10) >= max)
    > - return max << 17;
    > - else
    > - return (remainder >> 10) << 17;
    > -}
    > -
    > -/*
    > * For xHCI 1.0 host controllers, TD size is the number of max packet sized
    > * packets remaining in the TD (*not* including this TRB).
    > *
    > @@ -3046,30 +3031,36 @@ static u32 xhci_td_remainder(unsigned int remainder)
    > *
    > * TD size = total_packet_count - packets_transferred
    > *
    > - * It must fit in bits 21:17, so it can't be bigger than 31.
    > + * For xHCI 0.96 and older, TD size field should be the remaining bytes
    > + * including this TRB, right shifted by 10
    > + *
    > + * For all hosts it must fit in bits 21:17, so it can't be bigger than 31.
    > + * This is taken care of in the TRB_TD_SIZE() macro
    > + *
    > * The last TRB in a TD must have the TD size set to zero.
    > */
    > -static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
    > - unsigned int total_packet_count, struct urb *urb,
    > - unsigned int num_trbs_left)
    > +static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
    > + int trb_buff_len, unsigned int td_total_len,
    > + struct urb *urb, unsigned int num_trbs_left)
    > {
    > - int packets_transferred;
    > + u32 maxp, total_packet_count;
    > +
    > + if (xhci->hci_version < 0x100)
    > + return ((td_total_len - transferred) >> 10);
    > +
    > + maxp = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
    > + total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
    >
    > /* One TRB with a zero-length data packet. */
    > - if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0))
    > + if (num_trbs_left == 0 || (transferred == 0 && trb_buff_len == 0) ||
    > + trb_buff_len == td_total_len)
    > return 0;
    >
    > - /* All the TRB queueing functions don't count the current TRB in
    > - * running_total.
    > - */
    > - packets_transferred = (running_total + trb_buff_len) /
    > - GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
    > -
    > - if ((total_packet_count - packets_transferred) > 31)
    > - return 31 << 17;
    > - return (total_packet_count - packets_transferred) << 17;
    > + /* Queueing functions don't count the current TRB into transferred */
    > + return (total_packet_count - ((transferred + trb_buff_len) / maxp));
    > }
    >
    > +
    > static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
    > struct urb *urb, int slot_id, unsigned int ep_index)
    > {
    > @@ -3191,17 +3182,12 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
    > }
    >
    > /* Set the TRB length, TD size, and interrupter fields. */
    > - if (xhci->hci_version < 0x100) {
    > - remainder = xhci_td_remainder(
    > - urb->transfer_buffer_length -
    > - running_total);
    > - } else {
    > - remainder = xhci_v1_0_td_remainder(running_total,
    > - trb_buff_len, total_packet_count, urb,
    > - num_trbs - 1);
    > - }
    > + remainder = xhci_td_remainder(xhci, running_total, trb_buff_len,
    > + urb->transfer_buffer_length,
    > + urb, num_trbs - 1);
    > +
    > length_field = TRB_LEN(trb_buff_len) |
    > - remainder |
    > + TRB_TD_SIZE(remainder) |
    > TRB_INTR_TARGET(0);
    >
    > if (num_trbs > 1)
    > @@ -3364,17 +3350,12 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
    > field |= TRB_ISP;
    >
    > /* Set the TRB length, TD size, and interrupter fields. */
    > - if (xhci->hci_version < 0x100) {
    > - remainder = xhci_td_remainder(
    > - urb->transfer_buffer_length -
    > - running_total);
    > - } else {
    > - remainder = xhci_v1_0_td_remainder(running_total,
    > - trb_buff_len, total_packet_count, urb,
    > - num_trbs - 1);
    > - }
    > + remainder = xhci_td_remainder(xhci, running_total, trb_buff_len,
    > + urb->transfer_buffer_length,
    > + urb, num_trbs - 1);
    > +
    > length_field = TRB_LEN(trb_buff_len) |
    > - remainder |
    > + TRB_TD_SIZE(remainder) |
    > TRB_INTR_TARGET(0);
    >
    > if (num_trbs > 1)
    > @@ -3412,7 +3393,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
    > struct usb_ctrlrequest *setup;
    > struct xhci_generic_trb *start_trb;
    > int start_cycle;
    > - u32 field, length_field;
    > + u32 field, length_field, remainder;
    > struct urb_priv *urb_priv;
    > struct xhci_td *td;
    >
    > @@ -3485,9 +3466,15 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
    > else
    > field = TRB_TYPE(TRB_DATA);
    >
    > + remainder = xhci_td_remainder(xhci, 0,
    > + urb->transfer_buffer_length,
    > + urb->transfer_buffer_length,
    > + urb, 1);
    > +
    > length_field = TRB_LEN(urb->transfer_buffer_length) |
    > - xhci_td_remainder(urb->transfer_buffer_length) |
    > + TRB_TD_SIZE(remainder) |
    > TRB_INTR_TARGET(0);
    > +
    > if (urb->transfer_buffer_length > 0) {
    > if (setup->bRequestType & USB_DIR_IN)
    > field |= TRB_DIR_IN;
    > @@ -3816,17 +3803,12 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
    > trb_buff_len = td_remain_len;
    >
    > /* Set the TRB length, TD size, & interrupter fields. */
    > - if (xhci->hci_version < 0x100) {
    > - remainder = xhci_td_remainder(
    > - td_len - running_total);
    > - } else {
    > - remainder = xhci_v1_0_td_remainder(
    > - running_total, trb_buff_len,
    > - total_packet_count, urb,
    > - (trbs_per_td - j - 1));
    > - }
    > + remainder = xhci_td_remainder(xhci, running_total,
    > + trb_buff_len, td_len,
    > + urb, trbs_per_td - j - 1);
    > +
    > length_field = TRB_LEN(trb_buff_len) |
    > - remainder |
    > + TRB_TD_SIZE(remainder) |
    > TRB_INTR_TARGET(0);
    >
    > queue_trb(xhci, ep_ring, more_trbs_coming,
    > diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
    > index dbda41e..ea8b904 100644
    > --- a/drivers/usb/host/xhci.h
    > +++ b/drivers/usb/host/xhci.h
    > @@ -1136,6 +1136,8 @@ enum xhci_setup_dev {
    > /* Normal TRB fields */
    > /* transfer_len bitmasks - bits 0:16 */
    > #define TRB_LEN(p) ((p) & 0x1ffff)
    > +/* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */
    > +#define TRB_TD_SIZE(p) (min((p), (u32)31) << 17)
    > /* Interrupter Target - which MSI-X vector to target the completion event at */
    > #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
    > #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)




    \
     
     \ /
      Last update: 2015-09-11 06:41    [W:2.927 / U:1.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site