diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-26 08:08:32 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-26 08:08:32 +0200 |
commit | f549953c15deab4c54708b39af86d4edecc6cddc (patch) | |
tree | f0412f989b77cdceab34c18aa85a8a25d5942a1f /drivers/usb/host | |
parent | Merge branch 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/... (diff) | |
parent | EHCI: fix direction handling for interrupt data toggles (diff) | |
download | linux-f549953c15deab4c54708b39af86d4edecc6cddc.tar.xz linux-f549953c15deab4c54708b39af86d4edecc6cddc.zip |
Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (115 commits)
EHCI: fix direction handling for interrupt data toggles
USB: serial: add IDs for WinChipHead USB->RS232 adapter
USB: OHCI: fix another regression for NVIDIA controllers
usb: gadget: m66592-udc: add pullup function
usb: gadget: m66592-udc: add function for external controller
usb: gadget: r8a66597-udc: add pullup function
usb: renesas_usbhs: support multi driver
usb: renesas_usbhs: inaccessible pipe is not an error
usb: renesas_usbhs: care buff alignment when dma handler
USB: PL2303: correctly handle baudrates above 115200
usb: r8a66597-hcd: fixup USB_PORT_STAT_C_SUSPEND shift
usb: renesas_usbhs: compile/config are rescued
usb: renesas_usbhs: fixup comment-out
usb: update email address in ohci-sh and r8a66597-hcd
usb: r8a66597-hcd: add function for external controller
EHCI: only power off port if over-current is active
USB: mon: Allow to use usbmon without debugfs
USB: EHCI: go back to using the system clock for QH unlinks
ehci: add pci quirk for Ordissimo and RM Slate 100 too
ehci: refactor pci quirk to use standard dmi_check_system method
...
Fix up trivial conflicts in Documentation/feature-removal-schedule.txt
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 21 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 78 | ||||
-rw-r--r-- | drivers/usb/host/ehci-msm.c | 20 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 85 | ||||
-rw-r--r-- | drivers/usb/host/ehci-s5p.c | 95 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 17 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sysfs.c | 190 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 6 | ||||
-rw-r--r-- | drivers/usb/host/ohci-sh.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 56 | ||||
-rw-r--r-- | drivers/usb/host/r8a66597-hcd.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/r8a66597.h | 38 | ||||
-rw-r--r-- | drivers/usb/host/xhci-dbg.c | 22 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 26 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 42 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 10 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 7 |
17 files changed, 481 insertions, 240 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index f8030ee928e8..f72ae0b6ee7f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -94,7 +94,8 @@ static const char hcd_name [] = "ehci_hcd"; #define EHCI_IAA_MSECS 10 /* arbitrary */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ -#define EHCI_SHRINK_FRAMES 5 /* async qh unlink delay */ +#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) + /* 200-ms async qh unlink delay */ /* Initial IRQ latency: faster than hw default */ static int log2_irq_thresh = 0; // 0 to 6 @@ -114,7 +115,7 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); /* for link power management(LPM) feature */ static unsigned int hird; module_param(hird, int, S_IRUGO); -MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n"); +MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) @@ -152,10 +153,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action) break; /* case TIMER_ASYNC_SHRINK: */ default: - /* add a jiffie since we synch against the - * 8 KHz uframe counter. - */ - t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1; + t = EHCI_SHRINK_JIFFIES; break; } mod_timer(&ehci->watchdog, t + jiffies); @@ -340,6 +338,7 @@ static void ehci_work(struct ehci_hcd *ehci); #include "ehci-mem.c" #include "ehci-q.c" #include "ehci-sched.c" +#include "ehci-sysfs.c" /*-------------------------------------------------------------------------*/ @@ -524,7 +523,7 @@ static void ehci_stop (struct usb_hcd *hcd) ehci_reset (ehci); spin_unlock_irq(&ehci->lock); - remove_companion_file(ehci); + remove_sysfs_files(ehci); remove_debug_files (ehci); /* root hub is shut down separately (first, when possible) */ @@ -575,6 +574,12 @@ static int ehci_init(struct usb_hcd *hcd) hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); /* + * by default set standard 80% (== 100 usec/uframe) max periodic + * bandwidth as required by USB 2.0 + */ + ehci->uframe_periodic_max = 100; + + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. */ @@ -758,7 +763,7 @@ static int ehci_run (struct usb_hcd *hcd) * since the class device isn't created that early. */ create_debug_files(ehci); - create_companion_file(ehci); + create_sysfs_files(ehci); return 0; } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index ea6184bf48d0..bf2c8f65e1ae 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -471,29 +471,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -/* Display the ports dedicated to the companion controller */ -static ssize_t show_companion(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ehci_hcd *ehci; - int nports, index, n; - int count = PAGE_SIZE; - char *ptr = buf; - - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); - nports = HCS_N_PORTS(ehci->hcs_params); - - for (index = 0; index < nports; ++index) { - if (test_bit(index, &ehci->companion_ports)) { - n = scnprintf(ptr, count, "%d\n", index + 1); - ptr += n; - count -= n; - } - } - return ptr - buf; -} - /* * Sets the owner of a port */ @@ -528,58 +505,6 @@ static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner) } } -/* - * Dedicate or undedicate a port to the companion controller. - * Syntax is "[-]portnum", where a leading '-' sign means - * return control of the port to the EHCI controller. - */ -static ssize_t store_companion(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ehci_hcd *ehci; - int portnum, new_owner; - - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); - new_owner = PORT_OWNER; /* Owned by companion */ - if (sscanf(buf, "%d", &portnum) != 1) - return -EINVAL; - if (portnum < 0) { - portnum = - portnum; - new_owner = 0; /* Owned by EHCI */ - } - if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) - return -ENOENT; - portnum--; - if (new_owner) - set_bit(portnum, &ehci->companion_ports); - else - clear_bit(portnum, &ehci->companion_ports); - set_owner(ehci, portnum, new_owner); - return count; -} -static DEVICE_ATTR(companion, 0644, show_companion, store_companion); - -static inline int create_companion_file(struct ehci_hcd *ehci) -{ - int i = 0; - - /* with integrated TT there is no companion! */ - if (!ehci_is_TDI(ehci)) - i = device_create_file(ehci_to_hcd(ehci)->self.controller, - &dev_attr_companion); - return i; -} - -static inline void remove_companion_file(struct ehci_hcd *ehci) -{ - /* with integrated TT there is no companion! */ - if (!ehci_is_TDI(ehci)) - device_remove_file(ehci_to_hcd(ehci)->self.controller, - &dev_attr_companion); -} - - /*-------------------------------------------------------------------------*/ static int check_reset_complete ( @@ -891,10 +816,11 @@ static int ehci_hub_control ( * power switching; they're allowed to just limit the * current. khubd will turn the power back on. */ - if (HCS_PPC (ehci->hcs_params)){ + if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) { ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_POWER), status_reg); + temp = ehci_readl(ehci, status_reg); } } diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index b5a0bf649c95..592d5f76803e 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -40,27 +40,9 @@ static int ehci_msm_reset(struct usb_hcd *hcd) int retval; ehci->caps = USB_CAPLENGTH; - ehci->regs = USB_CAPLENGTH + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache the data to minimize the chip reads*/ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - hcd->has_tt = 1; - ehci->sbrn = HCD_USB2; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - retval = ehci_reset(ehci); + retval = ehci_setup(hcd); if (retval) return retval; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 5d6bc624c961..0917e3a32465 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { unsigned is_out, epnum; - is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); + is_out = qh->is_out; epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); @@ -946,6 +946,7 @@ done: hw = qh->hw; hw->hw_info1 = cpu_to_hc32(ehci, info1); hw->hw_info2 = cpu_to_hc32(ehci, info2); + qh->is_out = !is_input; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); qh_refresh (ehci, qh); return qh; @@ -1231,6 +1232,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) prev->hw->hw_next = qh->hw->hw_next; prev->qh_next = qh->qh_next; + if (ehci->qh_scan_next == qh) + ehci->qh_scan_next = qh->qh_next.qh; wmb (); /* If the controller isn't running, we don't have to wait for it */ @@ -1256,53 +1259,49 @@ static void scan_async (struct ehci_hcd *ehci) struct ehci_qh *qh; enum ehci_timer_action action = TIMER_IO_WATCHDOG; - ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index); timer_action_done (ehci, TIMER_ASYNC_SHRINK); -rescan: stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state); - qh = ehci->async->qh_next.qh; - if (likely (qh != NULL)) { - do { - /* clean any finished work for this qh */ - if (!list_empty(&qh->qtd_list) && (stopped || - qh->stamp != ehci->stamp)) { - int temp; - - /* unlinks could happen here; completion - * reporting drops the lock. rescan using - * the latest schedule, but don't rescan - * qhs we already finished (no looping) - * unless the controller is stopped. - */ - qh = qh_get (qh); - qh->stamp = ehci->stamp; - temp = qh_completions (ehci, qh); - if (qh->needs_rescan) - unlink_async(ehci, qh); - qh_put (qh); - if (temp != 0) { - goto rescan; - } - } - /* unlink idle entries, reducing DMA usage as well - * as HCD schedule-scanning costs. delay for any qh - * we just scanned, there's a not-unusual case that it - * doesn't stay idle for long. - * (plus, avoids some kind of re-activation race.) + ehci->qh_scan_next = ehci->async->qh_next.qh; + while (ehci->qh_scan_next) { + qh = ehci->qh_scan_next; + ehci->qh_scan_next = qh->qh_next.qh; + rescan: + /* clean any finished work for this qh */ + if (!list_empty(&qh->qtd_list)) { + int temp; + + /* + * Unlinks could happen here; completion reporting + * drops the lock. That's why ehci->qh_scan_next + * always holds the next qh to scan; if the next qh + * gets unlinked then ehci->qh_scan_next is adjusted + * in start_unlink_async(). */ - if (list_empty(&qh->qtd_list) - && qh->qh_state == QH_STATE_LINKED) { - if (!ehci->reclaim && (stopped || - ((ehci->stamp - qh->stamp) & 0x1fff) - >= EHCI_SHRINK_FRAMES * 8)) - start_unlink_async(ehci, qh); - else - action = TIMER_ASYNC_SHRINK; - } + qh = qh_get(qh); + temp = qh_completions(ehci, qh); + if (qh->needs_rescan) + unlink_async(ehci, qh); + qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES; + qh_put(qh); + if (temp != 0) + goto rescan; + } - qh = qh->qh_next.qh; - } while (qh); + /* unlink idle entries, reducing DMA usage as well + * as HCD schedule-scanning costs. delay for any qh + * we just scanned, there's a not-unusual case that it + * doesn't stay idle for long. + * (plus, avoids some kind of re-activation race.) + */ + if (list_empty(&qh->qtd_list) + && qh->qh_state == QH_STATE_LINKED) { + if (!ehci->reclaim && (stopped || + time_after_eq(jiffies, qh->unlink_time))) + start_unlink_async(ehci, qh); + else + action = TIMER_ASYNC_SHRINK; + } } if (action == TIMER_ASYNC_SHRINK) timer_action (ehci, TIMER_ASYNC_SHRINK); diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index e3374c8f7b3f..b3958b3d3163 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -189,6 +189,100 @@ static void s5p_ehci_shutdown(struct platform_device *pdev) hcd->driver->shutdown(hcd); } +#ifdef CONFIG_PM +static int s5p_ehci_suspend(struct device *dev) +{ + struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); + struct usb_hcd *hcd = s5p_ehci->hcd; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct platform_device *pdev = to_platform_device(dev); + struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; + unsigned long flags; + int rc = 0; + + if (time_before(jiffies, ehci->next_statechange)) + msleep(20); + + /* + * Root hub was already suspended. Disable irq emission and + * mark HW unaccessible. The PM and USB cores make sure that + * the root hub is either suspended or stopped. + */ + ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); + spin_lock_irqsave(&ehci->lock, flags); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + (void)ehci_readl(ehci, &ehci->regs->intr_enable); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + spin_unlock_irqrestore(&ehci->lock, flags); + + if (pdata && pdata->phy_exit) + pdata->phy_exit(pdev, S5P_USB_PHY_HOST); + + return rc; +} + +static int s5p_ehci_resume(struct device *dev) +{ + struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); + struct usb_hcd *hcd = s5p_ehci->hcd; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct platform_device *pdev = to_platform_device(dev); + struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; + + if (pdata && pdata->phy_init) + pdata->phy_init(pdev, S5P_USB_PHY_HOST); + + if (time_before(jiffies, ehci->next_statechange)) + msleep(100); + + /* Mark hardware accessible again as we are out of D3 state by now */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { + int mask = INTR_MASK; + + ehci_prepare_ports_for_controller_resume(ehci); + if (!hcd->self.root_hub->do_remote_wakeup) + mask &= ~STS_PCD; + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); + return 0; + } + + usb_root_hub_lost_power(hcd->self.root_hub); + + (void) ehci_halt(ehci); + (void) ehci_reset(ehci); + + /* emptying the schedule aborts any urbs */ + spin_lock_irq(&ehci->lock); + if (ehci->reclaim) + end_unlink_async(ehci); + ehci_work(ehci); + spin_unlock_irq(&ehci->lock); + + ehci_writel(ehci, ehci->command, &ehci->regs->command); + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + + /* here we "know" root ports should always stay powered */ + ehci_port_power(ehci, 1); + + hcd->state = HC_STATE_SUSPENDED; + + return 0; +} +#else +#define s5p_ehci_suspend NULL +#define s5p_ehci_resume NULL +#endif + +static const struct dev_pm_ops s5p_ehci_pm_ops = { + .suspend = s5p_ehci_suspend, + .resume = s5p_ehci_resume, +}; + static struct platform_driver s5p_ehci_driver = { .probe = s5p_ehci_probe, .remove = __devexit_p(s5p_ehci_remove), @@ -196,6 +290,7 @@ static struct platform_driver s5p_ehci_driver = { .driver = { .name = "s5p-ehci", .owner = THIS_MODULE, + .pm = &s5p_ehci_pm_ops, } }; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 6c9fbe352f73..2abf8543f083 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -172,7 +172,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) } } #ifdef DEBUG - if (usecs > 100) + if (usecs > ehci->uframe_periodic_max) ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", frame * 8 + uframe, usecs); #endif @@ -709,11 +709,8 @@ static int check_period ( if (uframe >= 8) return 0; - /* - * 80% periodic == 100 usec/uframe available - * convert "usecs we need" to "max already claimed" - */ - usecs = 100 - usecs; + /* convert "usecs we need" to "max already claimed" */ + usecs = ehci->uframe_periodic_max - usecs; /* we "know" 2 and 4 uframe intervals were rejected; so * for period 0, check _every_ microframe in the schedule. @@ -1286,9 +1283,9 @@ itd_slot_ok ( { uframe %= period; do { - /* can't commit more than 80% periodic == 100 usec */ + /* can't commit more than uframe_periodic_max usec */ if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) - > (100 - usecs)) + > (ehci->uframe_periodic_max - usecs)) return 0; /* we know urb->interval is 2^N uframes */ @@ -1345,7 +1342,7 @@ sitd_slot_ok ( #endif /* check starts (OUT uses more than one) */ - max_used = 100 - stream->usecs; + max_used = ehci->uframe_periodic_max - stream->usecs; for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { if (periodic_usecs (ehci, frame, uf) > max_used) return 0; @@ -1354,7 +1351,7 @@ sitd_slot_ok ( /* for IN, check CSPLIT */ if (stream->c_usecs) { uf = uframe & 7; - max_used = 100 - stream->c_usecs; + max_used = ehci->uframe_periodic_max - stream->c_usecs; do { tmp = 1 << uf; tmp <<= 8; diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c new file mode 100644 index 000000000000..14ced00ba220 --- /dev/null +++ b/drivers/usb/host/ehci-sysfs.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2007 by Alan Stern + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* this file is part of ehci-hcd.c */ + + +/* Display the ports dedicated to the companion controller */ +static ssize_t show_companion(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ehci_hcd *ehci; + int nports, index, n; + int count = PAGE_SIZE; + char *ptr = buf; + + ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + nports = HCS_N_PORTS(ehci->hcs_params); + + for (index = 0; index < nports; ++index) { + if (test_bit(index, &ehci->companion_ports)) { + n = scnprintf(ptr, count, "%d\n", index + 1); + ptr += n; + count -= n; + } + } + return ptr - buf; +} + +/* + * Dedicate or undedicate a port to the companion controller. + * Syntax is "[-]portnum", where a leading '-' sign means + * return control of the port to the EHCI controller. + */ +static ssize_t store_companion(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ehci_hcd *ehci; + int portnum, new_owner; + + ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + new_owner = PORT_OWNER; /* Owned by companion */ + if (sscanf(buf, "%d", &portnum) != 1) + return -EINVAL; + if (portnum < 0) { + portnum = - portnum; + new_owner = 0; /* Owned by EHCI */ + } + if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) + return -ENOENT; + portnum--; + if (new_owner) + set_bit(portnum, &ehci->companion_ports); + else + clear_bit(portnum, &ehci->companion_ports); + set_owner(ehci, portnum, new_owner); + return count; +} +static DEVICE_ATTR(companion, 0644, show_companion, store_companion); + + +/* + * Display / Set uframe_periodic_max + */ +static ssize_t show_uframe_periodic_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ehci_hcd *ehci; + int n; + + ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max); + return n; +} + + +static ssize_t store_uframe_periodic_max(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ehci_hcd *ehci; + unsigned uframe_periodic_max; + unsigned frame, uframe; + unsigned short allocated_max; + unsigned long flags; + ssize_t ret; + + ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); + if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) + return -EINVAL; + + if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { + ehci_info(ehci, "rejecting invalid request for " + "uframe_periodic_max=%u\n", uframe_periodic_max); + return -EINVAL; + } + + ret = -EINVAL; + + /* + * lock, so that our checking does not race with possible periodic + * bandwidth allocation through submitting new urbs. + */ + spin_lock_irqsave (&ehci->lock, flags); + + /* + * for request to decrease max periodic bandwidth, we have to check + * every microframe in the schedule to see whether the decrease is + * possible. + */ + if (uframe_periodic_max < ehci->uframe_periodic_max) { + allocated_max = 0; + + for (frame = 0; frame < ehci->periodic_size; ++frame) + for (uframe = 0; uframe < 7; ++uframe) + allocated_max = max(allocated_max, + periodic_usecs (ehci, frame, uframe)); + + if (allocated_max > uframe_periodic_max) { + ehci_info(ehci, + "cannot decrease uframe_periodic_max becase " + "periodic bandwidth is already allocated " + "(%u > %u)\n", + allocated_max, uframe_periodic_max); + goto out_unlock; + } + } + + /* increasing is always ok */ + + ehci_info(ehci, "setting max periodic bandwidth to %u%% " + "(== %u usec/uframe)\n", + 100*uframe_periodic_max/125, uframe_periodic_max); + + if (uframe_periodic_max != 100) + ehci_warn(ehci, "max periodic bandwidth set is non-standard\n"); + + ehci->uframe_periodic_max = uframe_periodic_max; + ret = count; + +out_unlock: + spin_unlock_irqrestore (&ehci->lock, flags); + return ret; +} +static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max); + + +static inline int create_sysfs_files(struct ehci_hcd *ehci) +{ + struct device *controller = ehci_to_hcd(ehci)->self.controller; + int i = 0; + + /* with integrated TT there is no companion! */ + if (!ehci_is_TDI(ehci)) + i = device_create_file(controller, &dev_attr_companion); + if (i) + goto out; + + i = device_create_file(controller, &dev_attr_uframe_periodic_max); +out: + return i; +} + +static inline void remove_sysfs_files(struct ehci_hcd *ehci) +{ + struct device *controller = ehci_to_hcd(ehci)->self.controller; + + /* with integrated TT there is no companion! */ + if (!ehci_is_TDI(ehci)) + device_remove_file(controller, &dev_attr_companion); + + device_remove_file(controller, &dev_attr_uframe_periodic_max); +} diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bd6ff489baf9..cc7d337ec355 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -75,6 +75,7 @@ struct ehci_hcd { /* one per controller */ struct ehci_qh *async; struct ehci_qh *dummy; /* For AMD quirk use */ struct ehci_qh *reclaim; + struct ehci_qh *qh_scan_next; unsigned scanning : 1; /* periodic schedule support */ @@ -87,6 +88,8 @@ struct ehci_hcd { /* one per controller */ union ehci_shadow *pshadow; /* mirror hw periodic table */ int next_uframe; /* scan periodic, start here */ unsigned periodic_sched; /* periodic activity count */ + unsigned uframe_periodic_max; /* max periodic time per uframe */ + /* list of itds & sitds completed while clock_frame was still active */ struct list_head cached_itd_list; @@ -117,7 +120,6 @@ struct ehci_hcd { /* one per controller */ struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; - unsigned stamp; unsigned periodic_stamp; unsigned random_frame; unsigned long next_statechange; @@ -343,6 +345,7 @@ struct ehci_qh { struct ehci_qh *reclaim; /* next to reclaim */ struct ehci_hcd *ehci; + unsigned long unlink_time; /* * Do NOT use atomic operations for QH refcounting. On some CPUs @@ -374,6 +377,7 @@ struct ehci_qh { #define NO_FRAME ((unsigned short)~0) /* pick new start */ struct usb_device *dev; /* access to TT */ + unsigned is_out:1; /* bulk or intr OUT */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ }; diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c index f47867ff78c7..14cecb52a9fe 100644 --- a/drivers/usb/host/ohci-sh.c +++ b/drivers/usb/host/ohci-sh.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Renesas Solutions Corp. * - * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> + * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index fd930618c28f..a9d315906e3d 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -35,6 +35,8 @@ #define OHCI_INTRSTATUS 0x0c #define OHCI_INTRENABLE 0x10 #define OHCI_INTRDISABLE 0x14 +#define OHCI_FMINTERVAL 0x34 +#define OHCI_HCR (1 << 0) /* host controller reset */ #define OHCI_OCR (1 << 3) /* ownership change request */ #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ #define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ @@ -497,6 +499,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) /* reset controller, preserving RWC (and possibly IR) */ writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); + readl(base + OHCI_CONTROL); + + /* Some NVIDIA controllers stop working if kept in RESET for too long */ + if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { + u32 fminterval; + int cnt; + + /* drive reset for at least 50 ms (7.1.7.5) */ + msleep(50); + + /* software reset of the controller, preserving HcFmInterval */ + fminterval = readl(base + OHCI_FMINTERVAL); + writel(OHCI_HCR, base + OHCI_CMDSTATUS); + + /* reset requires max 10 us delay */ + for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ + if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) + break; + udelay(1); + } + writel(fminterval, base + OHCI_FMINTERVAL); + + /* Now we're in the SUSPEND state with all devices reset + * and wakeups and interrupts disabled + */ + } /* * disable interrupts @@ -507,20 +535,34 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) iounmap(base); } +static const struct dmi_system_id __initconst ehci_dmi_nohandoff_table[] = { + { + /* Pegatron Lucid (ExoPC) */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "EXOPG06411"), + DMI_MATCH(DMI_BIOS_VERSION, "Lucid-CE-133"), + }, + }, + { + /* Pegatron Lucid (Ordissimo AIRIS) */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "M11JB"), + DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"), + }, + }, + { } +}; + static void __devinit ehci_bios_handoff(struct pci_dev *pdev, void __iomem *op_reg_base, u32 cap, u8 offset) { int try_handoff = 1, tried_handoff = 0; - /* The Pegatron Lucid (ExoPC) tablet sporadically waits for 90 - * seconds trying the handoff on its unused controller. Skip - * it. */ + /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying + * the handoff on its unused controller. Skip it. */ if (pdev->vendor == 0x8086 && pdev->device == 0x283a) { - const char *dmi_bn = dmi_get_system_info(DMI_BOARD_NAME); - const char *dmi_bv = dmi_get_system_info(DMI_BIOS_VERSION); - if (dmi_bn && !strcmp(dmi_bn, "EXOPG06411") && - dmi_bv && !strcmp(dmi_bv, "Lucid-CE-133")) + if (dmi_check_system(ehci_dmi_nohandoff_table)) try_handoff = 0; } diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 4586369dda00..40a0d8b03ad7 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -6,7 +6,7 @@ * Portions Copyright (C) 2004-2005 David Brownell * Portions Copyright (C) 1999 Roman Weissgaerber * - * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> + * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1438,7 +1438,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) if (pipenum > 0) r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS); if (urb->transfer_buffer) { - r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size); + r8a66597_write_fifo(r8a66597, td->pipe, buf, size); if (!usb_pipebulk(urb->pipe) || td->maxpacket != size) r8a66597_write(r8a66597, BVAL, td->pipe->fifoctr); } @@ -2306,7 +2306,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd) dbg("resume port = %d", port); rh->port &= ~USB_PORT_STAT_SUSPEND; - rh->port |= USB_PORT_STAT_C_SUSPEND < 16; + rh->port |= USB_PORT_STAT_C_SUSPEND << 16; r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg); msleep(50); r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg); diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index 25563e9a90bc..f28782d20eef 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -201,11 +201,26 @@ static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, iowrite16(val, r8a66597->reg + offset); } +static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, + u16 val, u16 pat, unsigned long offset) +{ + u16 tmp; + tmp = r8a66597_read(r8a66597, offset); + tmp = tmp & (~pat); + tmp = tmp | val; + r8a66597_write(r8a66597, tmp, offset); +} + +#define r8a66597_bclr(r8a66597, val, offset) \ + r8a66597_mdfy(r8a66597, 0, val, offset) +#define r8a66597_bset(r8a66597, val, offset) \ + r8a66597_mdfy(r8a66597, val, 0, offset) + static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, - unsigned long offset, u16 *buf, + struct r8a66597_pipe *pipe, u16 *buf, int len) { - void __iomem *fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + pipe->fifoaddr; unsigned long count; unsigned char *pb; int i; @@ -230,26 +245,15 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, iowrite16_rep(fifoaddr, buf, len); if (unlikely(odd)) { buf = &buf[len]; + if (r8a66597->pdata->wr0_shorted_to_wr1) + r8a66597_bclr(r8a66597, MBW_16, pipe->fifosel); iowrite8((unsigned char)*buf, fifoaddr); + if (r8a66597->pdata->wr0_shorted_to_wr1) + r8a66597_bset(r8a66597, MBW_16, pipe->fifosel); } } } -static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, - u16 val, u16 pat, unsigned long offset) -{ - u16 tmp; - tmp = r8a66597_read(r8a66597, offset); - tmp = tmp & (~pat); - tmp = tmp | val; - r8a66597_write(r8a66597, tmp, offset); -} - -#define r8a66597_bclr(r8a66597, val, offset) \ - r8a66597_mdfy(r8a66597, 0, val, offset) -#define r8a66597_bset(r8a66597, val, offset) \ - r8a66597_mdfy(r8a66597, val, 0, offset) - static inline unsigned long get_syscfg_reg(int port) { return port == 0 ? SYSCFG0 : SYSCFG1; diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 1f50b4468e87..e9b0f043455d 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -266,11 +266,11 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb) xhci_dbg(xhci, "Interrupter target = 0x%x\n", GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target))); xhci_dbg(xhci, "Cycle bit = %u\n", - (unsigned int) (le32_to_cpu(trb->link.control) & TRB_CYCLE)); + le32_to_cpu(trb->link.control) & TRB_CYCLE); xhci_dbg(xhci, "Toggle cycle bit = %u\n", - (unsigned int) (le32_to_cpu(trb->link.control) & LINK_TOGGLE)); + le32_to_cpu(trb->link.control) & LINK_TOGGLE); xhci_dbg(xhci, "No Snoop bit = %u\n", - (unsigned int) (le32_to_cpu(trb->link.control) & TRB_NO_SNOOP)); + le32_to_cpu(trb->link.control) & TRB_NO_SNOOP); break; case TRB_TYPE(TRB_TRANSFER): address = le64_to_cpu(trb->trans_event.buffer); @@ -284,9 +284,9 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb) address = le64_to_cpu(trb->event_cmd.cmd_trb); xhci_dbg(xhci, "Command TRB pointer = %llu\n", address); xhci_dbg(xhci, "Completion status = %u\n", - (unsigned int) GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status))); + GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status))); xhci_dbg(xhci, "Flags = 0x%x\n", - (unsigned int) le32_to_cpu(trb->event_cmd.flags)); + le32_to_cpu(trb->event_cmd.flags)); break; default: xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n", @@ -318,10 +318,10 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg) for (i = 0; i < TRBS_PER_SEGMENT; ++i) { trb = &seg->trbs[i]; xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr, - (u32)lower_32_bits(le64_to_cpu(trb->link.segment_ptr)), - (u32)upper_32_bits(le64_to_cpu(trb->link.segment_ptr)), - (unsigned int) le32_to_cpu(trb->link.intr_target), - (unsigned int) le32_to_cpu(trb->link.control)); + lower_32_bits(le64_to_cpu(trb->link.segment_ptr)), + upper_32_bits(le64_to_cpu(trb->link.segment_ptr)), + le32_to_cpu(trb->link.intr_target), + le32_to_cpu(trb->link.control)); addr += sizeof(*trb); } } @@ -402,8 +402,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) addr, lower_32_bits(le64_to_cpu(entry->seg_addr)), upper_32_bits(le64_to_cpu(entry->seg_addr)), - (unsigned int) le32_to_cpu(entry->seg_size), - (unsigned int) le32_to_cpu(entry->rsvd)); + le32_to_cpu(entry->seg_size), + le32_to_cpu(entry->rsvd)); addr += sizeof(*entry); } } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fcb7f7efc86d..d446886b22b0 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -89,8 +89,8 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, return; prev->next = next; if (link_trbs) { - prev->trbs[TRBS_PER_SEGMENT-1].link. - segment_ptr = cpu_to_le64(next->dma); + prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = + cpu_to_le64(next->dma); /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control); @@ -187,8 +187,8 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, if (link_trbs) { /* See section 4.9.2.1 and 6.4.4.1 */ - prev->trbs[TRBS_PER_SEGMENT-1].link. - control |= cpu_to_le32(LINK_TOGGLE); + prev->trbs[TRBS_PER_SEGMENT-1].link.control |= + cpu_to_le32(LINK_TOGGLE); xhci_dbg(xhci, "Wrote link toggle flag to" " segment %p (virtual), 0x%llx (DMA)\n", prev, (unsigned long long)prev->dma); @@ -549,8 +549,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, addr = cur_ring->first_seg->dma | SCT_FOR_CTX(SCT_PRI_TR) | cur_ring->cycle_state; - stream_info->stream_ctx_array[cur_stream]. - stream_ring = cpu_to_le64(addr); + stream_info->stream_ctx_array[cur_stream].stream_ring = + cpu_to_le64(addr); xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, (unsigned long long) addr); @@ -786,7 +786,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", slot_id, &xhci->dcbaa->dev_context_ptrs[slot_id], - (unsigned long long) le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id])); + le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id])); return 1; fail: @@ -890,19 +890,19 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); /* 3) Only the control endpoint is valid - one endpoint context */ - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | (u32) udev->route); + slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route); switch (udev->speed) { case USB_SPEED_SUPER: - slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_SS); + slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS); break; case USB_SPEED_HIGH: - slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_HS); + slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_HS); break; case USB_SPEED_FULL: - slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_FS); + slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_FS); break; case USB_SPEED_LOW: - slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_LS); + slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_LS); break; case USB_SPEED_WIRELESS: xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); @@ -916,7 +916,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud port_num = xhci_find_real_port_number(xhci, udev); if (!port_num) return -EINVAL; - slot_ctx->dev_info2 |= cpu_to_le32((u32) ROOT_HUB_PORT(port_num)); + slot_ctx->dev_info2 |= cpu_to_le32(ROOT_HUB_PORT(port_num)); /* Set the port number in the virtual_device to the faked port number */ for (top_dev = udev; top_dev->parent && top_dev->parent->parent; top_dev = top_dev->parent) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 70cacbbe7fb9..7113d16e2d3a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -113,15 +113,13 @@ static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, if (ring == xhci->event_ring) return trb == &seg->trbs[TRBS_PER_SEGMENT]; else - return (le32_to_cpu(trb->link.control) & TRB_TYPE_BITMASK) - == TRB_TYPE(TRB_LINK); + return TRB_TYPE_LINK_LE32(trb->link.control); } static int enqueue_is_link_trb(struct xhci_ring *ring) { struct xhci_link_trb *link = &ring->enqueue->link; - return ((le32_to_cpu(link->control) & TRB_TYPE_BITMASK) == - TRB_TYPE(TRB_LINK)); + return TRB_TYPE_LINK_LE32(link->control); } /* Updates trb to point to the next TRB in the ring, and updates seg if the next @@ -372,7 +370,7 @@ static struct xhci_segment *find_trb_seg( while (cur_seg->trbs > trb || &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) { generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic; - if (le32_to_cpu(generic_trb->field[3]) & LINK_TOGGLE) + if (generic_trb->field[3] & cpu_to_le32(LINK_TOGGLE)) *cycle_state ^= 0x1; cur_seg = cur_seg->next; if (cur_seg == start_seg) @@ -489,8 +487,8 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, } trb = &state->new_deq_ptr->generic; - if ((le32_to_cpu(trb->field[3]) & TRB_TYPE_BITMASK) == - TRB_TYPE(TRB_LINK) && (le32_to_cpu(trb->field[3]) & LINK_TOGGLE)) + if (TRB_TYPE_LINK_LE32(trb->field[3]) && + (trb->field[3] & cpu_to_le32(LINK_TOGGLE))) state->new_cycle_state ^= 0x1; next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); @@ -525,8 +523,7 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, for (cur_seg = cur_td->start_seg, cur_trb = cur_td->first_trb; true; next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { - if ((le32_to_cpu(cur_trb->generic.field[3]) & TRB_TYPE_BITMASK) - == TRB_TYPE(TRB_LINK)) { + if (TRB_TYPE_LINK_LE32(cur_trb->generic.field[3])) { /* Unchain any chained Link TRBs, but * leave the pointers intact. */ @@ -1000,7 +997,7 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, * but we don't care. */ xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n", - (unsigned int) GET_COMP_CODE(le32_to_cpu(event->status))); + GET_COMP_CODE(le32_to_cpu(event->status))); /* HW with the reset endpoint quirk needs to have a configure endpoint * command complete before the endpoint can be used. Queue that here @@ -1458,7 +1455,8 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci, * endpoint anyway. Check if a babble halted the * endpoint. */ - if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == EP_STATE_HALTED) + if ((ep_ctx->ep_info & cpu_to_le32(EP_STATE_MASK)) == + cpu_to_le32(EP_STATE_HALTED)) return 1; return 0; @@ -1753,10 +1751,8 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; cur_trb != event_trb; next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { - if ((le32_to_cpu(cur_trb->generic.field[3]) & - TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) && - (le32_to_cpu(cur_trb->generic.field[3]) & - TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK)) + if (!TRB_TYPE_NOOP_LE32(cur_trb->generic.field[3]) && + !TRB_TYPE_LINK_LE32(cur_trb->generic.field[3])) len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])); } len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - @@ -1885,10 +1881,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; cur_trb != event_trb; next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { - if ((le32_to_cpu(cur_trb->generic.field[3]) & - TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) && - (le32_to_cpu(cur_trb->generic.field[3]) & - TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK)) + if (!TRB_TYPE_NOOP_LE32(cur_trb->generic.field[3]) && + !TRB_TYPE_LINK_LE32(cur_trb->generic.field[3])) td->urb->actual_length += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])); } @@ -2047,8 +2041,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", - (unsigned int) (le32_to_cpu(event->flags) - & TRB_TYPE_BITMASK)>>10); + (le32_to_cpu(event->flags) & + TRB_TYPE_BITMASK)>>10); xhci_print_trb_offsets(xhci, (union xhci_trb *) event); if (ep->skip) { ep->skip = false; @@ -2119,9 +2113,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, * corresponding TD has been cancelled. Just ignore * the TD. */ - if ((le32_to_cpu(event_trb->generic.field[3]) - & TRB_TYPE_BITMASK) - == TRB_TYPE(TRB_TR_NOOP)) { + if (TRB_TYPE_NOOP_LE32(event_trb->generic.field[3])) { xhci_dbg(xhci, "event_trb is a no-op TRB. Skip it\n"); goto cleanup; @@ -2452,7 +2444,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, next->link.control |= cpu_to_le32(TRB_CHAIN); wmb(); - next->link.control ^= cpu_to_le32((u32) TRB_CYCLE); + next->link.control ^= cpu_to_le32(TRB_CYCLE); /* Toggle the cycle bit after the last ring segment. */ if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f5fe1ac301ab..763f484bc092 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1342,8 +1342,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, /* If the HC already knows the endpoint is disabled, * or the HCD has noted it is disabled, ignore this request */ - if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == - EP_STATE_DISABLED || + if (((ep_ctx->ep_info & cpu_to_le32(EP_STATE_MASK)) == + cpu_to_le32(EP_STATE_DISABLED)) || le32_to_cpu(ctrl_ctx->drop_flags) & xhci_get_endpoint_flag(&ep->desc)) { xhci_warn(xhci, "xHCI %s called with disabled ep %p\n", @@ -1758,8 +1758,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, /* Enqueue pointer can be left pointing to the link TRB, * we must handle that */ - if ((le32_to_cpu(command->command_trb->link.control) - & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) + if (TRB_TYPE_LINK_LE32(command->command_trb->link.control)) command->command_trb = xhci->cmd_ring->enq_seg->next->trbs; @@ -2559,8 +2558,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Enqueue pointer can be left pointing to the link TRB, * we must handle that */ - if ((le32_to_cpu(reset_device_cmd->command_trb->link.control) - & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) + if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control)) reset_device_cmd->command_trb = xhci->cmd_ring->enq_seg->next->trbs; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index d8bbf5ccb10d..cae8e23308bf 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1072,6 +1072,13 @@ union xhci_trb { /* Get NEC firmware revision. */ #define TRB_NEC_GET_FW 49 +#define TRB_TYPE_LINK(x) (((x) & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) +/* Above, but for __le32 types -- can avoid work by swapping constants: */ +#define TRB_TYPE_LINK_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \ + cpu_to_le32(TRB_TYPE(TRB_LINK))) +#define TRB_TYPE_NOOP_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \ + cpu_to_le32(TRB_TYPE(TRB_TR_NOOP))) + #define NEC_FW_MINOR(p) (((p) >> 0) & 0xff) #define NEC_FW_MAJOR(p) (((p) >> 8) & 0xff) |