From e4ab05df573834b8c70d19db426b7d6286782c1d Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 16 Sep 2009 16:42:30 -0700 Subject: USB: xhci: Stop debugging polling loop when HC dies. If the host controller card is removed from the system, stop the timer function to debug the xHCI rings. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 99911e727e0b..8719a3f6851d 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -335,6 +335,12 @@ void xhci_event_ring_work(unsigned long arg) spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, &xhci->op_regs->status); xhci_dbg(xhci, "op reg status = 0x%x\n", temp); + if (temp == 0xffffffff) { + xhci_dbg(xhci, "HW died, polling stopped.\n"); + spin_unlock_irqrestore(&xhci->lock, flags); + return; + } + temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp); xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled); -- cgit v1.2.2 From e34b2fbf28741310d1d59a217d34e050ce7867e8 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 28 Sep 2009 17:21:37 -0700 Subject: USB: xhci: Handle canceled URBs when HC dies. When the host controller dies (e.g. it is removed from a PCI card slot), the xHCI driver cannot expect commands to complete. The buggy code this patch fixes would mark an URB as canceled and then expect the URB to be completed when the stop endpoint command completed. That would never happen if the host controller was dead, so the USB core would just hang in the disconnect code. If the host controller died, and the driver asks to cancel an URB, free any structures associated with that URB and immediately give it back. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 8719a3f6851d..592e742c5f35 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -782,6 +782,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { unsigned long flags; int ret; + u32 temp; struct xhci_hcd *xhci; struct xhci_td *td; unsigned int ep_index; @@ -794,6 +795,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret || !urb->hcpriv) goto done; + temp = xhci_readl(xhci, &xhci->op_regs->status); + if (temp == 0xffffffff) { + xhci_dbg(xhci, "HW died, freeing TD.\n"); + td = (struct xhci_td *) urb->hcpriv; + + usb_hcd_unlink_urb_from_ep(hcd, urb); + spin_unlock_irqrestore(&xhci->lock, flags); + usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN); + kfree(td); + return ret; + } xhci_dbg(xhci, "Cancel URB %p\n", urb); xhci_dbg(xhci, "Event ring:\n"); -- cgit v1.2.2 From c526d0d4fc9707816b407d2d3336267d3271db2b Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 16 Sep 2009 16:42:39 -0700 Subject: USB: xhci: Don't wait for a disable slot cmd when HC dies. When the host controller dies or is removed while a device is plugged in, the USB core will attempt to deallocate the struct usb_device. That will call into xhci_free_dev(). This function used to attempt to submit a disable slot command to the host controller and clean up the device structures when that command returned. Change xhci_free_dev() to skip the command submission and just free the memory if the host controller died. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 592e742c5f35..d61c49f90f4a 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -1428,11 +1428,20 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); unsigned long flags; + u32 state; if (udev->slot_id == 0) return; spin_lock_irqsave(&xhci->lock, flags); + /* Don't disable the slot if the host controller is dead. */ + state = xhci_readl(xhci, &xhci->op_regs->status); + if (state == 0xffffffff) { + xhci_free_virt_device(xhci, udev->slot_id); + spin_unlock_irqrestore(&xhci->lock, flags); + return; + } + if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); -- cgit v1.2.2 From 0a023c6cf10c63d2ce68a2816d90c2f0f1ad2763 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 18 Sep 2009 08:55:12 -0700 Subject: USB: xhci: Fix dropping endpoints from the xHC schedule. When an endpoint is to be dropped from the hardware bandwidth schedule, we want to clear its add flag. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index d61c49f90f4a..932f99938481 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c @@ -895,7 +895,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, ctrl_ctx->drop_flags |= drop_flag; new_drop_flags = ctrl_ctx->drop_flags; - ctrl_ctx->add_flags = ~drop_flag; + ctrl_ctx->add_flags &= ~drop_flag; new_add_flags = ctrl_ctx->add_flags; last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags); -- cgit v1.2.2 From b0a9cf297e587219332ee4acca243627702c2cc9 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 7 Oct 2009 04:29:31 -0400 Subject: USB: isp1362: fix build warnings on 64-bit systems A bunch of places assumed pointers were 32-bits in size (bit checking and debug output), but none of these affected runtime functionality. Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1362-hcd.c | 18 +++++++++--------- drivers/usb/host/isp1362.h | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index e35d82808bab..5c774ab98252 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2284,10 +2284,10 @@ static int isp1362_mem_config(struct usb_hcd *hcd) dev_info(hcd->self.controller, "ISP1362 Memory usage:\n"); dev_info(hcd->self.controller, " ISTL: 2 * %4d: %4d @ $%04x:$%04x\n", istl_size / 2, istl_size, 0, istl_size / 2); - dev_info(hcd->self.controller, " INTL: %4d * (%3u+8): %4d @ $%04x\n", + dev_info(hcd->self.controller, " INTL: %4d * (%3lu+8): %4d @ $%04x\n", ISP1362_INTL_BUFFERS, intl_blksize - PTD_HEADER_SIZE, intl_size, istl_size); - dev_info(hcd->self.controller, " ATL : %4d * (%3u+8): %4d @ $%04x\n", + dev_info(hcd->self.controller, " ATL : %4d * (%3lu+8): %4d @ $%04x\n", atl_buffers, atl_blksize - PTD_HEADER_SIZE, atl_size, istl_size + intl_size); dev_info(hcd->self.controller, " USED/FREE: %4d %4d\n", total, @@ -2677,12 +2677,12 @@ static int __devexit isp1362_remove(struct platform_device *pdev) DBG(0, "%s: Removing HCD\n", __func__); usb_remove_hcd(hcd); - DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__, - (u32)isp1362_hcd->data_reg); + DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, + isp1362_hcd->data_reg); iounmap(isp1362_hcd->data_reg); - DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__, - (u32)isp1362_hcd->addr_reg); + DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, + isp1362_hcd->addr_reg); iounmap(isp1362_hcd->addr_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); @@ -2810,16 +2810,16 @@ static int __init isp1362_probe(struct platform_device *pdev) return 0; err6: - DBG(0, "%s: Freeing dev %08x\n", __func__, (u32)isp1362_hcd); + DBG(0, "%s: Freeing dev %p\n", __func__, isp1362_hcd); usb_put_hcd(hcd); err5: - DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__, (u32)data_reg); + DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, data_reg); iounmap(data_reg); err4: DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)data->start); release_mem_region(data->start, resource_len(data)); err3: - DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__, (u32)addr_reg); + DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, addr_reg); iounmap(addr_reg); err2: DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)addr->start); diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h index fe60f62a32f3..1a253ebf7e50 100644 --- a/drivers/usb/host/isp1362.h +++ b/drivers/usb/host/isp1362.h @@ -580,7 +580,7 @@ static inline const char *ISP1362_INT_NAME(int n) static inline void ALIGNSTAT(struct isp1362_hcd *isp1362_hcd, void *ptr) { - unsigned p = (unsigned)ptr; + unsigned long p = (unsigned long)ptr; if (!(p & 0xf)) isp1362_hcd->stat16++; else if (!(p & 0x7)) @@ -770,7 +770,7 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l if (!len) return; - if ((unsigned)dp & 0x1) { + if ((unsigned long)dp & 0x1) { /* not aligned */ for (; len > 1; len -= 2) { data = *dp++; @@ -962,8 +962,8 @@ static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 isp1362_write_diraddr(isp1362_hcd, offset, len); - DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %08x\n", __func__, - len, offset, (u32)buf); + DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n", + __func__, len, offset, buf); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); @@ -982,8 +982,8 @@ static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 isp1362_write_diraddr(isp1362_hcd, offset, len); - DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %08x\n", __func__, - len, offset, (u32)buf); + DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n", + __func__, len, offset, buf); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); -- cgit v1.2.2 From d55500941fe6db4d7424c744522ee2451ac1ceda Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 6 Oct 2009 13:45:59 -0700 Subject: USB: ehci: Fix isoc scheduling boundary checking. The EHCI driver does some bounds checking when it's scheduling an iTD for an active endpoint. It sets the local variable start to stream->next_uframe and moves that variable further in the schedule if necessary. However, the driver fails to do anything with start before jumping to the ready label and setting the URB's starting frame to stream->next_uframe. Alan Stern confirms the EHCI driver should set stream->next_uframe to start before jumping. Signed-off-by: Sarah Sharp Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 3ea05936851f..3efa59b18044 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1425,6 +1425,7 @@ iso_stream_schedule ( status = -EFBIG; goto fail; } + stream->next_uframe = start; goto ready; } -- cgit v1.2.2 From d93a8f829fe1d2f3002f2c6ddb553d12db420412 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 11 Oct 2009 15:57:57 -0700 Subject: Revert "USB: Work around BIOS bugs by quiescing USB controllers earlier" This reverts commit db8be50c4307dac2b37305fc59c8dc0f978d09ea, as per http://bugzilla.kernel.org/show_bug.cgi?id=14374 http://marc.info/?l=linux-kernel&m=125446885705223&w=4 We simply can't do the USB handoff at FIXUP_HEADER time, since it will often require us to have valid IO mappings etc. But that in turn requires a whole different approach, not this trivial one-liner. Maybe we could teach all the USB quirk handoff handlers to only do the quirk if the device has all its registers set up (since if it isn't initialized, it's unlikely to be active), but regardless that will need a whole lot more code than just saying "let's do it really early". The proper fix is almost certainly to just leave the legacy IOMMU mappings active until after all devices have been initialized. Reported-by: Nick Piggin Cc: David Woodhouse Cc: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/host/pci-quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 23cf3bde4762..83b5f9cea85a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -475,4 +475,4 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) quirk_usb_handoff_xhci(pdev); } -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); -- cgit v1.2.2 From 171b37ee95865c052a88d52a05895c3c584f4871 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Mon, 12 Oct 2009 15:45:15 +0000 Subject: USB: whci-hcd: handle early deletion of endpoints If an endpoint is deleted before it's been fully added to the hardware list, the associated qset will not be fully initialized and an oops will occur when complete(&qset->remove_complete) is called. This can happen if a queued URB is cancelled. Fix this by only removing the qset from the hardware list if the cancelled URB had qTDs. Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/whci/asl.c | 19 ++++++++++++------- drivers/usb/host/whci/pzl.c | 20 +++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index c632437c7649..14ccbcfc4315 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -305,6 +305,7 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status) struct whc_urb *wurb = urb->hcpriv; struct whc_qset *qset = wurb->qset; struct whc_std *std, *t; + bool has_qtd = false; int ret; unsigned long flags; @@ -315,17 +316,21 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status) goto out; list_for_each_entry_safe(std, t, &qset->stds, list_node) { - if (std->urb == urb) + if (std->urb == urb) { + if (std->qtd) + has_qtd = true; qset_free_std(whc, std); - else + } else std->qtd = NULL; /* so this std is re-added when the qset is */ } - asl_qset_remove(whc, qset); - wurb->status = status; - wurb->is_async = true; - queue_work(whc->workqueue, &wurb->dequeue_work); - + if (has_qtd) { + asl_qset_remove(whc, qset); + wurb->status = status; + wurb->is_async = true; + queue_work(whc->workqueue, &wurb->dequeue_work); + } else + qset_remove_urb(whc, qset, urb, status); out: spin_unlock_irqrestore(&whc->lock, flags); diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index a9e05bac6646..e923633f30c1 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c @@ -333,6 +333,7 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status) struct whc_urb *wurb = urb->hcpriv; struct whc_qset *qset = wurb->qset; struct whc_std *std, *t; + bool has_qtd = false; int ret; unsigned long flags; @@ -343,17 +344,22 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status) goto out; list_for_each_entry_safe(std, t, &qset->stds, list_node) { - if (std->urb == urb) + if (std->urb == urb) { + if (std->qtd) + has_qtd = true; qset_free_std(whc, std); - else + } else std->qtd = NULL; /* so this std is re-added when the qset is */ } - pzl_qset_remove(whc, qset); - wurb->status = status; - wurb->is_async = false; - queue_work(whc->workqueue, &wurb->dequeue_work); - + if (has_qtd) { + pzl_qset_remove(whc, qset); + update_pzl_hw_view(whc); + wurb->status = status; + wurb->is_async = false; + queue_work(whc->workqueue, &wurb->dequeue_work); + } else + qset_remove_urb(whc, qset, urb, status); out: spin_unlock_irqrestore(&whc->lock, flags); -- cgit v1.2.2 From 1f01ca4e0c1d4126eb663f8ea0bab03836099770 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Mon, 12 Oct 2009 15:45:16 +0000 Subject: USB: whci-hcd: always do an update after processing a halted qTD A halted qTD always triggers a hardware list update because the qset was either removed or reactivated. Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/whci/asl.c | 4 ++++ drivers/usb/host/whci/pzl.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index 14ccbcfc4315..562eba108816 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -115,6 +115,10 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) if (status & QTD_STS_HALTED) { /* Ug, an error. */ process_halted_qtd(whc, qset, td); + /* A halted qTD always triggers an update + because the qset was either removed or + reactivated. */ + update |= WHC_UPDATE_UPDATED; goto done; } diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index e923633f30c1..0db3fb2dc03a 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c @@ -121,6 +121,10 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset) if (status & QTD_STS_HALTED) { /* Ug, an error. */ process_halted_qtd(whc, qset, td); + /* A halted qTD always triggers an update + because the qset was either removed or + reactivated. */ + update |= WHC_UPDATE_UPDATED; goto done; } -- cgit v1.2.2 From 36f21329d217016f0f212f0752ae595b4a76754d Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 9 Oct 2009 12:28:41 -0700 Subject: USB: ehci: Fix IST boundary checking interval math. When the EHCI driver falls behind in its scheduling, the active stream's first empty microframe may be in the past with respect to the current microframe. The code attempts to move the starting microframe ("start") N number of microframes forward, where N is the interval of endpoint. However, stream->interval is a copy of the endpoint's bInterval, which is designated in frames for FS devices, and microframes for HS devices. Convert stream->interval to microframes before using it to move the starting microframe forward. Acked-by: Alan Stern Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 3efa59b18044..b25cdea93a1f 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1400,6 +1400,10 @@ iso_stream_schedule ( goto fail; } + period = urb->interval; + if (!stream->highspeed) + period <<= 3; + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; /* when's the last uframe this urb could start? */ @@ -1417,8 +1421,8 @@ iso_stream_schedule ( /* Fell behind (by up to twice the slop amount)? */ if (start >= max - 2 * 8 * SCHEDULE_SLOP) - start += stream->interval * DIV_ROUND_UP( - max - start, stream->interval) - mod; + start += period * DIV_ROUND_UP( + max - start, period) - mod; /* Tried to schedule too far into the future? */ if (unlikely((start + sched->span) >= max)) { @@ -1441,10 +1445,6 @@ iso_stream_schedule ( /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ - period = urb->interval; - if (!stream->highspeed) - period <<= 3; - /* find a uframe slot with enough bandwidth */ for (; start < (stream->next_uframe + period); start++) { int enough_space; -- cgit v1.2.2 From 1e6159f858f5da608612ae10d6554bb7ecac9755 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 21 Oct 2009 20:33:39 +0900 Subject: USB: r8a66597-hcd: fix cannot detect a device when uses_new_polling is set Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/usb/host') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 749b53742828..e33d36256350 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -1003,19 +1003,20 @@ static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port, if (syssts == SE0) { r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port)); r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port)); - return; - } + } else { + if (syssts == FS_JSTS) + r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); + else if (syssts == LS_JSTS) + r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port)); - if (syssts == FS_JSTS) - r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); - else if (syssts == LS_JSTS) - r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port)); + r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); + r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port)); - r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); - r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port)); + if (r8a66597->bus_suspended) + usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597)); + } - if (r8a66597->bus_suspended) - usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597)); + usb_hcd_poll_rh_status(r8a66597_to_hcd(r8a66597)); } /* this function must be called with interrupt disabled */ @@ -1024,6 +1025,8 @@ static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port) u16 speed = get_rh_usb_speed(r8a66597, port); struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; + rh->port &= ~((1 << USB_PORT_FEAT_HIGHSPEED) | + (1 << USB_PORT_FEAT_LOWSPEED)); if (speed == HSMODE) rh->port |= (1 << USB_PORT_FEAT_HIGHSPEED); else if (speed == LSMODE) -- cgit v1.2.2