diff options
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 49 |
1 files changed, 44 insertions, 5 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 6fcffe15a005..ac0f7a4b0341 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/dma-mapping.h> | 36 | #include <linux/dma-mapping.h> |
37 | #include <linux/debugfs.h> | 37 | #include <linux/debugfs.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/uaccess.h> | ||
39 | 40 | ||
40 | #include <asm/byteorder.h> | 41 | #include <asm/byteorder.h> |
41 | #include <asm/io.h> | 42 | #include <asm/io.h> |
@@ -78,7 +79,13 @@ static const char hcd_name [] = "ehci_hcd"; | |||
78 | #define EHCI_TUNE_RL_TT 0 | 79 | #define EHCI_TUNE_RL_TT 0 |
79 | #define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ | 80 | #define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ |
80 | #define EHCI_TUNE_MULT_TT 1 | 81 | #define EHCI_TUNE_MULT_TT 1 |
81 | #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ | 82 | /* |
83 | * Some drivers think it's safe to schedule isochronous transfers more than | ||
84 | * 256 ms into the future (partly as a result of an old bug in the scheduling | ||
85 | * code). In an attempt to avoid trouble, we will use a minimum scheduling | ||
86 | * length of 512 frames instead of 256. | ||
87 | */ | ||
88 | #define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ | ||
82 | 89 | ||
83 | #define EHCI_IAA_MSECS 10 /* arbitrary */ | 90 | #define EHCI_IAA_MSECS 10 /* arbitrary */ |
84 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ | 91 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ |
@@ -100,6 +107,11 @@ static int ignore_oc = 0; | |||
100 | module_param (ignore_oc, bool, S_IRUGO); | 107 | module_param (ignore_oc, bool, S_IRUGO); |
101 | MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); | 108 | MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); |
102 | 109 | ||
110 | /* for link power management(LPM) feature */ | ||
111 | static unsigned int hird; | ||
112 | module_param(hird, int, S_IRUGO); | ||
113 | MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n"); | ||
114 | |||
103 | #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) | 115 | #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) |
104 | 116 | ||
105 | /*-------------------------------------------------------------------------*/ | 117 | /*-------------------------------------------------------------------------*/ |
@@ -304,6 +316,7 @@ static void end_unlink_async(struct ehci_hcd *ehci); | |||
304 | static void ehci_work(struct ehci_hcd *ehci); | 316 | static void ehci_work(struct ehci_hcd *ehci); |
305 | 317 | ||
306 | #include "ehci-hub.c" | 318 | #include "ehci-hub.c" |
319 | #include "ehci-lpm.c" | ||
307 | #include "ehci-mem.c" | 320 | #include "ehci-mem.c" |
308 | #include "ehci-q.c" | 321 | #include "ehci-q.c" |
309 | #include "ehci-sched.c" | 322 | #include "ehci-sched.c" |
@@ -577,6 +590,11 @@ static int ehci_init(struct usb_hcd *hcd) | |||
577 | if (log2_irq_thresh < 0 || log2_irq_thresh > 6) | 590 | if (log2_irq_thresh < 0 || log2_irq_thresh > 6) |
578 | log2_irq_thresh = 0; | 591 | log2_irq_thresh = 0; |
579 | temp = 1 << (16 + log2_irq_thresh); | 592 | temp = 1 << (16 + log2_irq_thresh); |
593 | if (HCC_PER_PORT_CHANGE_EVENT(hcc_params)) { | ||
594 | ehci->has_ppcd = 1; | ||
595 | ehci_dbg(ehci, "enable per-port change event\n"); | ||
596 | temp |= CMD_PPCEE; | ||
597 | } | ||
580 | if (HCC_CANPARK(hcc_params)) { | 598 | if (HCC_CANPARK(hcc_params)) { |
581 | /* HW default park == 3, on hardware that supports it (like | 599 | /* HW default park == 3, on hardware that supports it (like |
582 | * NVidia and ALI silicon), maximizes throughput on the async | 600 | * NVidia and ALI silicon), maximizes throughput on the async |
@@ -603,10 +621,22 @@ static int ehci_init(struct usb_hcd *hcd) | |||
603 | default: BUG(); | 621 | default: BUG(); |
604 | } | 622 | } |
605 | } | 623 | } |
624 | if (HCC_LPM(hcc_params)) { | ||
625 | /* support link power management EHCI 1.1 addendum */ | ||
626 | ehci_dbg(ehci, "support lpm\n"); | ||
627 | ehci->has_lpm = 1; | ||
628 | if (hird > 0xf) { | ||
629 | ehci_dbg(ehci, "hird %d invalid, use default 0", | ||
630 | hird); | ||
631 | hird = 0; | ||
632 | } | ||
633 | temp |= hird << 24; | ||
634 | } | ||
606 | ehci->command = temp; | 635 | ehci->command = temp; |
607 | 636 | ||
608 | /* Accept arbitrarily long scatter-gather lists */ | 637 | /* Accept arbitrarily long scatter-gather lists */ |
609 | hcd->self.sg_tablesize = ~0; | 638 | if (!(hcd->driver->flags & HCD_LOCAL_MEM)) |
639 | hcd->self.sg_tablesize = ~0; | ||
610 | return 0; | 640 | return 0; |
611 | } | 641 | } |
612 | 642 | ||
@@ -619,7 +649,6 @@ static int ehci_run (struct usb_hcd *hcd) | |||
619 | u32 hcc_params; | 649 | u32 hcc_params; |
620 | 650 | ||
621 | hcd->uses_new_polling = 1; | 651 | hcd->uses_new_polling = 1; |
622 | hcd->poll_rh = 0; | ||
623 | 652 | ||
624 | /* EHCI spec section 4.1 */ | 653 | /* EHCI spec section 4.1 */ |
625 | if ((retval = ehci_reset(ehci)) != 0) { | 654 | if ((retval = ehci_reset(ehci)) != 0) { |
@@ -764,6 +793,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
764 | /* remote wakeup [4.3.1] */ | 793 | /* remote wakeup [4.3.1] */ |
765 | if (status & STS_PCD) { | 794 | if (status & STS_PCD) { |
766 | unsigned i = HCS_N_PORTS (ehci->hcs_params); | 795 | unsigned i = HCS_N_PORTS (ehci->hcs_params); |
796 | u32 ppcd = 0; | ||
767 | 797 | ||
768 | /* kick root hub later */ | 798 | /* kick root hub later */ |
769 | pcd_status = status; | 799 | pcd_status = status; |
@@ -772,9 +802,18 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
772 | if (!(cmd & CMD_RUN)) | 802 | if (!(cmd & CMD_RUN)) |
773 | usb_hcd_resume_root_hub(hcd); | 803 | usb_hcd_resume_root_hub(hcd); |
774 | 804 | ||
805 | /* get per-port change detect bits */ | ||
806 | if (ehci->has_ppcd) | ||
807 | ppcd = status >> 16; | ||
808 | |||
775 | while (i--) { | 809 | while (i--) { |
776 | int pstatus = ehci_readl(ehci, | 810 | int pstatus; |
777 | &ehci->regs->port_status [i]); | 811 | |
812 | /* leverage per-port change bits feature */ | ||
813 | if (ehci->has_ppcd && !(ppcd & (1 << i))) | ||
814 | continue; | ||
815 | pstatus = ehci_readl(ehci, | ||
816 | &ehci->regs->port_status[i]); | ||
778 | 817 | ||
779 | if (pstatus & PORT_OWNER) | 818 | if (pstatus & PORT_OWNER) |
780 | continue; | 819 | continue; |