diff options
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 74 |
1 files changed, 60 insertions, 14 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 423bf3649570..e038ad3375dc 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1898,6 +1898,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, case TRB_NEC_GET_FW: xhci_handle_cmd_nec_get_fw(xhci, event); break; + case TRB_GET_BW: + break; default: /* Skip over unknown commands on the event ring */ xhci_info(xhci, "INFO unknown command type %d\n", cmd_type); @@ -2977,9 +2979,6 @@ debug_finding_td: (unsigned long long)xhci_trb_virt_to_dma(td->start_seg, td->start_trb), (unsigned long long)xhci_trb_virt_to_dma(td->end_seg, td->end_trb)); - xhci_for_each_ring_seg(ep_ring->first_seg, ep_seg) - xhci_warn(xhci, "Ring seg %u dma %pad\n", ep_seg->num, &ep_seg->dma); - return -ESHUTDOWN; err_out: @@ -3050,9 +3049,9 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter * - When all events have finished * - To avoid "Event Ring Full Error" condition */ -static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, - struct xhci_interrupter *ir, - bool clear_ehb) +void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + struct xhci_interrupter *ir, + bool clear_ehb) { u64 temp_64; dma_addr_t deq; @@ -3083,11 +3082,14 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir) { if (!ir->ip_autoclear) { - u32 irq_pending; + u32 iman; + + iman = readl(&ir->ir_set->iman); + iman |= IMAN_IP; + writel(iman, &ir->ir_set->iman); - irq_pending = readl(&ir->ir_set->irq_pending); - irq_pending |= IMAN_IP; - writel(irq_pending, &ir->ir_set->irq_pending); + /* Read operation to guarantee the write has been flushed from posted buffers */ + readl(&ir->ir_set->iman); } } @@ -3095,10 +3097,11 @@ static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir) * Handle all OS-owned events on an interrupter event ring. It may drop * and reaquire xhci->lock between event processing. */ -static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir) +static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir, + bool skip_events) { int event_loop = 0; - int err; + int err = 0; u64 temp; xhci_clear_interrupt_pending(ir); @@ -3121,7 +3124,8 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir /* Process all OS owned event TRBs on this event ring */ while (unhandled_event_trb(ir->event_ring)) { - err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue); + if (!skip_events) + err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue); /* * If half a segment of events have been handled in one go then @@ -3149,6 +3153,37 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir } /* + * Move the event ring dequeue pointer to skip events kept in the secondary + * event ring. This is used to ensure that pending events in the ring are + * acknowledged, so the xHCI HCD can properly enter suspend/resume. The + * secondary ring is typically maintained by an external component. + */ +void xhci_skip_sec_intr_events(struct xhci_hcd *xhci, + struct xhci_ring *ring, struct xhci_interrupter *ir) +{ + union xhci_trb *current_trb; + u64 erdp_reg; + dma_addr_t deq; + + /* disable irq, ack pending interrupt and ack all pending events */ + xhci_disable_interrupter(xhci, ir); + + /* last acked event trb is in erdp reg */ + erdp_reg = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); + deq = (dma_addr_t)(erdp_reg & ERST_PTR_MASK); + if (!deq) { + xhci_err(xhci, "event ring handling not required\n"); + return; + } + + current_trb = ir->event_ring->dequeue; + /* read cycle state of the last acked trb to find out CCS */ + ring->cycle_state = le32_to_cpu(current_trb->event_cmd.flags) & TRB_CYCLE; + + xhci_handle_events(xhci, ir, true); +} + +/* * xHCI spec says we can get an interrupt, and if the HC has an error condition, * we might get bad data out of the event ring. Section 4.10.2.7 has a list of * indicators of an event TRB error, but we check the status *first* to be safe. @@ -3192,7 +3227,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) writel(status, &xhci->op_regs->status); /* This is the handler of the primary interrupter */ - xhci_handle_events(xhci, xhci->interrupters[0]); + xhci_handle_events(xhci, xhci->interrupters[0], false); out: spin_unlock(&xhci->lock); @@ -4414,6 +4449,17 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, command_must_succeed); } +/* Queue a get root hub port bandwidth command TRB */ +int xhci_queue_get_port_bw(struct xhci_hcd *xhci, + struct xhci_command *cmd, dma_addr_t in_ctx_ptr, + u8 dev_speed, bool command_must_succeed) +{ + return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr), + upper_32_bits(in_ctx_ptr), 0, + TRB_TYPE(TRB_GET_BW) | DEV_SPEED_FOR_TRB(dev_speed), + command_must_succeed); +} + /* Queue an evaluate context command TRB */ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed) |