xhci: Refactor interrupter code for initial multi interrupter support.
[platform/kernel/linux-rpi.git] / drivers / usb / host / xhci.c
index f61fda4..8dc3f2c 100644 (file)
@@ -613,6 +613,7 @@ static int xhci_init(struct usb_hcd *hcd)
 
 static int xhci_run_finished(struct xhci_hcd *xhci)
 {
+       struct xhci_interrupter *ir = xhci->interrupter;
        unsigned long   flags;
        u32             temp;
 
@@ -628,8 +629,8 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
        writel(temp, &xhci->op_regs->command);
 
        xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Enable primary interrupter");
-       temp = readl(&xhci->ir_set->irq_pending);
-       writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
+       temp = readl(&ir->ir_set->irq_pending);
+       writel(ER_IRQ_ENABLE(temp), &ir->ir_set->irq_pending);
 
        if (xhci_start(xhci)) {
                xhci_halt(xhci);
@@ -665,7 +666,7 @@ int xhci_run(struct usb_hcd *hcd)
        u64 temp_64;
        int ret;
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-
+       struct xhci_interrupter *ir = xhci->interrupter;
        /* Start the xHCI host controller running only after the USB 2.0 roothub
         * is setup.
         */
@@ -680,17 +681,17 @@ int xhci_run(struct usb_hcd *hcd)
        if (ret)
                return ret;
 
-       temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+       temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
        temp_64 &= ~ERST_PTR_MASK;
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "ERST deq = 64'h%0lx", (long unsigned int) temp_64);
 
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "// Set the interrupt modulation register");
-       temp = readl(&xhci->ir_set->irq_control);
+       temp = readl(&ir->ir_set->irq_control);
        temp &= ~ER_IRQ_INTERVAL_MASK;
        temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
-       writel(temp, &xhci->ir_set->irq_control);
+       writel(temp, &ir->ir_set->irq_control);
 
        if (xhci->quirks & XHCI_NEC_HOST) {
                struct xhci_command *command;
@@ -769,8 +770,8 @@ static void xhci_stop(struct usb_hcd *hcd)
                        "// Disabling event ring interrupts");
        temp = readl(&xhci->op_regs->status);
        writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
-       temp = readl(&xhci->ir_set->irq_pending);
-       writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
+       temp = readl(&xhci->interrupter->ir_set->irq_pending);
+       writel(ER_IRQ_DISABLE(temp), &xhci->interrupter->ir_set->irq_pending);
 
        xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
        xhci_mem_cleanup(xhci);
@@ -832,28 +833,36 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
 #ifdef CONFIG_PM
 static void xhci_save_registers(struct xhci_hcd *xhci)
 {
+       struct xhci_interrupter *ir = xhci->interrupter;
+
        xhci->s3.command = readl(&xhci->op_regs->command);
        xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
        xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
        xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
-       xhci->s3.erst_size = readl(&xhci->ir_set->erst_size);
-       xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
-       xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
-       xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending);
-       xhci->s3.irq_control = readl(&xhci->ir_set->irq_control);
+
+       if (!ir)
+               return;
+
+       ir->s3_erst_size = readl(&ir->ir_set->erst_size);
+       ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+       ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+       ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
+       ir->s3_irq_control = readl(&ir->ir_set->irq_control);
 }
 
 static void xhci_restore_registers(struct xhci_hcd *xhci)
 {
+       struct xhci_interrupter *ir = xhci->interrupter;
+
        writel(xhci->s3.command, &xhci->op_regs->command);
        writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
        xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
        writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
-       writel(xhci->s3.erst_size, &xhci->ir_set->erst_size);
-       xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
-       xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
-       writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
-       writel(xhci->s3.irq_control, &xhci->ir_set->irq_control);
+       writel(ir->s3_erst_size, &ir->ir_set->erst_size);
+       xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
+       xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
+       writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
+       writel(ir->s3_irq_control, &ir->ir_set->irq_control);
 }
 
 static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
@@ -1218,8 +1227,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                xhci_dbg(xhci, "// Disabling event ring interrupts\n");
                temp = readl(&xhci->op_regs->status);
                writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
-               temp = readl(&xhci->ir_set->irq_pending);
-               writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
+               temp = readl(&xhci->interrupter->ir_set->irq_pending);
+               writel(ER_IRQ_DISABLE(temp), &xhci->interrupter->ir_set->irq_pending);
 
                xhci_dbg(xhci, "cleaning up memory\n");
                xhci_mem_cleanup(xhci);
@@ -5334,6 +5343,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        if (xhci->hci_version > 0x100)
                xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
 
+       /* xhci-plat or xhci-pci might have set max_interrupters already */
+       if ((!xhci->max_interrupters) ||
+           xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1))
+               xhci->max_interrupters = HCS_MAX_INTRS(xhci->hcs_params1);
+
        xhci->quirks |= quirks;
 
        get_quirks(dev, xhci);