Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: OHCI: disable RHSC inside interrupt handler

This patch (as808b) moves the Root Hub Status Change interrupt-disable
code in ohci-hcd back into the interrupt handler proper, to avoid the
chance of adverse interactions with mediocre hardware implementations.

It also deletes the root-hub status timer from within the interrupt-enable
routine. There's no need to poll for status any more once interrupts are
re-enabled.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
052ac01a b1878440

+18 -16
+10
drivers/usb/host/ohci-hcd.c
··· 729 729 ohci->next_statechange = jiffies + STATECHANGE_DELAY; 730 730 ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC, 731 731 &regs->intrstatus); 732 + 733 + /* NOTE: Vendors didn't always make the same implementation 734 + * choices for RHSC. Many followed the spec; RHSC triggers 735 + * on an edge, like setting and maybe clearing a port status 736 + * change bit. With others it's level-triggered, active 737 + * until khubd clears all the port status change bits. We'll 738 + * always disable it here and rely on polling until khubd 739 + * re-enables it. 740 + */ 741 + ohci_writel(ohci, OHCI_INTR_RHSC, &regs->intrdisable); 732 742 usb_hcd_poll_rh_status(hcd); 733 743 } 734 744
+8 -16
drivers/usb/host/ohci-hub.c
··· 41 41 { 42 42 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 43 43 44 - ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); 44 + spin_lock_irq(&ohci->lock); 45 + if (!ohci->autostop) 46 + del_timer(&hcd->rh_timer); /* Prevent next poll */ 47 + ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); 48 + spin_unlock_irq(&ohci->lock); 45 49 } 46 50 47 51 #define OHCI_SCHED_ENABLES \ ··· 352 348 { 353 349 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 354 350 int i, changed = 0, length = 1; 355 - int any_connected = 0, rhsc_enabled = 1; 351 + int any_connected = 0; 356 352 unsigned long flags; 357 353 358 354 spin_lock_irqsave (&ohci->lock, flags); ··· 393 389 } 394 390 } 395 391 396 - /* NOTE: vendors didn't always make the same implementation 397 - * choices for RHSC. Sometimes it triggers on an edge (like 398 - * setting and maybe clearing a port status change bit); and 399 - * it's level-triggered on other silicon, active until khubd 400 - * clears all active port status change bits. If it's still 401 - * set (level-triggered) we must disable it and rely on 402 - * polling until khubd re-enables it. 403 - */ 404 - if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) { 405 - ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); 406 - (void) ohci_readl (ohci, &ohci->regs->intrdisable); 407 - rhsc_enabled = 0; 408 - } 409 392 hcd->poll_rh = 1; 410 393 411 394 /* carry out appropriate state changes */ ··· 403 412 * and RHSC is enabled */ 404 413 if (!ohci->autostop) { 405 414 if (any_connected) { 406 - if (rhsc_enabled) 415 + if (ohci_readl(ohci, &ohci->regs->intrenable) & 416 + OHCI_INTR_RHSC) 407 417 hcd->poll_rh = 0; 408 418 } else { 409 419 ohci->autostop = 1;