USB: revert EHCI VIA workaround patch
This reverts 26f953fd88
which caused
resume problems on the mac mini.
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
4e4bc305e1
Коммит
64f89798da
|
@ -754,7 +754,9 @@ show_registers (struct class_device *class_dev, char *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ehci->reclaim) {
|
if (ehci->reclaim) {
|
||||||
temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim);
|
temp = scnprintf (next, size, "reclaim qh %p%s\n",
|
||||||
|
ehci->reclaim,
|
||||||
|
ehci->reclaim_ready ? " ready" : "");
|
||||||
size -= temp;
|
size -= temp;
|
||||||
next += temp;
|
next += temp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd";
|
||||||
#define EHCI_TUNE_MULT_TT 1
|
#define EHCI_TUNE_MULT_TT 1
|
||||||
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
|
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
|
||||||
|
|
||||||
#define EHCI_IAA_MSECS 10 /* arbitrary */
|
#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
|
||||||
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
|
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
|
||||||
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
|
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
|
||||||
#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
|
#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
|
||||||
|
@ -254,7 +254,6 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static void end_unlink_async (struct ehci_hcd *ehci);
|
|
||||||
static void ehci_work(struct ehci_hcd *ehci);
|
static void ehci_work(struct ehci_hcd *ehci);
|
||||||
|
|
||||||
#include "ehci-hub.c"
|
#include "ehci-hub.c"
|
||||||
|
@ -264,29 +263,6 @@ static void ehci_work(struct ehci_hcd *ehci);
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static void ehci_iaa_watchdog (unsigned long param)
|
|
||||||
{
|
|
||||||
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
|
|
||||||
unsigned long flags;
|
|
||||||
u32 status;
|
|
||||||
|
|
||||||
spin_lock_irqsave (&ehci->lock, flags);
|
|
||||||
WARN_ON(!ehci->reclaim);
|
|
||||||
|
|
||||||
/* lost IAA irqs wedge things badly; seen first with a vt8235 */
|
|
||||||
if (ehci->reclaim) {
|
|
||||||
status = readl (&ehci->regs->status);
|
|
||||||
if (status & STS_IAA) {
|
|
||||||
ehci_vdbg (ehci, "lost IAA\n");
|
|
||||||
COUNT (ehci->stats.lost_iaa);
|
|
||||||
writel (STS_IAA, &ehci->regs->status);
|
|
||||||
end_unlink_async (ehci);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ehci_watchdog (unsigned long param)
|
static void ehci_watchdog (unsigned long param)
|
||||||
{
|
{
|
||||||
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
|
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
|
||||||
|
@ -294,7 +270,18 @@ static void ehci_watchdog (unsigned long param)
|
||||||
|
|
||||||
spin_lock_irqsave (&ehci->lock, flags);
|
spin_lock_irqsave (&ehci->lock, flags);
|
||||||
|
|
||||||
/* stop async processing after it's idled a bit */
|
/* lost IAA irqs wedge things badly; seen with a vt8235 */
|
||||||
|
if (ehci->reclaim) {
|
||||||
|
u32 status = readl (&ehci->regs->status);
|
||||||
|
if (status & STS_IAA) {
|
||||||
|
ehci_vdbg (ehci, "lost IAA\n");
|
||||||
|
COUNT (ehci->stats.lost_iaa);
|
||||||
|
writel (STS_IAA, &ehci->regs->status);
|
||||||
|
ehci->reclaim_ready = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stop async processing after it's idled a bit */
|
||||||
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
|
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
|
||||||
start_unlink_async (ehci, ehci->async);
|
start_unlink_async (ehci, ehci->async);
|
||||||
|
|
||||||
|
@ -345,6 +332,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
|
||||||
static void ehci_work (struct ehci_hcd *ehci)
|
static void ehci_work (struct ehci_hcd *ehci)
|
||||||
{
|
{
|
||||||
timer_action_done (ehci, TIMER_IO_WATCHDOG);
|
timer_action_done (ehci, TIMER_IO_WATCHDOG);
|
||||||
|
if (ehci->reclaim_ready)
|
||||||
|
end_unlink_async (ehci);
|
||||||
|
|
||||||
/* another CPU may drop ehci->lock during a schedule scan while
|
/* another CPU may drop ehci->lock during a schedule scan while
|
||||||
* it reports urb completions. this flag guards against bogus
|
* it reports urb completions. this flag guards against bogus
|
||||||
|
@ -379,7 +368,6 @@ static void ehci_stop (struct usb_hcd *hcd)
|
||||||
|
|
||||||
/* no more interrupts ... */
|
/* no more interrupts ... */
|
||||||
del_timer_sync (&ehci->watchdog);
|
del_timer_sync (&ehci->watchdog);
|
||||||
del_timer_sync (&ehci->iaa_watchdog);
|
|
||||||
|
|
||||||
spin_lock_irq(&ehci->lock);
|
spin_lock_irq(&ehci->lock);
|
||||||
if (HC_IS_RUNNING (hcd->state))
|
if (HC_IS_RUNNING (hcd->state))
|
||||||
|
@ -426,10 +414,6 @@ static int ehci_init(struct usb_hcd *hcd)
|
||||||
ehci->watchdog.function = ehci_watchdog;
|
ehci->watchdog.function = ehci_watchdog;
|
||||||
ehci->watchdog.data = (unsigned long) ehci;
|
ehci->watchdog.data = (unsigned long) ehci;
|
||||||
|
|
||||||
init_timer(&ehci->iaa_watchdog);
|
|
||||||
ehci->iaa_watchdog.function = ehci_iaa_watchdog;
|
|
||||||
ehci->iaa_watchdog.data = (unsigned long) ehci;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hw default: 1K periodic list heads, one per frame.
|
* hw default: 1K periodic list heads, one per frame.
|
||||||
* periodic_size can shrink by USBCMD update if hcc_params allows.
|
* periodic_size can shrink by USBCMD update if hcc_params allows.
|
||||||
|
@ -446,6 +430,7 @@ static int ehci_init(struct usb_hcd *hcd)
|
||||||
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
|
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
|
||||||
|
|
||||||
ehci->reclaim = NULL;
|
ehci->reclaim = NULL;
|
||||||
|
ehci->reclaim_ready = 0;
|
||||||
ehci->next_uframe = -1;
|
ehci->next_uframe = -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -619,7 +604,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
||||||
/* complete the unlinking of some qh [4.15.2.3] */
|
/* complete the unlinking of some qh [4.15.2.3] */
|
||||||
if (status & STS_IAA) {
|
if (status & STS_IAA) {
|
||||||
COUNT (ehci->stats.reclaim);
|
COUNT (ehci->stats.reclaim);
|
||||||
end_unlink_async (ehci);
|
ehci->reclaim_ready = 1;
|
||||||
bh = 1;
|
bh = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,14 +708,10 @@ static int ehci_urb_enqueue (
|
||||||
|
|
||||||
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||||
{
|
{
|
||||||
// BUG_ON(qh->qh_state != QH_STATE_LINKED);
|
/* if we need to use IAA and it's busy, defer */
|
||||||
|
if (qh->qh_state == QH_STATE_LINKED
|
||||||
/* failfast */
|
&& ehci->reclaim
|
||||||
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
|
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
|
||||||
end_unlink_async (ehci);
|
|
||||||
|
|
||||||
/* defer till later if busy */
|
|
||||||
else if (ehci->reclaim) {
|
|
||||||
struct ehci_qh *last;
|
struct ehci_qh *last;
|
||||||
|
|
||||||
for (last = ehci->reclaim;
|
for (last = ehci->reclaim;
|
||||||
|
@ -740,8 +721,12 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||||
qh->qh_state = QH_STATE_UNLINK_WAIT;
|
qh->qh_state = QH_STATE_UNLINK_WAIT;
|
||||||
last->reclaim = qh;
|
last->reclaim = qh;
|
||||||
|
|
||||||
/* start IAA cycle */
|
/* bypass IAA if the hc can't care */
|
||||||
} else
|
} else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
|
||||||
|
end_unlink_async (ehci);
|
||||||
|
|
||||||
|
/* something else might have unlinked the qh by now */
|
||||||
|
if (qh->qh_state == QH_STATE_LINKED)
|
||||||
start_unlink_async (ehci, qh);
|
start_unlink_async (ehci, qh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,19 +748,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
|
||||||
qh = (struct ehci_qh *) urb->hcpriv;
|
qh = (struct ehci_qh *) urb->hcpriv;
|
||||||
if (!qh)
|
if (!qh)
|
||||||
break;
|
break;
|
||||||
switch (qh->qh_state) {
|
unlink_async (ehci, qh);
|
||||||
case QH_STATE_LINKED:
|
|
||||||
case QH_STATE_COMPLETING:
|
|
||||||
unlink_async (ehci, qh);
|
|
||||||
break;
|
|
||||||
case QH_STATE_UNLINK:
|
|
||||||
case QH_STATE_UNLINK_WAIT:
|
|
||||||
/* already started */
|
|
||||||
break;
|
|
||||||
case QH_STATE_IDLE:
|
|
||||||
WARN_ON(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PIPE_INTERRUPT:
|
case PIPE_INTERRUPT:
|
||||||
|
@ -867,7 +840,6 @@ rescan:
|
||||||
unlink_async (ehci, qh);
|
unlink_async (ehci, qh);
|
||||||
/* FALL THROUGH */
|
/* FALL THROUGH */
|
||||||
case QH_STATE_UNLINK: /* wait for hw to finish? */
|
case QH_STATE_UNLINK: /* wait for hw to finish? */
|
||||||
case QH_STATE_UNLINK_WAIT:
|
|
||||||
idle_timeout:
|
idle_timeout:
|
||||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||||
schedule_timeout_uninterruptible(1);
|
schedule_timeout_uninterruptible(1);
|
||||||
|
|
|
@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
||||||
}
|
}
|
||||||
ehci->command = readl (&ehci->regs->command);
|
ehci->command = readl (&ehci->regs->command);
|
||||||
if (ehci->reclaim)
|
if (ehci->reclaim)
|
||||||
end_unlink_async (ehci);
|
ehci->reclaim_ready = 1;
|
||||||
ehci_work(ehci);
|
ehci_work(ehci);
|
||||||
|
|
||||||
/* suspend any active/unsuspended ports, maybe allow wakeup */
|
/* suspend any active/unsuspended ports, maybe allow wakeup */
|
||||||
|
|
|
@ -303,7 +303,7 @@ restart:
|
||||||
/* emptying the schedule aborts any urbs */
|
/* emptying the schedule aborts any urbs */
|
||||||
spin_lock_irq(&ehci->lock);
|
spin_lock_irq(&ehci->lock);
|
||||||
if (ehci->reclaim)
|
if (ehci->reclaim)
|
||||||
end_unlink_async (ehci);
|
ehci->reclaim_ready = 1;
|
||||||
ehci_work(ehci);
|
ehci_work(ehci);
|
||||||
spin_unlock_irq(&ehci->lock);
|
spin_unlock_irq(&ehci->lock);
|
||||||
|
|
||||||
|
|
|
@ -967,7 +967,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
|
||||||
struct ehci_qh *qh = ehci->reclaim;
|
struct ehci_qh *qh = ehci->reclaim;
|
||||||
struct ehci_qh *next;
|
struct ehci_qh *next;
|
||||||
|
|
||||||
iaa_watchdog_done (ehci);
|
timer_action_done (ehci, TIMER_IAA_WATCHDOG);
|
||||||
|
|
||||||
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
|
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
|
||||||
qh->qh_state = QH_STATE_IDLE;
|
qh->qh_state = QH_STATE_IDLE;
|
||||||
|
@ -977,6 +977,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
|
||||||
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
|
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
|
||||||
next = qh->reclaim;
|
next = qh->reclaim;
|
||||||
ehci->reclaim = next;
|
ehci->reclaim = next;
|
||||||
|
ehci->reclaim_ready = 0;
|
||||||
qh->reclaim = NULL;
|
qh->reclaim = NULL;
|
||||||
|
|
||||||
qh_completions (ehci, qh);
|
qh_completions (ehci, qh);
|
||||||
|
@ -1051,10 +1052,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ehci->reclaim_ready = 0;
|
||||||
cmd |= CMD_IAAD;
|
cmd |= CMD_IAAD;
|
||||||
writel (cmd, &ehci->regs->command);
|
writel (cmd, &ehci->regs->command);
|
||||||
(void) readl (&ehci->regs->command);
|
(void) readl (&ehci->regs->command);
|
||||||
iaa_watchdog_start (ehci);
|
timer_action (ehci, TIMER_IAA_WATCHDOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct ehci_hcd { /* one per controller */
|
||||||
/* async schedule support */
|
/* async schedule support */
|
||||||
struct ehci_qh *async;
|
struct ehci_qh *async;
|
||||||
struct ehci_qh *reclaim;
|
struct ehci_qh *reclaim;
|
||||||
|
unsigned reclaim_ready : 1;
|
||||||
unsigned scanning : 1;
|
unsigned scanning : 1;
|
||||||
|
|
||||||
/* periodic schedule support */
|
/* periodic schedule support */
|
||||||
|
@ -80,7 +81,6 @@ struct ehci_hcd { /* one per controller */
|
||||||
struct dma_pool *itd_pool; /* itd per iso urb */
|
struct dma_pool *itd_pool; /* itd per iso urb */
|
||||||
struct dma_pool *sitd_pool; /* sitd per split iso urb */
|
struct dma_pool *sitd_pool; /* sitd per split iso urb */
|
||||||
|
|
||||||
struct timer_list iaa_watchdog;
|
|
||||||
struct timer_list watchdog;
|
struct timer_list watchdog;
|
||||||
unsigned long actions;
|
unsigned long actions;
|
||||||
unsigned stamp;
|
unsigned stamp;
|
||||||
|
@ -114,21 +114,9 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
iaa_watchdog_start (struct ehci_hcd *ehci)
|
|
||||||
{
|
|
||||||
WARN_ON(timer_pending(&ehci->iaa_watchdog));
|
|
||||||
mod_timer (&ehci->iaa_watchdog,
|
|
||||||
jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void iaa_watchdog_done (struct ehci_hcd *ehci)
|
|
||||||
{
|
|
||||||
del_timer (&ehci->iaa_watchdog);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ehci_timer_action {
|
enum ehci_timer_action {
|
||||||
TIMER_IO_WATCHDOG,
|
TIMER_IO_WATCHDOG,
|
||||||
|
TIMER_IAA_WATCHDOG,
|
||||||
TIMER_ASYNC_SHRINK,
|
TIMER_ASYNC_SHRINK,
|
||||||
TIMER_ASYNC_OFF,
|
TIMER_ASYNC_OFF,
|
||||||
};
|
};
|
||||||
|
@ -146,6 +134,9 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
|
||||||
unsigned long t;
|
unsigned long t;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
case TIMER_IAA_WATCHDOG:
|
||||||
|
t = EHCI_IAA_JIFFIES;
|
||||||
|
break;
|
||||||
case TIMER_IO_WATCHDOG:
|
case TIMER_IO_WATCHDOG:
|
||||||
t = EHCI_IO_JIFFIES;
|
t = EHCI_IO_JIFFIES;
|
||||||
break;
|
break;
|
||||||
|
@ -162,7 +153,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
|
||||||
// async queue SHRINK often precedes IAA. while it's ready
|
// async queue SHRINK often precedes IAA. while it's ready
|
||||||
// to go OFF neither can matter, and afterwards the IO
|
// to go OFF neither can matter, and afterwards the IO
|
||||||
// watchdog stops unless there's still periodic traffic.
|
// watchdog stops unless there's still periodic traffic.
|
||||||
if (time_before_eq(t, ehci->watchdog.expires)
|
if (action != TIMER_IAA_WATCHDOG
|
||||||
|
&& t > ehci->watchdog.expires
|
||||||
&& timer_pending (&ehci->watchdog))
|
&& timer_pending (&ehci->watchdog))
|
||||||
return;
|
return;
|
||||||
mod_timer (&ehci->watchdog, t);
|
mod_timer (&ehci->watchdog, t);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче