|
@@ -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);
|