Commit b61d378f authored by Sarah Sharp's avatar Sarah Sharp

xhci 1.0: Set transfer burst last packet count field.

The xHCI 1.0 specification defines a new isochronous TRB field, called
transfer burst last packet count (TBLPC).  This field defines the number
of packets in the last "burst" of packets in a TD.  Only SuperSpeed
endpoints can handle more than one burst, so this is set to the number for
packets in a TD for all non-SuperSpeed devices (minus one, since the field
is zero based).

This patch should have no effect on host controllers that don't advertise
the xHCI 1.0 (0x100) version number in their hci_version field.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
parent 5cd43e33
...@@ -3144,6 +3144,42 @@ static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci, ...@@ -3144,6 +3144,42 @@ static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
return roundup(total_packet_count, max_burst + 1) - 1; return roundup(total_packet_count, max_burst + 1) - 1;
} }
/*
* Returns the number of packets in the last "burst" of packets. This field is
* valid for all speeds of devices. USB 2.0 devices can only do one "burst", so
* the last burst packet count is equal to the total number of packets in the
* TD. SuperSpeed endpoints can have up to 3 bursts. All but the last burst
* must contain (bMaxBurst + 1) number of packets, but the last burst can
* contain 1 to (bMaxBurst + 1) packets.
*/
static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
struct usb_device *udev,
struct urb *urb, unsigned int total_packet_count)
{
unsigned int max_burst;
unsigned int residue;
if (xhci->hci_version < 0x100)
return 0;
switch (udev->speed) {
case USB_SPEED_SUPER:
/* bMaxBurst is zero based: 0 means 1 packet per burst */
max_burst = urb->ep->ss_ep_comp.bMaxBurst;
residue = total_packet_count % (max_burst + 1);
/* If residue is zero, the last burst contains (max_burst + 1)
* number of packets, but the TLBPC field is zero-based.
*/
if (residue == 0)
return max_burst;
return residue - 1;
default:
if (total_packet_count == 0)
return 0;
return total_packet_count - 1;
}
}
/* This is for isoc transfer */ /* This is for isoc transfer */
static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index) struct urb *urb, int slot_id, unsigned int ep_index)
...@@ -3186,6 +3222,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -3186,6 +3222,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
for (i = 0; i < num_tds; i++) { for (i = 0; i < num_tds; i++) {
unsigned int total_packet_count; unsigned int total_packet_count;
unsigned int burst_count; unsigned int burst_count;
unsigned int residue;
first_trb = true; first_trb = true;
running_total = 0; running_total = 0;
...@@ -3197,6 +3234,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -3197,6 +3234,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
le16_to_cpu(urb->ep->desc.wMaxPacketSize)); le16_to_cpu(urb->ep->desc.wMaxPacketSize));
burst_count = xhci_get_burst_count(xhci, urb->dev, urb, burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
total_packet_count); total_packet_count);
residue = xhci_get_last_burst_packet_count(xhci,
urb->dev, urb, total_packet_count);
trbs_per_td = count_isoc_trbs_needed(xhci, urb, i); trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
...@@ -3210,7 +3249,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -3210,7 +3249,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
for (j = 0; j < trbs_per_td; j++) { for (j = 0; j < trbs_per_td; j++) {
u32 remainder = 0; u32 remainder = 0;
field = TRB_TBC(burst_count); field = TRB_TBC(burst_count) | TRB_TLBPC(residue);
if (first_trb) { if (first_trb) {
/* Queue the isoc TRB */ /* Queue the isoc TRB */
......
...@@ -944,6 +944,7 @@ struct xhci_event_cmd { ...@@ -944,6 +944,7 @@ struct xhci_event_cmd {
#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
#define TRB_TBC(p) (((p) & 0x3) << 7) #define TRB_TBC(p) (((p) & 0x3) << 7)
#define TRB_TLBPC(p) (((p) & 0xf) << 16)
/* Cycle bit - indicates TRB ownership by HC or HCD */ /* Cycle bit - indicates TRB ownership by HC or HCD */
#define TRB_CYCLE (1<<0) #define TRB_CYCLE (1<<0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment