[PATCH] USB: Switch isp116x-hcd over to root hub interrupt

Switch isp116x-hcd over from root hub polling to interrupt.  This change closes
also a race that was present with the old polling scheme: status polling could
happen in a time window, where root hub status bits were not stable.

Signed-off-by: Olav Kongas <ok@artecdesign.ee>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Olav Kongas 2005-08-05 14:23:35 +03:00 коммит произвёл Greg Kroah-Hartman
Родитель f8d23d3098
Коммит 9a57116bc9
1 изменённых файлов: 22 добавлений и 13 удалений

Просмотреть файл

@ -83,7 +83,7 @@
#include "../core/hcd.h" #include "../core/hcd.h"
#include "isp116x.h" #include "isp116x.h"
#define DRIVER_VERSION "08 Apr 2005" #define DRIVER_VERSION "05 Aug 2005"
#define DRIVER_DESC "ISP116x USB Host Controller Driver" #define DRIVER_DESC "ISP116x USB Host Controller Driver"
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
@ -629,14 +629,12 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
ERR("Unrecoverable error\n"); ERR("Unrecoverable error\n");
/* What should we do here? Reset? */ /* What should we do here? Reset? */
} }
if (intstat & HCINT_RHSC) { if (intstat & HCINT_RHSC)
isp116x->rhstatus = /* When root hub or any of its ports is going
isp116x_read_reg32(isp116x, HCRHSTATUS); to come out of suspend, it may take more
isp116x->rhport[0] = than 10ms for status bits to stabilize. */
isp116x_read_reg32(isp116x, HCRHPORT1); mod_timer(&hcd->rh_timer, jiffies
isp116x->rhport[1] = + msecs_to_jiffies(20) + 1);
isp116x_read_reg32(isp116x, HCRHPORT2);
}
if (intstat & HCINT_RD) { if (intstat & HCINT_RD) {
DBG("---- remote wakeup\n"); DBG("---- remote wakeup\n");
schedule_work(&isp116x->rh_resume); schedule_work(&isp116x->rh_resume);
@ -925,20 +923,27 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
{ {
struct isp116x *isp116x = hcd_to_isp116x(hcd); struct isp116x *isp116x = hcd_to_isp116x(hcd);
int ports, i, changed = 0; int ports, i, changed = 0;
unsigned long flags;
if (!HC_IS_RUNNING(hcd->state)) if (!HC_IS_RUNNING(hcd->state))
return -ESHUTDOWN; return -ESHUTDOWN;
ports = isp116x->rhdesca & RH_A_NDP; /* Report no status change now, if we are scheduled to be
called later */
if (timer_pending(&hcd->rh_timer))
return 0;
/* init status */ ports = isp116x->rhdesca & RH_A_NDP;
spin_lock_irqsave(&isp116x->lock, flags);
isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC)) if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))
buf[0] = changed = 1; buf[0] = changed = 1;
else else
buf[0] = 0; buf[0] = 0;
for (i = 0; i < ports; i++) { for (i = 0; i < ports; i++) {
u32 status = isp116x->rhport[i]; u32 status = isp116x->rhport[i] =
isp116x_read_reg32(isp116x, i ? HCRHPORT2 : HCRHPORT1);
if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
| RH_PS_OCIC | RH_PS_PRSC)) { | RH_PS_OCIC | RH_PS_PRSC)) {
@ -947,6 +952,7 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
continue; continue;
} }
} }
spin_unlock_irqrestore(&isp116x->lock, flags);
return changed; return changed;
} }
@ -1536,6 +1542,9 @@ static int isp116x_start(struct usb_hcd *hcd)
return -ENODEV; return -ENODEV;
} }
/* To be removed in future */
hcd->uses_new_polling = 1;
isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE); isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE); isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);