Loading drivers/usb/host/xhci-mem.c +76 −24 Original line number Diff line number Diff line Loading @@ -1789,27 +1789,17 @@ void xhci_free_command(struct xhci_hcd *xhci, kfree(command); } int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) void xhci_handle_sec_intr_events(struct xhci_hcd *xhci, int intr_num) { int size; u32 iman_reg; union xhci_trb *erdp_trb, *current_trb; struct xhci_segment *seg; u64 erdp_reg; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct device *dev = xhci_to_hcd(xhci)->self.controller; u32 iman_reg; dma_addr_t deq; unsigned long segment_offset; if (intr_num > xhci->max_interrupters) { xhci_err(xhci, "invalid secondary interrupter num %d\n", intr_num); return -EINVAL; } /* disable irq, ack pending interrupt and ack all pending events */ size = sizeof(struct xhci_erst_entry)*(xhci->sec_erst[intr_num].num_entries); if (xhci->sec_erst[intr_num].entries) { /* * disable irq, ack pending interrupt and clear EHB for xHC to * generate interrupt again when new event ring is setup */ iman_reg = readl_relaxed(&xhci->sec_ir_set[intr_num]->irq_pending); iman_reg &= ~IMAN_IE; Loading @@ -1820,14 +1810,76 @@ int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) if (iman_reg & IMAN_IP) writel_relaxed(iman_reg, &xhci->sec_ir_set[intr_num]->irq_pending); /* make sure IP gets cleared before clearing EHB */ mb(); erdp_reg = xhci_read_64(xhci, &xhci->sec_ir_set[intr_num]->erst_dequeue); xhci_write_64(xhci, erdp_reg | ERST_EHB, /* last acked event trb is in erdp reg */ erdp_reg = xhci_read_64(xhci, &xhci->sec_ir_set[intr_num]->erst_dequeue); deq = (dma_addr_t)(erdp_reg & ~ERST_PTR_MASK); if (!deq) { pr_debug("%s: event ring handling not required\n", __func__); return; } seg = xhci->sec_event_ring[intr_num]->first_seg; segment_offset = deq - seg->dma; /* find out virtual address of the last acked event trb */ erdp_trb = current_trb = &seg->trbs[0] + (segment_offset/sizeof(*current_trb)); /* read cycle state of the last acked trb to find out CCS */ xhci->sec_event_ring[intr_num]->cycle_state = (current_trb->event_cmd.flags & TRB_CYCLE); while (1) { /* last trb of the event ring: toggle cycle state */ if (current_trb == &seg->trbs[TRBS_PER_SEGMENT - 1]) { xhci->sec_event_ring[intr_num]->cycle_state ^= 1; current_trb = &seg->trbs[0]; } else { current_trb++; } /* cycle state transition */ if ((le32_to_cpu(current_trb->event_cmd.flags) & TRB_CYCLE) != xhci->sec_event_ring[intr_num]->cycle_state) break; } if (erdp_trb != current_trb) { deq = xhci_trb_virt_to_dma(xhci->sec_event_ring[intr_num]->deq_seg, current_trb); if (deq == 0) xhci_warn(xhci, "WARN ivalid SW event ring dequeue ptr.\n"); /* Update HC event ring dequeue pointer */ erdp_reg &= ERST_PTR_MASK; erdp_reg |= ((u64) deq & (u64) ~ERST_PTR_MASK); } /* Clear the event handler busy flag (RW1C); event ring is empty. */ erdp_reg |= ERST_EHB; xhci_write_64(xhci, erdp_reg, &xhci->sec_ir_set[intr_num]->erst_dequeue); } int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) { int size; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct device *dev = xhci_to_hcd(xhci)->self.controller; if (intr_num > xhci->max_interrupters) { xhci_err(xhci, "invalid secondary interrupter num %d\n", intr_num); return -EINVAL; } size = sizeof(struct xhci_erst_entry)*(xhci->sec_erst[intr_num].num_entries); if (xhci->sec_erst[intr_num].entries) { xhci_handle_sec_intr_events(xhci, intr_num); dma_free_coherent(dev, size, xhci->sec_erst[intr_num].entries, xhci->sec_erst[intr_num].erst_dma_addr); xhci->sec_erst[intr_num].entries = NULL; Loading drivers/usb/host/xhci-plat.c +2 −2 Original line number Diff line number Diff line Loading @@ -336,7 +336,7 @@ static int xhci_plat_runtime_suspend(struct device *dev) dev_dbg(dev, "xhci-plat runtime suspend\n"); return 0; return xhci_suspend(xhci, true); } static int xhci_plat_runtime_resume(struct device *dev) Loading @@ -350,7 +350,7 @@ static int xhci_plat_runtime_resume(struct device *dev) dev_dbg(dev, "xhci-plat runtime resume\n"); ret = 0; ret = xhci_resume(xhci, false); pm_runtime_mark_last_busy(dev); return ret; Loading Loading
drivers/usb/host/xhci-mem.c +76 −24 Original line number Diff line number Diff line Loading @@ -1789,27 +1789,17 @@ void xhci_free_command(struct xhci_hcd *xhci, kfree(command); } int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) void xhci_handle_sec_intr_events(struct xhci_hcd *xhci, int intr_num) { int size; u32 iman_reg; union xhci_trb *erdp_trb, *current_trb; struct xhci_segment *seg; u64 erdp_reg; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct device *dev = xhci_to_hcd(xhci)->self.controller; u32 iman_reg; dma_addr_t deq; unsigned long segment_offset; if (intr_num > xhci->max_interrupters) { xhci_err(xhci, "invalid secondary interrupter num %d\n", intr_num); return -EINVAL; } /* disable irq, ack pending interrupt and ack all pending events */ size = sizeof(struct xhci_erst_entry)*(xhci->sec_erst[intr_num].num_entries); if (xhci->sec_erst[intr_num].entries) { /* * disable irq, ack pending interrupt and clear EHB for xHC to * generate interrupt again when new event ring is setup */ iman_reg = readl_relaxed(&xhci->sec_ir_set[intr_num]->irq_pending); iman_reg &= ~IMAN_IE; Loading @@ -1820,14 +1810,76 @@ int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) if (iman_reg & IMAN_IP) writel_relaxed(iman_reg, &xhci->sec_ir_set[intr_num]->irq_pending); /* make sure IP gets cleared before clearing EHB */ mb(); erdp_reg = xhci_read_64(xhci, &xhci->sec_ir_set[intr_num]->erst_dequeue); xhci_write_64(xhci, erdp_reg | ERST_EHB, /* last acked event trb is in erdp reg */ erdp_reg = xhci_read_64(xhci, &xhci->sec_ir_set[intr_num]->erst_dequeue); deq = (dma_addr_t)(erdp_reg & ~ERST_PTR_MASK); if (!deq) { pr_debug("%s: event ring handling not required\n", __func__); return; } seg = xhci->sec_event_ring[intr_num]->first_seg; segment_offset = deq - seg->dma; /* find out virtual address of the last acked event trb */ erdp_trb = current_trb = &seg->trbs[0] + (segment_offset/sizeof(*current_trb)); /* read cycle state of the last acked trb to find out CCS */ xhci->sec_event_ring[intr_num]->cycle_state = (current_trb->event_cmd.flags & TRB_CYCLE); while (1) { /* last trb of the event ring: toggle cycle state */ if (current_trb == &seg->trbs[TRBS_PER_SEGMENT - 1]) { xhci->sec_event_ring[intr_num]->cycle_state ^= 1; current_trb = &seg->trbs[0]; } else { current_trb++; } /* cycle state transition */ if ((le32_to_cpu(current_trb->event_cmd.flags) & TRB_CYCLE) != xhci->sec_event_ring[intr_num]->cycle_state) break; } if (erdp_trb != current_trb) { deq = xhci_trb_virt_to_dma(xhci->sec_event_ring[intr_num]->deq_seg, current_trb); if (deq == 0) xhci_warn(xhci, "WARN ivalid SW event ring dequeue ptr.\n"); /* Update HC event ring dequeue pointer */ erdp_reg &= ERST_PTR_MASK; erdp_reg |= ((u64) deq & (u64) ~ERST_PTR_MASK); } /* Clear the event handler busy flag (RW1C); event ring is empty. */ erdp_reg |= ERST_EHB; xhci_write_64(xhci, erdp_reg, &xhci->sec_ir_set[intr_num]->erst_dequeue); } int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) { int size; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct device *dev = xhci_to_hcd(xhci)->self.controller; if (intr_num > xhci->max_interrupters) { xhci_err(xhci, "invalid secondary interrupter num %d\n", intr_num); return -EINVAL; } size = sizeof(struct xhci_erst_entry)*(xhci->sec_erst[intr_num].num_entries); if (xhci->sec_erst[intr_num].entries) { xhci_handle_sec_intr_events(xhci, intr_num); dma_free_coherent(dev, size, xhci->sec_erst[intr_num].entries, xhci->sec_erst[intr_num].erst_dma_addr); xhci->sec_erst[intr_num].entries = NULL; Loading
drivers/usb/host/xhci-plat.c +2 −2 Original line number Diff line number Diff line Loading @@ -336,7 +336,7 @@ static int xhci_plat_runtime_suspend(struct device *dev) dev_dbg(dev, "xhci-plat runtime suspend\n"); return 0; return xhci_suspend(xhci, true); } static int xhci_plat_runtime_resume(struct device *dev) Loading @@ -350,7 +350,7 @@ static int xhci_plat_runtime_resume(struct device *dev) dev_dbg(dev, "xhci-plat runtime resume\n"); ret = 0; ret = xhci_resume(xhci, false); pm_runtime_mark_last_busy(dev); return ret; Loading