From 284d20552461466b04d6bfeafeb1c47a8891b591 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 5 Sep 2013 11:01:20 +0300 Subject: xhci: Fix oops happening after address device timeout When a command times out, the command ring is first aborted, and then stopped. If the command ring is empty when it is stopped the stop event will point to next command which is not yet set. xHCI tries to handle this next event often causing an oops. Don't handle command completion events on stopped cmd ring if ring is empty. This patch should be backported to kernels as old as 3.7, that contain the commit b92cc66c047ff7cf587b318fe377061a353c120f "xHCI: add aborting command ring function" Signed-off-by: Mathias Nyman Reported-by: Giovanni Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org --- drivers/usb/host/xhci-ring.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 411da1fc7ae8..aaa2906f7b78 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1414,6 +1414,12 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, inc_deq(xhci, xhci->cmd_ring); return; } + /* There is no command to handle if we get a stop event when the + * command ring is empty, event->cmd_trb points to the next + * unset command + */ + if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue) + return; } switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3]) -- cgit v1.2.3-59-g8ed1b From ec7e43e2d98173483866fe2e4e690143626b659c Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 30 Aug 2013 18:25:49 +0300 Subject: xhci: Ensure a command structure points to the correct trb on the command ring If a command on the command ring needs to be cancelled before it is handled it can be turned to a no-op operation when the ring is stopped. We want to store the command ring enqueue pointer in the command structure when the command in enqueued for the cancellation case. Some commands used to store the command ring dequeue pointers instead of enqueue (these often worked because enqueue happends to equal dequeue quite often) Other commands correctly used the enqueue pointer but did not check if it pointed to a valid trb or a link trb, this caused for example stop endpoint command to timeout in xhci_stop_device() in about 2% of suspend/resume cases. This should also solve some weird behavior happening in command cancellation cases. This patch is based on a patch submitted by Sarah Sharp to linux-usb, but then forgotten: http://marc.info/?l=linux-usb&m=136269803207465&w=2 This patch should be backported to kernels as old as 3.7, that contain the commit b92cc66c047ff7cf587b318fe377061a353c120f "xHCI: add aborting command ring function" Signed-off-by: Mathias Nyman Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org --- drivers/usb/host/xhci-hub.c | 2 +- drivers/usb/host/xhci-ring.c | 10 ++++++++++ drivers/usb/host/xhci.c | 25 +++++-------------------- drivers/usb/host/xhci.h | 1 + 4 files changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index fae697ed0b70..ccf0a06199a3 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -287,7 +287,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) xhci_queue_stop_endpoint(xhci, slot_id, i, suspend); } - cmd->command_trb = xhci->cmd_ring->enqueue; + cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list); xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend); xhci_ring_cmd_db(xhci); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index aaa2906f7b78..9ac9672d4498 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -123,6 +123,16 @@ static int enqueue_is_link_trb(struct xhci_ring *ring) return TRB_TYPE_LINK_LE32(link->control); } +union xhci_trb *xhci_find_next_enqueue(struct xhci_ring *ring) +{ + /* Enqueue pointer can be left pointing to the link TRB, + * we must handle that + */ + if (TRB_TYPE_LINK_LE32(ring->enqueue->link.control)) + return ring->enq_seg->next->trbs; + return ring->enqueue; +} + /* Updates trb to point to the next TRB in the ring, and updates seg if the next * TRB is in a new segment. This does not skip over link TRBs, and it does not * effect the ring dequeue or enqueue pointers. diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 49b6edb84a79..1e36dbb48366 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2598,15 +2598,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, if (command) { cmd_completion = command->completion; cmd_status = &command->status; - command->command_trb = xhci->cmd_ring->enqueue; - - /* Enqueue pointer can be left pointing to the link TRB, - * we must handle that - */ - if (TRB_TYPE_LINK_LE32(command->command_trb->link.control)) - command->command_trb = - xhci->cmd_ring->enq_seg->next->trbs; - + command->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); list_add_tail(&command->cmd_list, &virt_dev->cmd_list); } else { cmd_completion = &virt_dev->cmd_completion; @@ -2614,7 +2606,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, } init_completion(cmd_completion); - cmd_trb = xhci->cmd_ring->dequeue; + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); if (!ctx_change) ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, udev->slot_id, must_succeed); @@ -3439,14 +3431,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Attempt to submit the Reset Device command to the command ring */ spin_lock_irqsave(&xhci->lock, flags); - reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; - - /* Enqueue pointer can be left pointing to the link TRB, - * we must handle that - */ - if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control)) - reset_device_cmd->command_trb = - xhci->cmd_ring->enq_seg->next->trbs; + reset_device_cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); ret = xhci_queue_reset_device(xhci, slot_id); @@ -3650,7 +3635,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) union xhci_trb *cmd_trb; spin_lock_irqsave(&xhci->lock, flags); - cmd_trb = xhci->cmd_ring->dequeue; + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); @@ -3785,7 +3770,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) slot_ctx->dev_info >> 27); spin_lock_irqsave(&xhci->lock, flags); - cmd_trb = xhci->cmd_ring->dequeue; + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, udev->slot_id); if (ret) { diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 46aa14894148..f3e10206cd95 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1840,6 +1840,7 @@ int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, union xhci_trb *cmd_trb); void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id); +union xhci_trb *xhci_find_next_enqueue(struct xhci_ring *ring); /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, -- cgit v1.2.3-59-g8ed1b From 8b3d45705e54075cfb9d4212dbca9ea82c85c4b8 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 20 Aug 2013 08:12:12 -0700 Subject: usb: Fix xHCI host issues on remote wakeup. When a device signals remote wakeup on a roothub, and the suspend change bit is set, the host controller driver must not give control back to the USB core until the port goes back into the active state. EHCI accomplishes this by waiting in the get port status function until the PORT_RESUME bit is cleared: /* stop resume signaling */ temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME); ehci_writel(ehci, temp, status_reg); clear_bit(wIndex, &ehci->resuming_ports); retval = ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 2000 /* 2msec */); Similarly, the xHCI host should wait until the port goes into U0, before passing control up to the USB core. When the port transitions from the RExit state to U0, the xHCI driver will get a port status change event. We need to wait for that event before passing control up to the USB core. After the port transitions to the active state, the USB core should time a recovery interval before it talks to the device. The length of that recovery interval is TRSMRCY, 10 ms, mentioned in the USB 2.0 spec, section 7.1.7.7. The previous xHCI code (which did not wait for the port to go into U0) would cause the USB core to violate that recovery interval. This bug caused numerous USB device disconnects on remote wakeup under ChromeOS and a Lynx Point LP xHCI host that takes up to 20 ms to move from RExit to U0. ChromeOS is very aggressive about power savings, and sets the autosuspend_delay to 100 ms, and disables USB persist. I attempted to replicate this bug with Ubuntu 12.04, but could not. I used Ubuntu 12.04 on the same platform, with the same BIOS that the bug was triggered on ChromeOS with. I also changed the USB sysfs settings as described above, but still could not reproduce the bug under Ubuntu. It may be that ChromeOS userspace triggers this bug through additional settings. Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-hub.c | 45 ++++++++++++++++++++++++++++++++++---------- drivers/usb/host/xhci-mem.c | 2 ++ drivers/usb/host/xhci-ring.c | 13 +++++++++++++ drivers/usb/host/xhci.h | 10 ++++++++++ 4 files changed, 60 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index ccf0a06199a3..773a6b28c4f1 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -552,11 +552,15 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) * - Mark a port as being done with device resume, * and ring the endpoint doorbells. * - Stop the Synopsys redriver Compliance Mode polling. + * - Drop and reacquire the xHCI lock, in order to wait for port resume. */ static u32 xhci_get_port_status(struct usb_hcd *hcd, struct xhci_bus_state *bus_state, __le32 __iomem **port_array, - u16 wIndex, u32 raw_port_status) + u16 wIndex, u32 raw_port_status, + unsigned long flags) + __releases(&xhci->lock) + __acquires(&xhci->lock) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); u32 status = 0; @@ -591,21 +595,42 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, return 0xffffffff; if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { + int time_left; + xhci_dbg(xhci, "Resume USB2 port %d\n", wIndex + 1); bus_state->resume_done[wIndex] = 0; clear_bit(wIndex, &bus_state->resuming_ports); + + set_bit(wIndex, &bus_state->rexit_ports); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); - xhci_dbg(xhci, "set port %d resume\n", - wIndex + 1); - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - wIndex + 1); - if (!slot_id) { - xhci_dbg(xhci, "slot_id is zero\n"); - return 0xffffffff; + + spin_unlock_irqrestore(&xhci->lock, flags); + time_left = wait_for_completion_timeout( + &bus_state->rexit_done[wIndex], + msecs_to_jiffies( + XHCI_MAX_REXIT_TIMEOUT)); + spin_lock_irqsave(&xhci->lock, flags); + + if (time_left) { + slot_id = xhci_find_slot_id_by_port(hcd, + xhci, wIndex + 1); + if (!slot_id) { + xhci_dbg(xhci, "slot_id is zero\n"); + return 0xffffffff; + } + xhci_ring_device(xhci, slot_id); + } else { + int port_status = xhci_readl(xhci, + port_array[wIndex]); + xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n", + XHCI_MAX_REXIT_TIMEOUT, + port_status); + status |= USB_PORT_STAT_SUSPEND; + clear_bit(wIndex, &bus_state->rexit_ports); } - xhci_ring_device(xhci, slot_id); + bus_state->port_c_suspend |= 1 << wIndex; bus_state->suspended_ports &= ~(1 << wIndex); } else { @@ -728,7 +753,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; } status = xhci_get_port_status(hcd, bus_state, port_array, - wIndex, temp); + wIndex, temp, flags); if (status == 0xffffffff) goto error; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 53b972c2a09f..83bcd13622c3 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2428,6 +2428,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) for (i = 0; i < USB_MAXCHILDREN; ++i) { xhci->bus_state[0].resume_done[i] = 0; xhci->bus_state[1].resume_done[i] = 0; + /* Only the USB 2.0 completions will ever be used. */ + init_completion(&xhci->bus_state[1].rexit_done[i]); } if (scratchpad_alloc(xhci, flags)) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9ac9672d4498..dd02402700d5 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1759,6 +1759,19 @@ static void handle_port_status(struct xhci_hcd *xhci, } } + /* + * Check to see if xhci-hub.c is waiting on RExit to U0 transition (or + * RExit to a disconnect state). If so, let the the driver know it's + * out of the RExit state. + */ + if (!DEV_SUPERSPEED(temp) && + test_and_clear_bit(faked_port_index, + &bus_state->rexit_ports)) { + complete(&bus_state->rexit_done[faked_port_index]); + bogus_port_status = true; + goto cleanup; + } + if (hcd->speed != HCD_USB3) xhci_test_and_clear_bit(xhci, port_array, faked_port_index, PORT_PLC); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f3e10206cd95..289fbfbae746 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1412,8 +1412,18 @@ struct xhci_bus_state { unsigned long resume_done[USB_MAXCHILDREN]; /* which ports have started to resume */ unsigned long resuming_ports; + /* Which ports are waiting on RExit to U0 transition. */ + unsigned long rexit_ports; + struct completion rexit_done[USB_MAXCHILDREN]; }; + +/* + * It can take up to 20 ms to transition from RExit to U0 on the + * Intel Lynx Point LP xHCI host. + */ +#define XHCI_MAX_REXIT_TIMEOUT (20 * 1000) + static inline unsigned int hcd_index(struct usb_hcd *hcd) { if (hcd->speed == HCD_USB3) -- cgit v1.2.3-59-g8ed1b From 526867c3ca0caa2e3e846cb993b0f961c33c2abb Mon Sep 17 00:00:00 2001 From: Florian Wolter Date: Wed, 14 Aug 2013 10:33:16 +0200 Subject: xhci: Fix race between ep halt and URB cancellation The halted state of a endpoint cannot be cleared over CLEAR_HALT from a user process, because the stopped_td variable was overwritten in the handle_stopped_endpoint() function. So the xhci_endpoint_reset() function will refuse the reset and communication with device can not run over this endpoint. https://bugzilla.kernel.org/show_bug.cgi?id=60699 Signed-off-by: Florian Wolter Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-ring.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index dd02402700d5..6bfbd80ec2b9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -869,8 +869,12 @@ remove_finished_td: /* Otherwise ring the doorbell(s) to restart queued transfers */ ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } - ep->stopped_td = NULL; - ep->stopped_trb = NULL; + + /* Clear stopped_td and stopped_trb if endpoint is not halted */ + if (!(ep->ep_state & EP_HALTED)) { + ep->stopped_td = NULL; + ep->stopped_trb = NULL; + } /* * Drop the lock and complete the URBs in the cancelled TD list. -- cgit v1.2.3-59-g8ed1b From 38d7f6885164b114fdfae84bc18397e8fced9b00 Mon Sep 17 00:00:00 2001 From: Xenia Ragiadakou Date: Wed, 4 Sep 2013 17:24:45 +0300 Subject: usbcore: check usb device's state before sending a Set SEL control transfer Set SEL control urbs cannot be sent to a device in unconfigured state. This patch adds a check in usb_req_set_sel() to ensure the usb device's state is USB_STATE_CONFIGURED. Signed-off-by: Xenia Ragiadakou Reported-by: Martin MOKREJS Suggested-by: Sarah Sharp Signed-off-by: Sarah Sharp --- drivers/usb/core/hub.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dde4c83516a1..e6b682c6c236 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3426,6 +3426,9 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) unsigned long long u2_pel; int ret; + if (udev->state != USB_STATE_CONFIGURED) + return 0; + /* Convert SEL and PEL stored in ns to us */ u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000); u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000); -- cgit v1.2.3-59-g8ed1b From 8937669fd637e2edff05973cb1fdee5f910cbcc7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 24 Sep 2013 15:48:05 -0400 Subject: USB: iMX21: accept very late isochronous URBs Commit 24f531371de1 (USB: EHCI: accept very late isochronous URBs) changed the isochronous API provided by ehci-hcd. URBs submitted too late, so that the time slots for all their packets have already expired, are no longer rejected outright. Instead the submission is accepted, and the URB completes normally with a -EXDEV error for each packet. This is what client drivers expect. The same policy should be implemented in imx21-hcd, but I don't know enough about the hardware to do it. As a second-best substitute, this patch treats very late isochronous submissions as though the URB_ISO_ASAP flag were set. I don't have any way to test this change, unfortunately. Signed-off-by: Alan Stern CC: Sascha Hauer CC: Martin Fuzzey Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/imx21-hcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 60a5de505ca1..adb01d950a16 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -824,13 +824,13 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd, i = DIV_ROUND_UP(wrap_frame( cur_frame - urb->start_frame), urb->interval); - if (urb->transfer_flags & URB_ISO_ASAP) { + + /* Treat underruns as if URB_ISO_ASAP was set */ + if ((urb->transfer_flags & URB_ISO_ASAP) || + i >= urb->number_of_packets) { urb->start_frame = wrap_frame(urb->start_frame + i * urb->interval); i = 0; - } else if (i >= urb->number_of_packets) { - ret = -EXDEV; - goto alloc_dmem_failed; } } } -- cgit v1.2.3-59-g8ed1b From bef073b067a7b1874a6b381e0035bb0516d71a77 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 24 Sep 2013 15:47:20 -0400 Subject: USB: UHCI: accept very late isochronous URBs Commit 24f531371de1 (USB: EHCI: accept very late isochronous URBs) changed the isochronous API provided by ehci-hcd. URBs submitted too late, so that the time slots for all their packets have already expired, are no longer rejected outright. Instead the submission is accepted, and the URB completes normally with a -EXDEV error for each packet. This is what client drivers expect. This patch implements the same policy in uhci-hcd. It should be applied to all kernels containing commit c44b225077bb (UHCI: implement new semantics for URB_ISO_ASAP). Signed-off-by: Alan Stern CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-q.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 041c6ddb695c..da6f56d996ce 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1303,7 +1303,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, } /* Fell behind? */ - if (uhci_frame_before_eq(frame, next)) { + if (!uhci_frame_before_eq(next, frame)) { /* USB_ISO_ASAP: Round up to the first available slot */ if (urb->transfer_flags & URB_ISO_ASAP) @@ -1311,13 +1311,17 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, -qh->period; /* - * Not ASAP: Use the next slot in the stream. If - * the entire URB falls before the threshold, fail. + * Not ASAP: Use the next slot in the stream, + * no matter what. */ else if (!uhci_frame_before_eq(next, frame + (urb->number_of_packets - 1) * qh->period)) - return -EXDEV; + dev_dbg(uhci_dev(uhci), "iso underrun %p (%u+%u < %u)\n", + urb, frame, + (urb->number_of_packets - 1) * + qh->period, + next); } } -- cgit v1.2.3-59-g8ed1b From a8693424c751b8247ee19bd8b857f1d4f432b972 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 24 Sep 2013 15:46:45 -0400 Subject: USB: OHCI: accept very late isochronous URBs Commit 24f531371de1 (USB: EHCI: accept very late isochronous URBs) changed the isochronous API provided by ehci-hcd. URBs submitted too late, so that the time slots for all their packets have already expired, are no longer rejected outright. Instead the submission is accepted, and the URB completes normally with a -EXDEV error for each packet. This is what client drivers expect. This patch implements the same policy in ohci-hcd. The change is more complicated than it was in ehci-hcd, because ohci-hcd doesn't scan for isochronous completions in the same way as ehci-hcd does. Rather, it depends on the hardware adding completed TDs to a "done queue". Some OHCI controller don't handle this properly when a TD's time slot has already expired, so we have to avoid adding such TDs to the schedule in the first place. As a result, if the URB was submitted too late then none of its TDs will get put on the schedule, so none of them will end up on the done queue, so the driver will never realize that the URB should be completed. To solve this problem, the patch adds one to urb_priv->td_cnt for such URBs, making it larger than urb_priv->length (td_cnt already gets set to the number of TD's that had to be skipped because their slots have expired). Each time an URB is given back, the finish_urb() routine looks to see if urb_priv->td_cnt for the next URB on the same endpoint is marked in this way. If so, it gives back the next URB right away. This should be applied to all kernels containing commit 815fa7b91761 (USB: OHCI: fix logic for scheduling isochronous URBs). Signed-off-by: Alan Stern CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 22 ++++++++++++---------- drivers/usb/host/ohci-q.c | 26 ++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 8f6b695af6a4..604cad1bcf9c 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -216,31 +216,26 @@ static int ohci_urb_enqueue ( frame &= ~(ed->interval - 1); frame |= ed->branch; urb->start_frame = frame; + ed->last_iso = frame + ed->interval * (size - 1); } } else if (ed->type == PIPE_ISOCHRONOUS) { u16 next = ohci_frame_no(ohci) + 1; u16 frame = ed->last_iso + ed->interval; + u16 length = ed->interval * (size - 1); /* Behind the scheduling threshold? */ if (unlikely(tick_before(frame, next))) { - /* USB_ISO_ASAP: Round up to the first available slot */ + /* URB_ISO_ASAP: Round up to the first available slot */ if (urb->transfer_flags & URB_ISO_ASAP) { frame += (next - frame + ed->interval - 1) & -ed->interval; /* - * Not ASAP: Use the next slot in the stream. If - * the entire URB falls before the threshold, fail. + * Not ASAP: Use the next slot in the stream, + * no matter what. */ } else { - if (tick_before(frame + ed->interval * - (urb->number_of_packets - 1), next)) { - retval = -EXDEV; - usb_hcd_unlink_urb_from_ep(hcd, urb); - goto fail; - } - /* * Some OHCI hardware doesn't handle late TDs * correctly. After retiring them it proceeds @@ -251,9 +246,16 @@ static int ohci_urb_enqueue ( urb_priv->td_cnt = DIV_ROUND_UP( (u16) (next - frame), ed->interval); + if (urb_priv->td_cnt >= urb_priv->length) { + ++urb_priv->td_cnt; /* Mark it */ + ohci_dbg(ohci, "iso underrun %p (%u+%u < %u)\n", + urb, frame, length, + next); + } } } urb->start_frame = frame; + ed->last_iso = frame + length; } /* fill the TDs and link them to the ed; and diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index df4a6707322d..e7f577e63624 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -41,9 +41,13 @@ finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { - struct device *dev = ohci_to_hcd(ohci)->self.controller; + struct device *dev = ohci_to_hcd(ohci)->self.controller; + struct usb_host_endpoint *ep = urb->ep; + struct urb_priv *urb_priv; + // ASSERT (urb->hcpriv != 0); + restart: urb_free_priv (ohci, urb->hcpriv); urb->hcpriv = NULL; if (likely(status == -EINPROGRESS)) @@ -80,6 +84,21 @@ __acquires(ohci->lock) ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE); ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); } + + /* + * An isochronous URB that is sumitted too late won't have any TDs + * (marked by the fact that the td_cnt value is larger than the + * actual number of TDs). If the next URB on this endpoint is like + * that, give it back now. + */ + if (!list_empty(&ep->urb_list)) { + urb = list_first_entry(&ep->urb_list, struct urb, urb_list); + urb_priv = urb->hcpriv; + if (urb_priv->td_cnt > urb_priv->length) { + status = 0; + goto restart; + } + } } @@ -546,7 +565,6 @@ td_fill (struct ohci_hcd *ohci, u32 info, td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000); *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci, (data & 0x0FFF) | 0xE000); - td->ed->last_iso = info & 0xffff; } else { td->hwCBP = cpu_to_hc32 (ohci, data); } @@ -996,7 +1014,7 @@ rescan_this: urb_priv->td_cnt++; /* if URB is done, clean up */ - if (urb_priv->td_cnt == urb_priv->length) { + if (urb_priv->td_cnt >= urb_priv->length) { modified = completed = 1; finish_urb(ohci, urb, 0); } @@ -1086,7 +1104,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) urb_priv->td_cnt++; /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) + if (urb_priv->td_cnt >= urb_priv->length) finish_urb(ohci, urb, status); /* clean schedule: unlink EDs that are no longer busy */ -- cgit v1.2.3-59-g8ed1b From f875fdbf344b9fde207f66b392c40845dd7e5aa6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 24 Sep 2013 15:45:25 -0400 Subject: USB: fix PM config symbol in uhci-hcd, ehci-hcd, and xhci-hcd Since uhci-hcd, ehci-hcd, and xhci-hcd support runtime PM, the .pm field in their pci_driver structures should be protected by CONFIG_PM rather than CONFIG_PM_SLEEP. The corresponding change has already been made for ohci-hcd. Without this change, controllers won't do runtime suspend if system suspend or hibernation isn't enabled. Signed-off-by: Alan Stern CC: Sarah Sharp CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 2 +- drivers/usb/host/uhci-pci.c | 2 +- drivers/usb/host/xhci-pci.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 6bd299e61f58..854c2ec7b699 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -361,7 +361,7 @@ static struct pci_driver ehci_pci_driver = { .remove = usb_hcd_pci_remove, .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .driver = { .pm = &usb_hcd_pci_pm_ops }, diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index c300bd2f7d1c..0f228c46eeda 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -293,7 +293,7 @@ static struct pci_driver uhci_pci_driver = { .remove = usb_hcd_pci_remove, .shutdown = uhci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .driver = { .pm = &usb_hcd_pci_pm_ops }, diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index c2d495057eb5..236c3aabe940 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -351,7 +351,7 @@ static struct pci_driver xhci_pci_driver = { /* suspend and resume implemented later */ .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .driver = { .pm = &usb_hcd_pci_pm_ops }, -- cgit v1.2.3-59-g8ed1b From f84839daa793f36ec7f8795d7510f0d61fa8875a Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 17 Sep 2013 12:37:20 +0800 Subject: usb: chipidea: udc: fix the oops after rmmod gadget When we rmmod gadget, the ci->driver needs to be cleared. Otherwise, when we plug in usb cable again, the driver will consider gadget is there, and go to enumeration procedure, but in fact, it was removed. ci_hdrc ci_hdrc.0: Connected to host Unable to handle kernel paging request at virtual address 7f02a42c pgd = 80004000 [7f02a42c] *pgd=3f13d811, *pte=00000000, *ppte=00000000 Internal error: Oops: 7 [#1] SMP ARM Modules linked in: usb_f_acm u_serial libcomposite configfs [last unloaded: g_serial] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.10.0+ #42 task: 807dba88 ti: 807d0000 task.ti: 807d0000 PC is at udc_irq+0x8fc/0xea4 LR is at l2x0_cache_sync+0x5c/0x6c pc : [<803de7f4>] lr : [<8001d0f0>] psr: 20000193 sp : 807d1d98 ip : 807d1d80 fp : 807d1df4 r10: af809900 r9 : 808184d4 r8 : 00080001 r7 : 00082001 r6 : afb711f8 r5 : afb71010 r4 : ffffffea r3 : 7f02a41c r2 : afb71010 r1 : 807d1dc0 r0 : afb71068 Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c53c7d Table: 3f01804a DAC: 00000017 Process swapper/0 (pid: 0, stack limit = 0x807d0238) Stack: (0x807d1d98 to 0x807d2000) 1d80: 00000000 afb71014 1da0: 000040f6 00000000 00000001 00000000 00007530 00000000 afb71010 001dcd65 1dc0: 01000680 00400000 807d1e2c afb71010 0000004e 00000000 00000000 0000004b 1de0: 808184d4 af809900 807d1e0c 807d1df8 803dbc24 803ddf04 afba75c0 0000004e 1e00: 807d1e44 807d1e10 8007a19c 803dbb9c 8108e7e0 8108e7e0 9ceddce0 af809900 1e20: 0000004e 807d0000 0000004b 00000000 00000010 00000000 807d1e5c 807d1e48 1e40: 8007a334 8007a154 af809900 0000004e 807d1e74 807d1e60 8007d3b4 8007a2f0 1e60: 0000004b 807cce3c 807d1e8c 807d1e78 80079b08 8007d300 00000180 807d8ba0 1e80: 807d1eb4 807d1e90 8000eef4 80079aec 00000000 f400010c 807d8ce4 807d1ed8 1ea0: f4000100 96d5c75d 807d1ed4 807d1eb8 80008600 8000eeac 8042699c 60000013 1ec0: ffffffff 807d1f0c 807d1f54 807d1ed8 8000e180 800085dc 807d1f20 00000046 1ee0: 9cedd275 00000010 8108f080 807de294 00000001 807de248 96d5c75d 00000010 1f00: 00000000 807d1f54 00000000 807d1f20 8005ff54 8042699c 60000013 ffffffff 1f20: 9cedd275 00000010 00000005 8108f080 8108f080 00000001 807de248 8086bd00 1f40: 807d0000 00000001 807d1f7c 807d1f58 80426af0 80426950 807d0000 00000000 1f60: 808184c0 808184c0 807d8954 805b886c 807d1f8c 807d1f80 8000f294 80426a44 1f80: 807d1fac 807d1f90 8005f110 8000f288 807d1fac 807d8908 805b4748 807dc86c 1fa0: 807d1fbc 807d1fb0 805aa58c 8005f068 807d1ff4 807d1fc0 8077c860 805aa530 1fc0: ffffffff ffffffff 8077c330 00000000 00000000 807bef88 00000000 10c53c7d 1fe0: 807d88d0 807bef84 00000000 807d1ff8 10008074 8077c594 00000000 00000000 Backtrace: [<803ddef8>] (udc_irq+0x0/0xea4) from [<803dbc24>] (ci_irq+0x94/0x14c) [<803dbb90>] (ci_irq+0x0/0x14c) from [<8007a19c>] (handle_irq_event_percpu+0x54/0x19c) r5:0000004e r4:afba75c0 [<8007a148>] (handle_irq_event_percpu+0x0/0x19c) from [<8007a334>] (handle_irq_event+0x50/0x70) [<8007a2e4>] (handle_irq_event+0x0/0x70) from [<8007d3b4>] (handle_fasteoi_irq+0xc0/0x16c) r5:0000004e r4:af809900 [<8007d2f4>] (handle_fasteoi_irq+0x0/0x16c) from [<80079b08>] (generic_handle_irq+0x28/0x38) r5:807cce3c r4:0000004b [<80079ae0>] (generic_handle_irq+0x0/0x38) from [<8000eef4>] (handle_IRQ+0x54/0xb4) r4:807d8ba0 r3:00000180 [<8000eea0>] (handle_IRQ+0x0/0xb4) from [<80008600>] (gic_handle_irq+0x30/0x64) r8:96d5c75d r7:f4000100 r6:807d1ed8 r5:807d8ce4 r4:f400010c r3:00000000 [<800085d0>] (gic_handle_irq+0x0/0x64) from [<8000e180>] (__irq_svc+0x40/0x54) Exception stack(0x807d1ed8 to 0x807d1f20) 1ec0: 807d1f20 00000046 1ee0: 9cedd275 00000010 8108f080 807de294 00000001 807de248 96d5c75d 00000010 1f00: 00000000 807d1f54 00000000 807d1f20 8005ff54 8042699c 60000013 ffffffff r7:807d1f0c r6:ffffffff r5:60000013 r4:8042699c [<80426944>] (cpuidle_enter_state+0x0/0xf4) from [<80426af0>] (cpuidle_idle_call+0xb8/0x174) r9:00000001 r8:807d0000 r7:8086bd00 r6:807de248 r5:00000001 r4:8108f080 [<80426a38>] (cpuidle_idle_call+0x0/0x174) from [<8000f294>] (arch_cpu_idle+0x18/0x5c) [<8000f27c>] (arch_cpu_idle+0x0/0x5c) from [<8005f110>] (cpu_startup_entry+0xb4/0x148) [<8005f05c>] (cpu_startup_entry+0x0/0x148) from [<805aa58c>] (rest_init+0x68/0x80) r7:807dc86c [<805aa524>] (rest_init+0x0/0x80) from [<8077c860>] (start_kernel+0x2d8/0x334) [<8077c588>] (start_kernel+0x0/0x334) from [<10008074>] (0x10008074) Code: e59031e0 e51b203c e24b1034 e2820058 (e5933010) ---[ end trace f874b2c5533c04bc ]--- Kernel panic - not syncing: Fatal exception in interrupt Tested-by: Marek Vasut Acked-by: Shawn Guo Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 6b4c2f2eb946..5280454fb2a7 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1667,13 +1667,13 @@ static int ci_udc_stop(struct usb_gadget *gadget, if (ci->platdata->notify_event) ci->platdata->notify_event(ci, CI_HDRC_CONTROLLER_STOPPED_EVENT); - ci->driver = NULL; spin_unlock_irqrestore(&ci->lock, flags); _gadget_stop_activity(&ci->gadget); spin_lock_irqsave(&ci->lock, flags); pm_runtime_put(&ci->gadget.dev); } + ci->driver = NULL; spin_unlock_irqrestore(&ci->lock, flags); return 0; -- cgit v1.2.3-59-g8ed1b From 222bed9b2dff53e4402d4819d6fca09e26b765fb Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 17 Sep 2013 12:37:21 +0800 Subject: usb: chipidea: Fix memleak for ci->hw_bank.regmap when removal It needs to free ci->hw_bank.regmap explicitly since it is not managed resource. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 94626409559a..23763dcec069 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -605,6 +605,7 @@ static int ci_hdrc_remove(struct platform_device *pdev) dbg_remove_files(ci); free_irq(ci->irq, ci); ci_role_destroy(ci); + kfree(ci->hw_bank.regmap); return 0; } -- cgit v1.2.3-59-g8ed1b From 3a254fea70f402859b92a9cd4299ee5de3bbc2f6 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 17 Sep 2013 12:37:23 +0800 Subject: usb: chipidea: imx: Add usb_phy_shutdown at probe's error path If not, the PHY will be active even the controller is not in use. We find this issue due to the PHY's clock refcount is not correct due to -EPROBE_DEFER return after phy's init. Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 74d998d9b45b..be822a2c1776 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -131,7 +131,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret); - goto err_clk; + goto err_phy; } } @@ -143,7 +143,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Can't register ci_hdrc platform device, err=%d\n", ret); - goto err_clk; + goto err_phy; } if (data->usbmisc_data) { @@ -164,6 +164,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data->ci_pdev); +err_phy: + if (data->phy) + usb_phy_shutdown(data->phy); err_clk: clk_disable_unprepare(data->clk); return ret; -- cgit v1.2.3-59-g8ed1b From e7ef5265b158ac1975b1556511e2b11bad5f5522 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 17 Sep 2013 12:37:24 +0800 Subject: usb: chipidea: udc: free pending TD at removal procedure There is a pending TD which is not freed after request finishes, we do this due to a controller bug. This TD needs to be freed when the driver is removed. It prints below error message when unload chipidea driver at current code: "ci_hdrc ci_hdrc.0: dma_pool_destroy ci_hw_td, b0001000 busy" It indicates the buffer at dma pool are still in use. This commit will free the pending TD at driver's removal procedure, it can fix the problem described above. Acked-by: Michael Grzeschik Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/udc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 5280454fb2a7..9333083dd111 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1600,6 +1600,8 @@ static void destroy_eps(struct ci_hdrc *ci) for (i = 0; i < ci->hw_ep_max; i++) { struct ci_hw_ep *hwep = &ci->ci_hw_ep[i]; + if (hwep->pending_td) + free_pending_td(hwep); dma_pool_free(ci->qh_pool, hwep->qh.ptr, hwep->qh.dma); } } -- cgit v1.2.3-59-g8ed1b From 2c740336159d9785ae81e8f9d6ba1a6b922723c9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 17 Sep 2013 12:37:25 +0800 Subject: usb: chipidea: USB_CHIPIDEA should depend on HAS_DMA If NO_DMA=y: drivers/built-in.o: In function `dma_set_coherent_mask': include/linux/dma-mapping.h:93: undefined reference to `dma_supported' Reviewed-and-tested-by: Peter Chen Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 4a851e15e58c..77b47d82c9a6 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -1,6 +1,6 @@ config USB_CHIPIDEA tristate "ChipIdea Highspeed Dual Role Controller" - depends on (USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET) + depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA help Say Y here if your system has a dual role high speed USB controller based on ChipIdea silicon IP. Currently, only the -- cgit v1.2.3-59-g8ed1b From 831abf76643555a99b80a3b54adfa7e4fa0a3259 Mon Sep 17 00:00:00 2001 From: Kurt Garloff Date: Tue, 24 Sep 2013 14:13:48 +0200 Subject: usb/core/devio.c: Don't reject control message to endpoint with wrong direction bit Trying to read data from the Pegasus Technologies NoteTaker (0e20:0101) [1] with the Windows App (EasyNote) works natively but fails when Windows is running under KVM (and the USB device handed to KVM). The reason is a USB control message usb 4-2.2: control urb: bRequestType=22 bRequest=09 wValue=0200 wIndex=0001 wLength=0008 This goes to endpoint address 0x01 (wIndex); however, endpoint address 0x01 does not exist. There is an endpoint 0x81 though (same number, but other direction); the app may have meant that endpoint instead. The kernel thus rejects the IO and thus we see the failure. Apparently, Linux is more strict here than Windows ... we can't change the Win app easily, so that's a problem. It seems that the Win app/driver is buggy here and the driver does not behave fully according to the USB HID class spec that it claims to belong to. The device seems to happily deal with that though (and seems to not really care about this value much). So the question is whether the Linux kernel should filter here. Rejecting has the risk that somewhat non-compliant userspace apps/ drivers (most likely in a virtual machine) are prevented from working. Not rejecting has the risk of confusing an overly sensitive device with such a transfer. Given the fact that Windows does not filter it makes this risk rather small though. The patch makes the kernel more tolerant: If the endpoint address in wIndex does not exist, but an endpoint with toggled direction bit does, it will let the transfer through. (It does NOT change the message.) With attached patch, the app in Windows in KVM works. usb 4-2.2: check_ctrlrecip: process 13073 (qemu-kvm) requesting ep 01 but needs 81 I suspect this will mostly affect apps in virtual environments; as on Linux the apps would have been adapted to the stricter handling of the kernel. I have done that for mine[2]. [1] http://www.pegatech.com/ [2] https://sourceforge.net/projects/notetakerpen/ Signed-off-by: Kurt Garloff Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 737e3c19967b..71dc5d768fa5 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -742,6 +742,22 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, if ((index & ~USB_DIR_IN) == 0) return 0; ret = findintfep(ps->dev, index); + if (ret < 0) { + /* + * Some not fully compliant Win apps seem to get + * index wrong and have the endpoint number here + * rather than the endpoint address (with the + * correct direction). Win does let this through, + * so we'll not reject it here but leave it to + * the device to not break KVM. But we warn. + */ + ret = findintfep(ps->dev, index ^ 0x80); + if (ret >= 0) + dev_info(&ps->dev->dev, + "%s: process %i (%s) requesting ep %02x but needs %02x\n", + __func__, task_pid_nr(current), + current->comm, index, index ^ 0x80); + } if (ret >= 0) ret = checkintf(ps, ret); break; -- cgit v1.2.3-59-g8ed1b From ad1260e9fbf768d6bed227d9604ebee76a84aae3 Mon Sep 17 00:00:00 2001 From: Ramneek Mehresh Date: Mon, 16 Sep 2013 15:11:33 +0530 Subject: fsl/usb: Resolve PHY_CLK_VLD instability issue for ULPI phy For controller versions greater than 1.6, setting ULPI_PHY_CLK_SEL bit when USB_EN bit is already set causes instability issues with PHY_CLK_VLD bit. So USB_EN is set only for IP controller version below 1.6 before setting ULPI_PHY_CLK_SEL bit Signed-off-by: Ramneek Mehresh Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 4449f565d6c6..d3166e693dcb 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -130,7 +130,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, } /* Enable USB controller, 83xx or 8536 */ - if (pdata->have_sysif_regs) + if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); /* Don't need to set host mode here. It will be done by tdi_reset() */ @@ -232,15 +232,9 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ + clrbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); setbits32(non_ehci + FSL_SOC_USB_CTRL, - ULPI_PHY_CLK_SEL); - /* - * Due to controller issue of PHY_CLK_VALID in ULPI - * mode, we set USB_CTRL_USB_EN before checking - * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work. - */ - clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, - UTMI_PHY_EN, USB_CTRL_USB_EN); + ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); } portsc |= PORT_PTS_ULPI; break; -- cgit v1.2.3-59-g8ed1b From 2606b28aabd7dea1766c23a105e1124c95409c96 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 20 Sep 2013 17:14:21 +0100 Subject: USB: Fix breakage in ffs_fs_mount() There's a bunch of failure exits in ffs_fs_mount() with seriously broken recovery logics. Most of that appears to stem from misunderstanding of the ->kill_sb() semantics; unlike ->put_super() it is called for *all* superblocks of given type, no matter how (in)complete the setup had been. ->put_super() is called only if ->s_root is not NULL; any failure prior to setting ->s_root will have the call of ->put_super() skipped. ->kill_sb(), OTOH, awaits every superblock that has come from sget(). Current behaviour of ffs_fs_mount(): We have struct ffs_sb_fill_data data on stack there. We do ffs_dev = functionfs_acquire_dev_callback(dev_name); and store that in data.private_data. Then we call mount_nodev(), passing it ffs_sb_fill() as a callback. That will either fail outright, or manage to call ffs_sb_fill(). There we allocate an instance of struct ffs_data, slap the value of ffs_dev (picked from data.private_data) into ffs->private_data and overwrite data.private_data by storing ffs into an overlapping member (data.ffs_data). Then we store ffs into sb->s_fs_info and attempt to set the rest of the things up (root inode, root dentry, then create /ep0 there). Any of those might fail. Should that happen, we get ffs_fs_kill_sb() called before mount_nodev() returns. If mount_nodev() fails for any reason whatsoever, we proceed to functionfs_release_dev_callback(data.ffs_data); That's broken in a lot of ways. Suppose the thing has failed in allocation of e.g. root inode or dentry. We have functionfs_release_dev_callback(ffs); ffs_data_put(ffs); done by ffs_fs_kill_sb() (ffs accessed via sb->s_fs_info), followed by functionfs_release_dev_callback(ffs); from ffs_fs_mount() (via data.ffs_data). Note that the second functionfs_release_dev_callback() has every chance to be done to freed memory. Suppose we fail *before* root inode allocation. What happens then? ffs_fs_kill_sb() doesn't do anything to ffs (it's either not called at all, or it doesn't have a pointer to ffs stored in sb->s_fs_info). And functionfs_release_dev_callback(data.ffs_data); is called by ffs_fs_mount(), but here we are in nasal daemon country - we are reading from a member of union we'd never stored into. In practice, we'll get what we used to store into the overlapping field, i.e. ffs_dev. And then we get screwed, since we treat it (struct gfs_ffs_obj * in disguise, returned by functionfs_acquire_dev_callback()) as struct ffs_data *, pick what would've been ffs_data ->private_data from it (*well* past the actual end of the struct gfs_ffs_obj - struct ffs_data is much bigger) and poke in whatever it points to. FWIW, there's a minor leak on top of all that in case if ffs_sb_fill() fails on kstrdup() - ffs is obviously forgotten. The thing is, there is no point in playing all those games with union. Just allocate and initialize ffs_data *before* calling mount_nodev() and pass a pointer to it via data.ffs_data. And once it's stored in sb->s_fs_info, clear data.ffs_data, so that ffs_fs_mount() knows that it doesn't need to kill the sucker manually - from that point on we'll have it done by ->kill_sb(). Signed-off-by: Al Viro Acked-by: Michal Nazarewicz Cc: stable # 3.3+ Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_fs.c | 60 ++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 1a66c5baa0d1..0658908d8968 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1034,37 +1034,19 @@ struct ffs_sb_fill_data { struct ffs_file_perms perms; umode_t root_mode; const char *dev_name; - union { - /* set by ffs_fs_mount(), read by ffs_sb_fill() */ - void *private_data; - /* set by ffs_sb_fill(), read by ffs_fs_mount */ - struct ffs_data *ffs_data; - }; + struct ffs_data *ffs_data; }; static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) { struct ffs_sb_fill_data *data = _data; struct inode *inode; - struct ffs_data *ffs; + struct ffs_data *ffs = data->ffs_data; ENTER(); - /* Initialise data */ - ffs = ffs_data_new(); - if (unlikely(!ffs)) - goto Enomem; - ffs->sb = sb; - ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL); - if (unlikely(!ffs->dev_name)) - goto Enomem; - ffs->file_perms = data->perms; - ffs->private_data = data->private_data; - - /* used by the caller of this function */ - data->ffs_data = ffs; - + data->ffs_data = NULL; sb->s_fs_info = ffs; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -1080,17 +1062,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) &data->perms); sb->s_root = d_make_root(inode); if (unlikely(!sb->s_root)) - goto Enomem; + return -ENOMEM; /* EP0 file */ if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations, NULL))) - goto Enomem; + return -ENOMEM; return 0; - -Enomem: - return -ENOMEM; } static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) @@ -1193,6 +1172,7 @@ ffs_fs_mount(struct file_system_type *t, int flags, struct dentry *rv; int ret; void *ffs_dev; + struct ffs_data *ffs; ENTER(); @@ -1200,18 +1180,30 @@ ffs_fs_mount(struct file_system_type *t, int flags, if (unlikely(ret < 0)) return ERR_PTR(ret); + ffs = ffs_data_new(); + if (unlikely(!ffs)) + return ERR_PTR(-ENOMEM); + ffs->file_perms = data.perms; + + ffs->dev_name = kstrdup(dev_name, GFP_KERNEL); + if (unlikely(!ffs->dev_name)) { + ffs_data_put(ffs); + return ERR_PTR(-ENOMEM); + } + ffs_dev = functionfs_acquire_dev_callback(dev_name); - if (IS_ERR(ffs_dev)) - return ffs_dev; + if (IS_ERR(ffs_dev)) { + ffs_data_put(ffs); + return ERR_CAST(ffs_dev); + } + ffs->private_data = ffs_dev; + data.ffs_data = ffs; - data.dev_name = dev_name; - data.private_data = ffs_dev; rv = mount_nodev(t, flags, &data, ffs_sb_fill); - - /* data.ffs_data is set by ffs_sb_fill */ - if (IS_ERR(rv)) + if (IS_ERR(rv) && data.ffs_data) { functionfs_release_dev_callback(data.ffs_data); - + ffs_data_put(data.ffs_data); + } return rv; } -- cgit v1.2.3-59-g8ed1b From eee41b49b80420e3e8c118d18dfacb7da43c1caa Mon Sep 17 00:00:00 2001 From: Shengzhou Liu Date: Mon, 2 Sep 2013 13:25:52 +0800 Subject: USB: fsl/ehci: fix failure of checking PHY_CLK_VALID during reinitialization In case of usb phy reinitialization: e.g. insmod usb-module(usb works well) -> rmmod usb-module -> insmod usb-module It found the PHY_CLK_VALID bit didn't work if it's not with the power-on reset. So we just check PHY_CLK_VALID bit during the stage with POR, this can be met by the tricky of checking FSL_SOC_USB_PRICTRL register. Signed-off-by: Shengzhou Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index d3166e693dcb..f2407b2e8a99 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -264,8 +264,9 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, if (pdata->have_sysif_regs && pdata->controller_ver && (phy_mode == FSL_USB2_PHY_ULPI)) { /* check PHY_CLK_VALID to get phy clk valid */ - if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & - PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { + if (!(spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & + PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0) || + in_be32(non_ehci + FSL_SOC_USB_PRICTRL))) { printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n"); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 85601f8cf67c56a561a6dd5e130e65fdc179047d Mon Sep 17 00:00:00 2001 From: David Cohen Date: Thu, 26 Sep 2013 13:01:44 -0700 Subject: usb: dwc3: add support for Merrifield Add PCI id for Intel Merrifield Signed-off-by: David Cohen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 997ebe420bc9..2e252aae51ca 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -29,6 +29,7 @@ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 +#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e struct dwc3_pci { struct device *dev; @@ -189,6 +190,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); -- cgit v1.2.3-59-g8ed1b