summaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r--drivers/usb/host/xhci.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ec82fa664e..8aed4283ed 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -257,6 +257,172 @@ static unsigned int xhci_get_ep_index(struct usb_endpoint_descriptor *desc)
return index;
}
+/*
+ * Convert bInterval expressed in microframes (in 1-255 range) to exponent of
+ * microframes, rounded down to nearest power of 2.
+ */
+static unsigned int xhci_microframes_to_exponent(unsigned int desc_interval,
+ unsigned int min_exponent,
+ unsigned int max_exponent)
+{
+ unsigned int interval;
+
+ interval = fls(desc_interval) - 1;
+ interval = clamp_val(interval, min_exponent, max_exponent);
+ if ((1 << interval) != desc_interval)
+ debug("rounding interval to %d microframes, "\
+ "ep desc says %d microframes\n",
+ 1 << interval, desc_interval);
+
+ return interval;
+}
+
+static unsigned int xhci_parse_microframe_interval(struct usb_device *udev,
+ struct usb_endpoint_descriptor *endpt_desc)
+{
+ if (endpt_desc->bInterval == 0)
+ return 0;
+
+ return xhci_microframes_to_exponent(endpt_desc->bInterval, 0, 15);
+}
+
+static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
+ struct usb_endpoint_descriptor *endpt_desc)
+{
+ return xhci_microframes_to_exponent(endpt_desc->bInterval * 8, 3, 10);
+}
+
+/*
+ * Convert interval expressed as 2^(bInterval - 1) == interval into
+ * straight exponent value 2^n == interval.
+ */
+static unsigned int xhci_parse_exponent_interval(struct usb_device *udev,
+ struct usb_endpoint_descriptor *endpt_desc)
+{
+ unsigned int interval;
+
+ interval = clamp_val(endpt_desc->bInterval, 1, 16) - 1;
+ if (interval != endpt_desc->bInterval - 1)
+ debug("ep %#x - rounding interval to %d %sframes\n",
+ endpt_desc->bEndpointAddress, 1 << interval,
+ udev->speed == USB_SPEED_FULL ? "" : "micro");
+
+ if (udev->speed == USB_SPEED_FULL) {
+ /*
+ * Full speed isoc endpoints specify interval in frames,
+ * not microframes. We are using microframes everywhere,
+ * so adjust accordingly.
+ */
+ interval += 3; /* 1 frame = 2^3 uframes */
+ }
+
+ return interval;
+}
+
+/*
+ * Return the polling or NAK interval.
+ *
+ * The polling interval is expressed in "microframes". If xHCI's Interval field
+ * is set to N, it will service the endpoint every 2^(Interval)*125us.
+ *
+ * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval
+ * is set to 0.
+ */
+static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
+ struct usb_endpoint_descriptor *endpt_desc)
+{
+ unsigned int interval = 0;
+
+ switch (udev->speed) {
+ case USB_SPEED_HIGH:
+ /* Max NAK rate */
+ if (usb_endpoint_xfer_control(endpt_desc) ||
+ usb_endpoint_xfer_bulk(endpt_desc)) {
+ interval = xhci_parse_microframe_interval(udev,
+ endpt_desc);
+ break;
+ }
+ /* Fall through - SS and HS isoc/int have same decoding */
+
+ case USB_SPEED_SUPER:
+ if (usb_endpoint_xfer_int(endpt_desc) ||
+ usb_endpoint_xfer_isoc(endpt_desc)) {
+ interval = xhci_parse_exponent_interval(udev,
+ endpt_desc);
+ }
+ break;
+
+ case USB_SPEED_FULL:
+ if (usb_endpoint_xfer_isoc(endpt_desc)) {
+ interval = xhci_parse_exponent_interval(udev,
+ endpt_desc);
+ break;
+ }
+ /*
+ * Fall through for interrupt endpoint interval decoding
+ * since it uses the same rules as low speed interrupt
+ * endpoints.
+ */
+
+ case USB_SPEED_LOW:
+ if (usb_endpoint_xfer_int(endpt_desc) ||
+ usb_endpoint_xfer_isoc(endpt_desc)) {
+ interval = xhci_parse_frame_interval(udev, endpt_desc);
+ }
+ break;
+
+ default:
+ BUG();
+ }
+
+ return interval;
+}
+
+/*
+ * The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps.
+ * High speed endpoint descriptors can define "the number of additional
+ * transaction opportunities per microframe", but that goes in the Max Burst
+ * endpoint context field.
+ */
+static u32 xhci_get_endpoint_mult(struct usb_device *udev,
+ struct usb_endpoint_descriptor *endpt_desc,
+ struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc)
+{
+ if (udev->speed < USB_SPEED_SUPER ||
+ !usb_endpoint_xfer_isoc(endpt_desc))
+ return 0;
+
+ return ss_ep_comp_desc->bmAttributes;
+}
+
+/*
+ * Return the maximum endpoint service interval time (ESIT) payload.
+ * Basically, this is the maxpacket size, multiplied by the burst size
+ * and mult size.
+ */
+static u32 xhci_get_max_esit_payload(struct usb_device *udev,
+ struct usb_endpoint_descriptor *endpt_desc,
+ struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc)
+{
+ int max_burst;
+ int max_packet;
+
+ /* Only applies for interrupt or isochronous endpoints */
+ if (usb_endpoint_xfer_control(endpt_desc) ||
+ usb_endpoint_xfer_bulk(endpt_desc))
+ return 0;
+
+ /* SuperSpeed Isoc ep with less than 48k per esit */
+ if (udev->speed >= USB_SPEED_SUPER)
+ return le16_to_cpu(ss_ep_comp_desc->wBytesPerInterval);
+
+ max_packet = usb_endpoint_maxp(endpt_desc);
+ max_burst = usb_endpoint_maxp_mult(endpt_desc);
+
+ /* A 0 in max burst means 1 transfer per ESIT */
+ return max_packet * max_burst;
+}
+
/**
* Issue a configure endpoint command or evaluate context command
* and wait for it to finish.
@@ -324,6 +490,10 @@ static int xhci_set_configuration(struct usb_device *udev)
int slot_id = udev->slot_id;
struct xhci_virt_device *virt_dev = ctrl->devs[slot_id];
struct usb_interface *ifdesc;
+ u32 max_esit_payload;
+ unsigned int interval;
+ unsigned int mult;
+ unsigned int avg_trb_len;
out_ctx = virt_dev->out_ctx;
in_ctx = virt_dev->in_ctx;
@@ -357,10 +527,26 @@ static int xhci_set_configuration(struct usb_device *udev)
/* filling up ep contexts */
for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) {
struct usb_endpoint_descriptor *endpt_desc = NULL;
+ struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc = NULL;
endpt_desc = &ifdesc->ep_desc[cur_ep];
+ ss_ep_comp_desc = &ifdesc->ss_ep_comp_desc[cur_ep];
trb_64 = 0;
+ /*
+ * Get values to fill the endpoint context, mostly from ep
+ * descriptor. The average TRB buffer lengt for bulk endpoints
+ * is unclear as we have no clue on scatter gather list entry
+ * size. For Isoc and Int, set it to max available.
+ * See xHCI 1.1 spec 4.14.1.1 for details.
+ */
+ max_esit_payload = xhci_get_max_esit_payload(udev, endpt_desc,
+ ss_ep_comp_desc);
+ interval = xhci_get_endpoint_interval(udev, endpt_desc);
+ mult = xhci_get_endpoint_mult(udev, endpt_desc,
+ ss_ep_comp_desc);
+ avg_trb_len = max_esit_payload;
+
ep_index = xhci_get_ep_index(endpt_desc);
ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
@@ -372,6 +558,11 @@ static int xhci_set_configuration(struct usb_device *udev)
/*NOTE: ep_desc[0] actually represents EP1 and so on */
dir = (((endpt_desc->bEndpointAddress) & (0x80)) >> 7);
ep_type = (((endpt_desc->bmAttributes) & (0x3)) | (dir << 2));
+
+ ep_ctx[ep_index]->ep_info =
+ cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
+ EP_INTERVAL(interval) | EP_MULT(mult));
+
ep_ctx[ep_index]->ep_info2 =
cpu_to_le32(ep_type << EP_TYPE_SHIFT);
ep_ctx[ep_index]->ep_info2 |=
@@ -386,6 +577,10 @@ static int xhci_set_configuration(struct usb_device *udev)
virt_dev->eps[ep_index].ring->enqueue;
ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 |
virt_dev->eps[ep_index].ring->cycle_state);
+
+ ep_ctx[ep_index]->tx_info =
+ cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
+ EP_AVG_TRB_LENGTH(avg_trb_len));
}
return xhci_configure_endpoints(udev, false);