Commit 46eb8948 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/linux/linux/BK/bleeding-2.5

into kroah.com:/home/linux/linux/BK/gregkh-2.5
parents 114d2a8e 414ca09c
...@@ -239,18 +239,14 @@ extern __inline__ struct async *async_getpending(struct dev_state *ps, void *use ...@@ -239,18 +239,14 @@ extern __inline__ struct async *async_getpending(struct dev_state *ps, void *use
{ {
unsigned long flags; unsigned long flags;
struct async *as; struct async *as;
struct list_head *p;
spin_lock_irqsave(&ps->lock, flags); spin_lock_irqsave(&ps->lock, flags);
for (p = ps->async_pending.next; p != &ps->async_pending; ) { list_for_each_entry(as, &ps->async_pending, asynclist)
as = list_entry(p, struct async, asynclist); if (as->userurb == userurb) {
p = p->next; list_del_init(&as->asynclist);
if (as->userurb != userurb) spin_unlock_irqrestore(&ps->lock, flags);
continue; return as;
list_del_init(&as->asynclist); }
spin_unlock_irqrestore(&ps->lock, flags);
return as;
}
spin_unlock_irqrestore(&ps->lock, flags); spin_unlock_irqrestore(&ps->lock, flags);
return NULL; return NULL;
} }
...@@ -295,19 +291,14 @@ static void destroy_async (struct dev_state *ps, struct list_head *list) ...@@ -295,19 +291,14 @@ static void destroy_async (struct dev_state *ps, struct list_head *list)
static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf) static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf)
{ {
struct async *as; struct list_head *p, *q, hitlist;
struct list_head *p, hitlist;
unsigned long flags; unsigned long flags;
INIT_LIST_HEAD(&hitlist); INIT_LIST_HEAD(&hitlist);
spin_lock_irqsave(&ps->lock, flags); spin_lock_irqsave(&ps->lock, flags);
for (p = ps->async_pending.next; p != &ps->async_pending; ) { list_for_each_safe(p, q, &ps->async_pending)
as = list_entry(p, struct async, asynclist); if (intf == list_entry(p, struct async, asynclist)->intf)
p = p->next; list_move_tail(p, &hitlist);
if (as->intf == intf)
list_move_tail(&as->asynclist, &hitlist);
}
spin_unlock_irqrestore(&ps->lock, flags); spin_unlock_irqrestore(&ps->lock, flags);
destroy_async(ps, &hitlist); destroy_async(ps, &hitlist);
} }
...@@ -869,7 +860,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg) ...@@ -869,7 +860,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg)
if (uurb.buffer_length > 16384) if (uurb.buffer_length > 16384)
return -EINVAL; return -EINVAL;
if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
return -EFAULT; return -EFAULT;
break; break;
default: default:
...@@ -964,10 +955,10 @@ static int processcompl(struct async *as) ...@@ -964,10 +955,10 @@ static int processcompl(struct async *as)
if (!(usb_pipeisoc(urb->pipe))) if (!(usb_pipeisoc(urb->pipe)))
return 0; return 0;
for (i = 0; i < urb->number_of_packets; i++) { for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length, if (put_user(urb->iso_frame_desc[i].actual_length,
&((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length)) &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length))
return -EFAULT; return -EFAULT;
if (put_user(urb->iso_frame_desc[i].status, if (put_user(urb->iso_frame_desc[i].status,
&((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status)) &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
return -EFAULT; return -EFAULT;
} }
...@@ -1099,12 +1090,10 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1099,12 +1090,10 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
else switch (ctrl.ioctl_code) { else switch (ctrl.ioctl_code) {
/* disconnect kernel driver from interface, leaving it unbound. */ /* disconnect kernel driver from interface, leaving it unbound. */
/* maybe unbound - you get no guarantee it stays unbound */
case USBDEVFS_DISCONNECT: case USBDEVFS_DISCONNECT:
/* this function is voodoo. */ /* this function is misdesigned - retained for compatibility */
/* which function ... usb_device_remove()? lock_kernel();
* FIXME either the module lock (BKL) should be involved
* here too, or the 'default' case below is broken
*/
driver = ifp->driver; driver = ifp->driver;
if (driver) { if (driver) {
dbg ("disconnect '%s' from dev %d interface %d", dbg ("disconnect '%s' from dev %d interface %d",
...@@ -1112,11 +1101,14 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1112,11 +1101,14 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
usb_device_remove(&ifp->dev); usb_device_remove(&ifp->dev);
} else } else
retval = -ENODATA; retval = -ENODATA;
unlock_kernel();
break; break;
/* let kernel drivers try to (re)bind to the interface */ /* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT: case USBDEVFS_CONNECT:
lock_kernel();
retval = usb_device_probe (&ifp->dev); retval = usb_device_probe (&ifp->dev);
unlock_kernel();
break; break;
/* talk directly to the interface's driver */ /* talk directly to the interface's driver */
...@@ -1131,20 +1123,17 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1131,20 +1123,17 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
unlock_kernel(); unlock_kernel();
retval = -ENOSYS; retval = -ENOSYS;
} else { } else {
if (driver->owner if (!try_module_get (driver->owner)) {
&& !try_inc_mod_count (driver->owner)) {
unlock_kernel(); unlock_kernel();
retval = -ENOSYS; retval = -ENOSYS;
break; break;
} }
unlock_kernel (); unlock_kernel ();
retval = driver->ioctl (ifp, ctrl.ioctl_code, buf); retval = driver->ioctl (ifp, ctrl.ioctl_code, buf);
if (driver->owner) if (retval == -ENOIOCTLCMD)
__MOD_DEC_USE_COUNT (driver->owner); retval = -ENOTTY;
module_put (driver->owner);
} }
if (retval == -ENOIOCTLCMD)
retval = -ENOTTY;
} }
/* cleanup and return */ /* cleanup and return */
...@@ -1197,7 +1186,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -1197,7 +1186,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case USBDEVFS_RESET: case USBDEVFS_RESET:
ret = proc_resetdevice(ps); ret = proc_resetdevice(ps);
break; break;
case USBDEVFS_CLEAR_HALT: case USBDEVFS_CLEAR_HALT:
ret = proc_clearhalt(ps, (void *)arg); ret = proc_clearhalt(ps, (void *)arg);
if (ret >= 0) if (ret >= 0)
......
...@@ -146,7 +146,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -146,7 +146,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
goto clean_2; goto clean_2;
} }
info ("%s @ %s, %s", hcd->description, dev->slot_name, dev->dev.name); dev_info (*hcd->controller, "%s\n", hcd->product_desc);
#ifndef __sparc__ #ifndef __sparc__
sprintf (buf, "%d", dev->irq); sprintf (buf, "%d", dev->irq);
...@@ -155,7 +155,8 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -155,7 +155,8 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
#endif #endif
if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd) if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd)
!= 0) { != 0) {
err ("request interrupt %s failed", bufp); dev_err (*hcd->controller,
"request interrupt %s failed\n", bufp);
retval = -EBUSY; retval = -EBUSY;
goto clean_3; goto clean_3;
} }
...@@ -163,7 +164,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -163,7 +164,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
hcd->regs = base; hcd->regs = base;
hcd->region = region; hcd->region = region;
info ("irq %s, %s %p", bufp, dev_info (*hcd->controller, "irq %s, %s %p\n", bufp,
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base", (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
base); base);
...@@ -205,19 +206,20 @@ void usb_hcd_pci_remove (struct pci_dev *dev) ...@@ -205,19 +206,20 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
if (!hcd) if (!hcd)
return; return;
info ("remove: %s, state %x", hcd->self.bus_name, hcd->state); dev_info (*hcd->controller, "remove, state %x\n", hcd->state);
if (in_interrupt ()) BUG (); if (in_interrupt ()) BUG ();
hub = hcd->self.root_hub; hub = hcd->self.root_hub;
hcd->state = USB_STATE_QUIESCING; hcd->state = USB_STATE_QUIESCING;
dbg ("%s: roothub graceful disconnect", hcd->self.bus_name); dev_dbg (*hcd->controller, "roothub graceful disconnect\n");
usb_disconnect (&hub); usb_disconnect (&hub);
hcd->driver->stop (hcd); hcd->driver->stop (hcd);
hcd_buffer_destroy (hcd); hcd_buffer_destroy (hcd);
hcd->state = USB_STATE_HALT; hcd->state = USB_STATE_HALT;
pci_set_drvdata (dev, 0);
free_irq (hcd->irq, hcd); free_irq (hcd->irq, hcd);
if (hcd->driver->flags & HCD_MEMORY) { if (hcd->driver->flags & HCD_MEMORY) {
...@@ -230,9 +232,12 @@ void usb_hcd_pci_remove (struct pci_dev *dev) ...@@ -230,9 +232,12 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
} }
usb_deregister_bus (&hcd->self); usb_deregister_bus (&hcd->self);
if (atomic_read (&hcd->self.refcnt) != 1) if (atomic_read (&hcd->self.refcnt) != 1) {
err ("usb_hcd_pci_remove %s, count != 1", hcd->self.bus_name); dev_warn (*hcd->controller,
"dangling refs (%d) to bus %d!\n",
atomic_read (&hcd->self.refcnt) - 1,
hcd->self.busnum);
}
hcd->driver->hcd_free (hcd); hcd->driver->hcd_free (hcd);
} }
EXPORT_SYMBOL (usb_hcd_pci_remove); EXPORT_SYMBOL (usb_hcd_pci_remove);
...@@ -279,7 +284,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) ...@@ -279,7 +284,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
int retval; int retval;
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
info ("suspend %s to state %d", hcd->self.bus_name, state); dev_info (*hcd->controller, "suspend to state %d\n", state);
pci_save_state (dev, hcd->pci_state); pci_save_state (dev, hcd->pci_state);
...@@ -308,19 +313,19 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -308,19 +313,19 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
int retval; int retval;
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
info ("resume %s", hcd->self.bus_name); dev_info (*hcd->controller, "resume\n");
/* guard against multiple resumes (APM bug?) */ /* guard against multiple resumes (APM bug?) */
atomic_inc (&hcd->resume_count); atomic_inc (&hcd->resume_count);
if (atomic_read (&hcd->resume_count) != 1) { if (atomic_read (&hcd->resume_count) != 1) {
err ("concurrent PCI resumes for %s", hcd->self.bus_name); dev_err (*hcd->controller, "concurrent PCI resumes\n");
retval = 0; retval = 0;
goto done; goto done;
} }
retval = -EBUSY; retval = -EBUSY;
if (hcd->state != USB_STATE_SUSPENDED) { if (hcd->state != USB_STATE_SUSPENDED) {
dbg ("can't resume, not suspended!"); dev_dbg (*hcd->controller, "can't resume, not suspended!\n");
goto done; goto done;
} }
hcd->state = USB_STATE_RESUMING; hcd->state = USB_STATE_RESUMING;
...@@ -330,7 +335,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -330,7 +335,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
retval = hcd->driver->resume (hcd); retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) { if (!HCD_IS_RUNNING (hcd->state)) {
dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval); dev_dbg (*hcd->controller, "resume fail, retval %d\n", retval);
usb_hc_died (hcd); usb_hc_died (hcd);
// FIXME: recover, reset etc. // FIXME: recover, reset etc.
} else { } else {
......
...@@ -715,7 +715,8 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev ...@@ -715,7 +715,8 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum); sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum);
retval = usb_new_device (usb_dev, parent_dev); retval = usb_new_device (usb_dev, parent_dev);
if (retval) if (retval)
err("%s - usb_new_device failed with value %d", __FUNCTION__, retval); dev_err (*parent_dev, "can't register root hub for %s, %d\n",
usb_dev->dev.bus_id, retval);
return retval; return retval;
} }
EXPORT_SYMBOL (usb_register_root_hub); EXPORT_SYMBOL (usb_register_root_hub);
...@@ -1286,13 +1287,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) ...@@ -1286,13 +1287,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
// NOTE: a generic device/urb monitoring hook would go here. // NOTE: a generic device/urb monitoring hook would go here.
// hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
// It would catch exit/unlink paths for all urbs, but non-exit // It would catch exit/unlink paths for all urbs.
// completions for periodic urbs need hooks inside the HCD.
// hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
if (urb->status)
dbg ("giveback urb %p status %d len %d",
urb, urb->status, urb->actual_length);
/* lower level hcd code should use *_dma exclusively */ /* lower level hcd code should use *_dma exclusively */
if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
......
...@@ -69,24 +69,23 @@ static struct device_driver usb_generic_driver = { ...@@ -69,24 +69,23 @@ static struct device_driver usb_generic_driver = {
.probe = generic_probe, .probe = generic_probe,
.remove = generic_remove, .remove = generic_remove,
}; };
/* needs to be called with BKL held */
int usb_device_probe(struct device *dev) int usb_device_probe(struct device *dev)
{ {
struct usb_interface * intf = to_usb_interface(dev); struct usb_interface * intf = to_usb_interface(dev);
struct usb_driver * driver = to_usb_driver(dev->driver); struct usb_driver * driver = to_usb_driver(dev->driver);
const struct usb_device_id *id; const struct usb_device_id *id;
int error = -ENODEV; int error = -ENODEV;
int m;
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
if (!driver->probe) if (!driver->probe)
return error; return error;
if (driver->owner) { if (!try_module_get(driver->owner)) {
m = try_inc_mod_count(driver->owner); err ("Can't get a module reference for %s", driver->name);
if (m == 0) return error;
return error;
} }
id = usb_match_id (intf, driver->id_table); id = usb_match_id (intf, driver->id_table);
...@@ -99,8 +98,7 @@ int usb_device_probe(struct device *dev) ...@@ -99,8 +98,7 @@ int usb_device_probe(struct device *dev)
if (!error) if (!error)
intf->driver = driver; intf->driver = driver;
if (driver->owner) module_put(driver->owner);
__MOD_DEC_USE_COUNT(driver->owner);
return error; return error;
} }
...@@ -109,7 +107,6 @@ int usb_device_remove(struct device *dev) ...@@ -109,7 +107,6 @@ int usb_device_remove(struct device *dev)
{ {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_driver *driver; struct usb_driver *driver;
int m;
intf = list_entry(dev,struct usb_interface,dev); intf = list_entry(dev,struct usb_interface,dev);
driver = to_usb_driver(dev->driver); driver = to_usb_driver(dev->driver);
...@@ -120,14 +117,11 @@ int usb_device_remove(struct device *dev) ...@@ -120,14 +117,11 @@ int usb_device_remove(struct device *dev)
return -ENODEV; return -ENODEV;
} }
if (driver->owner) { if (!try_module_get(driver->owner)) {
m = try_inc_mod_count(driver->owner); // FIXME this happens even when we just rmmod
if (m == 0) { // drivers that aren't in active use...
// FIXME this happens even when we just rmmod err("Dieing driver still bound to device.\n");
// drivers that aren't in active use... return -EIO;
err("Dieing driver still bound to device.\n");
return -EIO;
}
} }
/* if we sleep here on an umanaged driver /* if we sleep here on an umanaged driver
...@@ -143,8 +137,7 @@ int usb_device_remove(struct device *dev) ...@@ -143,8 +137,7 @@ int usb_device_remove(struct device *dev)
usb_driver_release_interface(driver, intf); usb_driver_release_interface(driver, intf);
up(&driver->serialize); up(&driver->serialize);
if (driver->owner) module_put(driver->owner);
__MOD_DEC_USE_COUNT(driver->owner);
return 0; return 0;
} }
......
...@@ -18,6 +18,17 @@ ...@@ -18,6 +18,17 @@
/* this file is part of ehci-hcd.c */ /* this file is part of ehci-hcd.c */
#define ehci_dbg(ehci, fmt, args...) \
dev_dbg (*(ehci)->hcd.controller, fmt, ## args )
#ifdef EHCI_VERBOSE_DEBUG
#define ehci_vdbg(ehci, fmt, args...) \
dev_dbg (*(ehci)->hcd.controller, fmt, ## args )
#else
#define ehci_vdbg(ehci, fmt, args...) do { } while (0)
#endif
#ifdef EHCI_VERBOSE_DEBUG #ifdef EHCI_VERBOSE_DEBUG
# define vdbg dbg # define vdbg dbg
#else #else
...@@ -34,7 +45,8 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) ...@@ -34,7 +45,8 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
{ {
u32 params = readl (&ehci->caps->hcs_params); u32 params = readl (&ehci->caps->hcs_params);
dbg ("%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d", ehci_dbg (ehci,
"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
label, params, label, params,
HCS_DEBUG_PORT (params), HCS_DEBUG_PORT (params),
HCS_INDICATOR (params) ? " ind" : "", HCS_INDICATOR (params) ? " ind" : "",
...@@ -56,9 +68,8 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) ...@@ -56,9 +68,8 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf))); ((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
strcat(buf, tmp); strcat(buf, tmp);
} }
dbg ("%s: %s portroute %s", ehci_dbg (ehci, "%s portroute %s\n",
hcd_to_bus (&ehci->hcd)->bus_name, label, label, buf);
buf);
} }
} }
#else #else
...@@ -77,19 +88,16 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) ...@@ -77,19 +88,16 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
{ {
u32 params = readl (&ehci->caps->hcc_params); u32 params = readl (&ehci->caps->hcc_params);
if (HCC_EXT_CAPS (params)) {
// EHCI 0.96 ... could interpret these (legacy?)
dbg ("%s extended capabilities at pci %2x",
label, HCC_EXT_CAPS (params));
}
if (HCC_ISOC_CACHE (params)) { if (HCC_ISOC_CACHE (params)) {
dbg ("%s hcc_params %04x caching frame %s%s%s", ehci_dbg (ehci,
"%s hcc_params %04x caching frame %s%s%s\n",
label, params, label, params,
HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024", HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
HCC_CANPARK (params) ? " park" : "", HCC_CANPARK (params) ? " park" : "",
HCC_64BIT_ADDR (params) ? " 64 bit addr" : ""); HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
} else { } else {
dbg ("%s hcc_params %04x caching %d uframes %s%s%s", ehci_dbg (ehci,
"%s hcc_params %04x thresh %d uframes %s%s%s\n",
label, label,
params, params,
HCC_ISOC_THRES (params), HCC_ISOC_THRES (params),
...@@ -235,19 +243,19 @@ dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status) ...@@ -235,19 +243,19 @@ dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
#define dbg_status(ehci, label, status) { \ #define dbg_status(ehci, label, status) { \
char _buf [80]; \ char _buf [80]; \
dbg_status_buf (_buf, sizeof _buf, label, status); \ dbg_status_buf (_buf, sizeof _buf, label, status); \
dbg ("%s", _buf); \ ehci_dbg (ehci, "%s\n", _buf); \
} }
#define dbg_cmd(ehci, label, command) { \ #define dbg_cmd(ehci, label, command) { \
char _buf [80]; \ char _buf [80]; \
dbg_command_buf (_buf, sizeof _buf, label, command); \ dbg_command_buf (_buf, sizeof _buf, label, command); \
dbg ("%s", _buf); \ ehci_dbg (ehci, "%s\n", _buf); \
} }
#define dbg_port(hcd, label, port, status) { \ #define dbg_port(ehci, label, port, status) { \
char _buf [80]; \ char _buf [80]; \
dbg_port_buf (_buf, sizeof _buf, label, port, status); \ dbg_port_buf (_buf, sizeof _buf, label, port, status); \
dbg ("%s", _buf); \ ehci_dbg (ehci, "%s\n", _buf); \
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -338,12 +346,8 @@ show_async (struct device *dev, char *buf, size_t count, loff_t off) ...@@ -338,12 +346,8 @@ show_async (struct device *dev, char *buf, size_t count, loff_t off)
* one QH per line, and TDs we know about * one QH per line, and TDs we know about
*/ */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
if (ehci->async) { for (qh = ehci->async->qh_next.qh; qh; qh = qh->qh_next.qh)
qh = ehci->async; qh_lines (qh, &next, &size);
do {
qh_lines (qh, &next, &size);
} while ((qh = qh->qh_next.qh) != ehci->async);
}
if (ehci->reclaim) { if (ehci->reclaim) {
temp = snprintf (next, size, "\nreclaim =\n"); temp = snprintf (next, size, "\nreclaim =\n");
size -= temp; size -= temp;
......
...@@ -17,6 +17,13 @@ ...@@ -17,6 +17,13 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -31,12 +38,6 @@ ...@@ -31,12 +38,6 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/version.h> #include <linux/version.h>
...@@ -70,6 +71,7 @@ ...@@ -70,6 +71,7 @@
* *
* HISTORY: * HISTORY:
* *
* 2002-11-29 Correct handling for hw async_next register.
* 2002-08-06 Handling for bulk and interrupt transfers is mostly shared; * 2002-08-06 Handling for bulk and interrupt transfers is mostly shared;
* only scheduling is different, no arbitrary limitations. * only scheduling is different, no arbitrary limitations.
* 2002-07-25 Sanity check PCI reads, mostly for better cardbus support, * 2002-07-25 Sanity check PCI reads, mostly for better cardbus support,
...@@ -92,7 +94,7 @@ ...@@ -92,7 +94,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4 * 2001-June Works with usb-storage and NEC EHCI on 2.4
*/ */
#define DRIVER_VERSION "2002-Sep-23" #define DRIVER_VERSION "2002-Nov-29"
#define DRIVER_AUTHOR "David Brownell" #define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
...@@ -114,7 +116,7 @@ static const char hcd_name [] = "ehci-hcd"; ...@@ -114,7 +116,7 @@ static const char hcd_name [] = "ehci-hcd";
#define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_MULT_TT 1
#define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ #define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
#define EHCI_ASYNC_JIFFIES (HZ/3) /* async idle timeout */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
/* Initial IRQ latency: lower than default */ /* Initial IRQ latency: lower than default */
static int log2_irq_thresh = 0; // 0 to 6 static int log2_irq_thresh = 0; // 0 to 6
...@@ -215,7 +217,7 @@ static void ehci_ready (struct ehci_hcd *ehci) ...@@ -215,7 +217,7 @@ static void ehci_ready (struct ehci_hcd *ehci)
/* wait for any schedule enables/disables to take effect */ /* wait for any schedule enables/disables to take effect */
temp = 0; temp = 0;
if (ehci->async) if (ehci->async->qh_next.qh)
temp = STS_ASS; temp = STS_ASS;
if (ehci->next_uframe != -1) if (ehci->next_uframe != -1)
temp |= STS_PSS; temp |= STS_PSS;
...@@ -260,7 +262,7 @@ static void ehci_watchdog (unsigned long param) ...@@ -260,7 +262,7 @@ static void ehci_watchdog (unsigned long param)
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
/* guard against lost IAA, which wedges everything */ /* guard against lost IAA, which wedges everything */
ehci_irq (&ehci->hcd); ehci_irq (&ehci->hcd);
/* unlink the last qh after it's idled a while */ /* stop async processing after it's idled a while */
if (ehci->async_idle) { if (ehci->async_idle) {
start_unlink_async (ehci, ehci->async); start_unlink_async (ehci, ehci->async);
ehci->async_idle = 0; ehci->async_idle = 0;
...@@ -287,12 +289,13 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) ...@@ -287,12 +289,13 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
pci_read_config_dword (ehci->hcd.pdev, where, &cap); pci_read_config_dword (ehci->hcd.pdev, where, &cap);
} while ((cap & (1 << 16)) && msec); } while ((cap & (1 << 16)) && msec);
if (cap & (1 << 16)) { if (cap & (1 << 16)) {
info ("BIOS handoff failed (%d, %04x)", where, cap); dev_info (*ehci->hcd.controller,
"BIOS handoff failed (%d, %04x)\n",
where, cap);
return 1; return 1;
} }
dbg ("BIOS handoff succeeded"); ehci_dbg (ehci, "BIOS handoff succeeded\n");
} else }
dbg ("BIOS handoff not needed");
return 0; return 0;
} }
...@@ -323,14 +326,15 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -323,14 +326,15 @@ static int ehci_start (struct usb_hcd *hcd)
u32 cap; u32 cap;
pci_read_config_dword (ehci->hcd.pdev, temp, &cap); pci_read_config_dword (ehci->hcd.pdev, temp, &cap);
dbg ("capability %04x at %02x", cap, temp); ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
switch (cap & 0xff) { switch (cap & 0xff) {
case 1: /* BIOS/SMM/... handoff */ case 1: /* BIOS/SMM/... handoff */
if (bios_handoff (ehci, temp, cap) != 0) if (bios_handoff (ehci, temp, cap) != 0)
return -EOPNOTSUPP; return -EOPNOTSUPP;
break; break;
case 0: /* illegal reserved capability */ case 0: /* illegal reserved capability */
warn ("illegal capability!"); dev_warn (*ehci->hcd.controller,
"illegal capability!\n");
cap = 0; cap = 0;
/* FALLTHROUGH */ /* FALLTHROUGH */
default: /* unknown */ default: /* unknown */
...@@ -360,7 +364,6 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -360,7 +364,6 @@ static int ehci_start (struct usb_hcd *hcd)
else // N microframes cached else // N microframes cached
ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params); ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
ehci->async = 0;
ehci->reclaim = 0; ehci->reclaim = 0;
ehci->next_uframe = -1; ehci->next_uframe = -1;
...@@ -374,6 +377,21 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -374,6 +377,21 @@ static int ehci_start (struct usb_hcd *hcd)
writel (INTR_MASK, &ehci->regs->intr_enable); writel (INTR_MASK, &ehci->regs->intr_enable);
writel (ehci->periodic_dma, &ehci->regs->frame_list); writel (ehci->periodic_dma, &ehci->regs->frame_list);
/*
* dedicate a qh for the async ring head, since we couldn't unlink
* a 'real' qh without stopping the async schedule [4.8]. use it
* as the 'reclamation list head' too.
*/
ehci->async->qh_next.qh = 0;
ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma);
ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD);
ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT);
ehci->async->hw_qtd_next = EHCI_LIST_END;
ehci->async->qh_state = QH_STATE_LINKED;
ehci_qtd_free (ehci, ehci->async->dummy);
ehci->async->dummy = 0;
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
/* /*
* hcc_params controls whether ehci->regs->segment must (!!!) * hcc_params controls whether ehci->regs->segment must (!!!)
* be used; it constrains QH/ITD/SITD and QTD locations. * be used; it constrains QH/ITD/SITD and QTD locations.
...@@ -388,7 +406,8 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -388,7 +406,8 @@ static int ehci_start (struct usb_hcd *hcd)
if (HCC_64BIT_ADDR (hcc_params)) { if (HCC_64BIT_ADDR (hcc_params)) {
writel (0, &ehci->regs->segment); writel (0, &ehci->regs->segment);
if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL)) if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL))
info ("enabled 64bit PCI DMA (DAC)"); dev_info (*ehci->hcd.controller,
"enabled 64bit PCI DMA (DAC)\n");
} }
/* clear interrupt enables, set irq latency */ /* clear interrupt enables, set irq latency */
...@@ -435,10 +454,10 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -435,10 +454,10 @@ static int ehci_start (struct usb_hcd *hcd)
/* PCI Serial Bus Release Number is at 0x60 offset */ /* PCI Serial Bus Release Number is at 0x60 offset */
pci_read_config_byte (hcd->pdev, 0x60, &tempbyte); pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
temp = readw (&ehci->caps->hci_version); temp = readw (&ehci->caps->hci_version);
info ("USB %x.%x support enabled, EHCI rev %x.%02x, %s %s", dev_info (*hcd->controller,
((tempbyte & 0xf0)>>4), (tempbyte & 0x0f), "USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
temp >> 8, temp & 0xff, ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
hcd_name, DRIVER_VERSION); temp >> 8, temp & 0xff, DRIVER_VERSION);
/* /*
* From here on, khubd concurrently accesses the root * From here on, khubd concurrently accesses the root
...@@ -470,13 +489,13 @@ static void ehci_stop (struct usb_hcd *hcd) ...@@ -470,13 +489,13 @@ static void ehci_stop (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
dbg ("%s: stop", hcd_to_bus (hcd)->bus_name); ehci_dbg (ehci, "stop\n");
/* no more interrupts ... */ /* no more interrupts ... */
if (hcd->state == USB_STATE_RUNNING) if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci); ehci_ready (ehci);
if (in_interrupt ()) /* should not happen!! */ if (in_interrupt ()) /* should not happen!! */
err ("stopped %s!", RUN_CONTEXT); dev_err (*hcd->controller, "stopped %s!\n", RUN_CONTEXT);
else else
del_timer_sync (&ehci->watchdog); del_timer_sync (&ehci->watchdog);
ehci_reset (ehci); ehci_reset (ehci);
...@@ -492,9 +511,9 @@ static void ehci_stop (struct usb_hcd *hcd) ...@@ -492,9 +511,9 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_mem_cleanup (ehci); ehci_mem_cleanup (ehci);
#ifdef EHCI_STATS #ifdef EHCI_STATS
dbg ("irq normal %ld err %ld reclaim %ld", ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim); ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
dbg ("complete %ld unlink %ld", ehci_dbg (ehci, "complete %ld unlink %ld\n",
ehci->stats.complete, ehci->stats.unlink); ehci->stats.complete, ehci->stats.unlink);
#endif #endif
...@@ -738,8 +757,8 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -738,8 +757,8 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
unsigned long flags; unsigned long flags;
dbg ("%s urb_dequeue %p qh %p state %d", ehci_vdbg (ehci, "urb_dequeue %p qh %p state %d\n",
hcd_to_bus (hcd)->bus_name, urb, qh, qh->qh_state); urb, qh, qh->qh_state);
switch (usb_pipetype (urb->pipe)) { switch (usb_pipetype (urb->pipe)) {
// case PIPE_CONTROL: // case PIPE_CONTROL:
...@@ -982,7 +1001,6 @@ MODULE_LICENSE ("GPL"); ...@@ -982,7 +1001,6 @@ MODULE_LICENSE ("GPL");
static int __init init (void) static int __init init (void)
{ {
dbg (DRIVER_INFO);
if (usb_disabled()) if (usb_disabled())
return -ENODEV; return -ENODEV;
......
...@@ -40,18 +40,15 @@ static int check_reset_complete ( ...@@ -40,18 +40,15 @@ static int check_reset_complete (
/* if reset finished and it's still not enabled -- handoff */ /* if reset finished and it's still not enabled -- handoff */
if (!(port_status & PORT_PE)) { if (!(port_status & PORT_PE)) {
dbg ("%s port %d full speed, give to companion, 0x%x", ehci_dbg (ehci, "port %d full speed --> companion\n",
hcd_to_bus (&ehci->hcd)->bus_name, index + 1);
index + 1, port_status);
// what happens if HCS_N_CC(params) == 0 ? // what happens if HCS_N_CC(params) == 0 ?
port_status |= PORT_OWNER; port_status |= PORT_OWNER;
writel (port_status, &ehci->regs->port_status [index]); writel (port_status, &ehci->regs->port_status [index]);
} else } else
dbg ("%s port %d high speed", ehci_dbg (ehci, "port %d high speed\n", index + 1);
hcd_to_bus (&ehci->hcd)->bus_name,
index + 1);
return port_status; return port_status;
} }
...@@ -277,7 +274,7 @@ static int ehci_hub_control ( ...@@ -277,7 +274,7 @@ static int ehci_hub_control (
#ifndef EHCI_VERBOSE_DEBUG #ifndef EHCI_VERBOSE_DEBUG
if (status & ~0xffff) /* only if wPortChange is interesting */ if (status & ~0xffff) /* only if wPortChange is interesting */
#endif #endif
dbg_port (hcd, "GetStatus", wIndex + 1, temp); dbg_port (ehci, "GetStatus", wIndex + 1, temp);
// we "know" this alignment is good, caller used kmalloc()... // we "know" this alignment is good, caller used kmalloc()...
*((u32 *) buf) = cpu_to_le32 (status); *((u32 *) buf) = cpu_to_le32 (status);
break; break;
...@@ -313,14 +310,12 @@ static int ehci_hub_control ( ...@@ -313,14 +310,12 @@ static int ehci_hub_control (
/* line status bits may report this as low speed */ /* line status bits may report this as low speed */
if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
&& PORT_USB11 (temp)) { && PORT_USB11 (temp)) {
dbg ("%s port %d low speed, give to companion", ehci_dbg (ehci,
hcd_to_bus (&ehci->hcd)->bus_name, "port %d low speed --> companion\n",
wIndex + 1); wIndex + 1);
temp |= PORT_OWNER; temp |= PORT_OWNER;
} else { } else {
vdbg ("%s port %d reset", ehci_vdbg (ehci, "port %d reset", wIndex + 1);
hcd_to_bus (&ehci->hcd)->bus_name,
wIndex + 1);
temp |= PORT_RESET; temp |= PORT_RESET;
temp &= ~PORT_PE; temp &= ~PORT_PE;
......
...@@ -103,7 +103,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) ...@@ -103,7 +103,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
/* dummy td enables safe urb queuing */ /* dummy td enables safe urb queuing */
qh->dummy = ehci_qtd_alloc (ehci, flags); qh->dummy = ehci_qtd_alloc (ehci, flags);
if (qh->dummy == 0) { if (qh->dummy == 0) {
dbg ("no dummy td"); ehci_dbg (ehci, "no dummy td\n");
pci_pool_free (ehci->qh_pool, qh, qh->qh_dma); pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
qh = 0; qh = 0;
} }
...@@ -113,19 +113,17 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) ...@@ -113,19 +113,17 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
/* to share a qh (cpu threads, or hc) */ /* to share a qh (cpu threads, or hc) */
static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh) static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh)
{ {
// dbg ("get %p (%d++)", qh, qh->refcount.counter);
atomic_inc (&qh->refcount); atomic_inc (&qh->refcount);
return qh; return qh;
} }
static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh) static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
// dbg ("put %p (--%d)", qh, qh->refcount.counter);
if (!atomic_dec_and_test (&qh->refcount)) if (!atomic_dec_and_test (&qh->refcount))
return; return;
/* clean qtds first, and know this is not linked */ /* clean qtds first, and know this is not linked */
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
dbg ("unused qh not empty!"); ehci_dbg (ehci, "unused qh not empty!\n");
BUG (); BUG ();
} }
if (qh->dummy) if (qh->dummy)
...@@ -142,6 +140,10 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -142,6 +140,10 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
static void ehci_mem_cleanup (struct ehci_hcd *ehci) static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{ {
if (ehci->async)
qh_put (ehci, ehci->async);
ehci->async = 0;
/* PCI consistent memory and pools */ /* PCI consistent memory and pools */
if (ehci->qtd_pool) if (ehci->qtd_pool)
pci_pool_destroy (ehci->qtd_pool); pci_pool_destroy (ehci->qtd_pool);
...@@ -183,20 +185,20 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -183,20 +185,20 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
if (!ehci->qtd_pool) { if (!ehci->qtd_pool) {
dbg ("no qtd pool"); goto fail;
ehci_mem_cleanup (ehci);
return -ENOMEM;
} }
/* QH for control/bulk/intr transfers */ /* QHs for control/bulk/intr transfers */
ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev, ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev,
sizeof (struct ehci_qh), sizeof (struct ehci_qh),
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
if (!ehci->qh_pool) { if (!ehci->qh_pool) {
dbg ("no qh pool"); goto fail;
ehci_mem_cleanup (ehci); }
return -ENOMEM; ehci->async = ehci_qh_alloc (ehci, flags);
if (!ehci->async) {
goto fail;
} }
/* ITD for high speed ISO transfers */ /* ITD for high speed ISO transfers */
...@@ -205,9 +207,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -205,9 +207,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
if (!ehci->itd_pool) { if (!ehci->itd_pool) {
dbg ("no itd pool"); goto fail;
ehci_mem_cleanup (ehci);
return -ENOMEM;
} }
/* SITD for full/low speed split ISO transfers */ /* SITD for full/low speed split ISO transfers */
...@@ -216,9 +216,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -216,9 +216,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
if (!ehci->sitd_pool) { if (!ehci->sitd_pool) {
dbg ("no sitd pool"); goto fail;
ehci_mem_cleanup (ehci);
return -ENOMEM;
} }
/* Hardware periodic table */ /* Hardware periodic table */
...@@ -227,9 +225,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -227,9 +225,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
ehci->periodic_size * sizeof (u32), ehci->periodic_size * sizeof (u32),
&ehci->periodic_dma); &ehci->periodic_dma);
if (ehci->periodic == 0) { if (ehci->periodic == 0) {
dbg ("no hw periodic table"); goto fail;
ehci_mem_cleanup (ehci);
return -ENOMEM;
} }
for (i = 0; i < ehci->periodic_size; i++) for (i = 0; i < ehci->periodic_size; i++)
ehci->periodic [i] = EHCI_LIST_END; ehci->periodic [i] = EHCI_LIST_END;
...@@ -237,11 +233,14 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags) ...@@ -237,11 +233,14 @@ static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
/* software shadow of hardware table */ /* software shadow of hardware table */
ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags); ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
if (ehci->pshadow == 0) { if (ehci->pshadow == 0) {
dbg ("no shadow periodic table"); goto fail;
ehci_mem_cleanup (ehci);
return -ENOMEM;
} }
memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *)); memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
return 0; return 0;
fail:
ehci_dbg (ehci, "couldn't init memory\n");
ehci_mem_cleanup (ehci);
return -ENOMEM;
} }
...@@ -130,8 +130,9 @@ static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token) ...@@ -130,8 +130,9 @@ static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
else /* unknown */ else /* unknown */
urb->status = -EPROTO; urb->status = -EPROTO;
dbg ("ep %d-%s qtd token %08x --> status %d", ehci_vdbg (ehci,
/* devpath */ "dev%d ep%d%s qtd token %08x --> status %d\n",
usb_pipedev (urb->pipe),
usb_pipeendpoint (urb->pipe), usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out", usb_pipein (urb->pipe) ? "in" : "out",
token, urb->status); token, urb->status);
...@@ -678,33 +679,33 @@ ehci_qh_make ( ...@@ -678,33 +679,33 @@ ehci_qh_make (
static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
u32 dma = QH_NEXT (qh->qh_dma); u32 dma = QH_NEXT (qh->qh_dma);
struct ehci_qh *q; struct ehci_qh *head;
if (unlikely (!(q = ehci->async))) { /* (re)start the async schedule? */
head = ehci->async;
if (ehci->async_idle)
del_timer (&ehci->watchdog);
else if (!head->qh_next.qh) {
u32 cmd = readl (&ehci->regs->command); u32 cmd = readl (&ehci->regs->command);
/* in case a clear of CMD_ASE didn't take yet */ if (!(cmd & CMD_ASE)) {
(void) handshake (&ehci->regs->status, STS_ASS, 0, 150); /* in case a clear of CMD_ASE didn't take yet */
(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */ cmd |= CMD_ASE | CMD_RUN;
qh->qh_next.qh = qh; writel (cmd, &ehci->regs->command);
qh->hw_next = dma; ehci->hcd.state = USB_STATE_RUNNING;
wmb (); /* posted write need not be known to HC yet ... */
ehci->async = qh; }
writel ((u32)qh->qh_dma, &ehci->regs->async_next);
cmd |= CMD_ASE | CMD_RUN;
writel (cmd, &ehci->regs->command);
ehci->hcd.state = USB_STATE_RUNNING;
/* posted write need not be known to HC yet ... */
} else {
/* splice right after "start" of ring */
qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
qh->qh_next = q->qh_next;
qh->hw_next = q->hw_next;
wmb ();
q->qh_next.qh = qh;
q->hw_next = dma;
} }
/* splice right after start */
qh->qh_next = head->qh_next;
qh->hw_next = head->hw_next;
wmb ();
head->qh_next.qh = qh;
head->hw_next = dma;
qh->qh_state = QH_STATE_LINKED; qh->qh_state = QH_STATE_LINKED;
/* qtd completions reported later by interrupt */ /* qtd completions reported later by interrupt */
...@@ -897,6 +898,14 @@ static void end_unlink_async (struct ehci_hcd *ehci) ...@@ -897,6 +898,14 @@ static void end_unlink_async (struct ehci_hcd *ehci)
qh_link_async (ehci, qh); qh_link_async (ehci, qh);
else else
qh_put (ehci, qh); // refcount from async list qh_put (ehci, qh); // refcount from async list
/* it's not free to turn the async schedule on/off, so we leave it
* active but idle for a while once it empties.
*/
if (!ehci->async->qh_next.qh && !timer_pending (&ehci->watchdog)) {
ehci->async_idle = 1;
mod_timer (&ehci->watchdog, jiffies + EHCI_ASYNC_JIFFIES);
}
} }
/* makes sure the async qh will become idle */ /* makes sure the async qh will become idle */
...@@ -909,7 +918,6 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -909,7 +918,6 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
#ifdef DEBUG #ifdef DEBUG
if (ehci->reclaim if (ehci->reclaim
|| !ehci->async
|| qh->qh_state != QH_STATE_LINKED || qh->qh_state != QH_STATE_LINKED
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
// this macro lies except on SMP compiles // this macro lies except on SMP compiles
...@@ -919,31 +927,20 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -919,31 +927,20 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
BUG (); BUG ();
#endif #endif
qh->qh_state = QH_STATE_UNLINK; /* stop async schedule right now? */
ehci->reclaim = qh = qh_get (qh); if (unlikely (qh == ehci->async)) {
// dbg_qh ("start unlink", ehci, qh);
/* Remove the last QH (qhead)? Stop async schedule first. */
if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
/* can't get here without STS_ASS set */ /* can't get here without STS_ASS set */
if (ehci->hcd.state != USB_STATE_HALT) { if (ehci->hcd.state != USB_STATE_HALT) {
writel (cmd & ~CMD_ASE, &ehci->regs->command); writel (cmd & ~CMD_ASE, &ehci->regs->command);
(void) handshake (&ehci->regs->status, STS_ASS, 0, 150); wmb ();
#if 0 // handshake later, if we need to
// one VT8235 system wants to die with STS_FATAL
// unless this qh is leaked here. others seem ok...
qh = qh_get (qh);
dbg_qh ("async/off", ehci, qh);
#endif
} }
qh->qh_next.qh = ehci->async = 0;
ehci->reclaim_ready = 1;
tasklet_schedule (&ehci->tasklet);
return; return;
} }
qh->qh_state = QH_STATE_UNLINK;
ehci->reclaim = qh = qh_get (qh);
if (unlikely (ehci->hcd.state == USB_STATE_HALT)) { if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
ehci->reclaim_ready = 1; ehci->reclaim_ready = 1;
tasklet_schedule (&ehci->tasklet); tasklet_schedule (&ehci->tasklet);
...@@ -951,13 +948,9 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -951,13 +948,9 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
} }
prev = ehci->async; prev = ehci->async;
while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async) while (prev->qh_next.qh != qh)
prev = prev->qh_next.qh; prev = prev->qh_next.qh;
if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) {
ehci->async = prev;
prev->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD);
}
prev->hw_next = qh->hw_next; prev->hw_next = qh->hw_next;
prev->qh_next = qh->qh_next; prev->qh_next = qh->qh_next;
wmb (); wmb ();
...@@ -979,7 +972,7 @@ scan_async (struct ehci_hcd *ehci) ...@@ -979,7 +972,7 @@ scan_async (struct ehci_hcd *ehci)
unsigned count; unsigned count;
rescan: rescan:
qh = ehci->async; qh = ehci->async->qh_next.qh;
count = 0; count = 0;
if (likely (qh != 0)) { if (likely (qh != 0)) {
do { do {
...@@ -991,25 +984,17 @@ scan_async (struct ehci_hcd *ehci) ...@@ -991,25 +984,17 @@ scan_async (struct ehci_hcd *ehci)
/* concurrent unlink could happen here */ /* concurrent unlink could happen here */
count += qh_completions (ehci, qh); count += qh_completions (ehci, qh);
qh_put (ehci, qh); qh_put (ehci, qh);
goto rescan;
} }
/* unlink idle entries, reducing HC PCI usage as /* unlink idle entries, reducing HC PCI usage as
* well as HCD schedule-scanning costs. removing * well as HCD schedule-scanning costs.
* the last qh is deferred, since it's costly.
* *
* FIXME don't unlink idle entries so quickly; it * FIXME don't unlink idle entries so quickly; it
* can penalize (common) half duplex protocols. * can penalize (common) half duplex protocols.
*/ */
if (list_empty (&qh->qtd_list) && !ehci->reclaim) { if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
if (qh->qh_next.qh != qh) { start_unlink_async (ehci, qh);
// dbg ("irq/empty");
start_unlink_async (ehci, qh);
} else if (!timer_pending (&ehci->watchdog)) {
/* can't use IAA for last entry */
ehci->async_idle = 1;
mod_timer (&ehci->watchdog,
jiffies + EHCI_ASYNC_JIFFIES);
}
} }
/* keep latencies down: let any irqs in */ /* keep latencies down: let any irqs in */
...@@ -1021,8 +1006,6 @@ scan_async (struct ehci_hcd *ehci) ...@@ -1021,8 +1006,6 @@ scan_async (struct ehci_hcd *ehci)
} }
qh = qh->qh_next.qh; qh = qh->qh_next.qh;
if (!qh) /* unlinked? */ } while (qh);
goto rescan;
} while (qh != ehci->async);
} }
} }
...@@ -1051,10 +1051,6 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) ...@@ -1051,10 +1051,6 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
td_error: td_error:
ret = uhci_map_status(status, uhci_packetout(td_token(td))); ret = uhci_map_status(status, uhci_packetout(td_token(td)));
if (ret == -EPIPE)
/* endpoint has stalled - mark it halted */
usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)),
uhci_packetout(td_token(td)));
err: err:
if ((debug == 1 && ret != -EPIPE) || debug > 1) { if ((debug == 1 && ret != -EPIPE) || debug > 1) {
......
...@@ -467,9 +467,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -467,9 +467,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
down (&port->sem); down (&port->sem);
port->tty = tty; port->tty = tty;
/* lock this module before we call it */ /* lock this module before we call it,
if (serial->type->owner) this may, which means we must bail out, safe because we are called with BKL held */
__MOD_INC_USE_COUNT(serial->type->owner); if (!try_module_get(serial->type->owner)) {
retval = -ENODEV;
goto bailout;
}
++port->open_count; ++port->open_count;
if (port->open_count == 1) { if (port->open_count == 1) {
...@@ -481,10 +484,10 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -481,10 +484,10 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
retval = usb_serial_generic_open(port, filp); retval = usb_serial_generic_open(port, filp);
if (retval) { if (retval) {
port->open_count = 0; port->open_count = 0;
if (serial->type->owner) module_put(serial->type->owner);
__MOD_DEC_USE_COUNT(serial->type->owner);
} }
} }
bailout:
up (&port->sem); up (&port->sem);
return retval; return retval;
...@@ -508,8 +511,7 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp) ...@@ -508,8 +511,7 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp)
port->open_count = 0; port->open_count = 0;
} }
if (port->serial->type->owner) module_put(port->serial->type->owner);
__MOD_DEC_USE_COUNT(port->serial->type->owner);
} }
static void serial_close(struct tty_struct *tty, struct file * filp) static void serial_close(struct tty_struct *tty, struct file * filp)
...@@ -899,11 +901,13 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -899,11 +901,13 @@ int usb_serial_probe(struct usb_interface *interface,
/* if this device type has a probe function, call it */ /* if this device type has a probe function, call it */
if (type->probe) { if (type->probe) {
if (type->owner) if (!try_module_get(type->owner)) {
__MOD_INC_USE_COUNT(type->owner); err ("module get failed, exiting");
kfree (serial);
return -EIO;
}
retval = type->probe (serial); retval = type->probe (serial);
if (type->owner) module_put(type->owner);
__MOD_DEC_USE_COUNT(type->owner);
if (retval < 0) { if (retval < 0) {
dbg ("sub driver rejected device"); dbg ("sub driver rejected device");
...@@ -996,11 +1000,13 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -996,11 +1000,13 @@ int usb_serial_probe(struct usb_interface *interface,
if (!num_ports) { if (!num_ports) {
/* if this device type has a calc_num_ports function, call it */ /* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) { if (type->calc_num_ports) {
if (type->owner) if (!try_module_get(type->owner)) {
__MOD_INC_USE_COUNT(type->owner); err ("module get failed, exiting");
kfree (serial);
return -EIO;
}
num_ports = type->calc_num_ports (serial); num_ports = type->calc_num_ports (serial);
if (type->owner) module_put(type->owner);
__MOD_DEC_USE_COUNT(type->owner);
} }
if (!num_ports) if (!num_ports)
num_ports = type->num_ports; num_ports = type->num_ports;
...@@ -1110,11 +1116,12 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1110,11 +1116,12 @@ int usb_serial_probe(struct usb_interface *interface,
/* if this device type has an attach function, call it */ /* if this device type has an attach function, call it */
if (type->attach) { if (type->attach) {
if (type->owner) if (!try_module_get(type->owner)) {
__MOD_INC_USE_COUNT(type->owner); err ("module get failed, exiting");
goto probe_error;
}
retval = type->attach (serial); retval = type->attach (serial);
if (type->owner) module_put(type->owner);
__MOD_DEC_USE_COUNT(type->owner);
if (retval < 0) if (retval < 0)
goto probe_error; goto probe_error;
if (retval > 0) { if (retval > 0) {
......
...@@ -532,8 +532,6 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) ...@@ -532,8 +532,6 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
if (result < 0) if (result < 0)
return result; return result;
printk(KERN_ERR "usb_stor_clear_halt() WORKED!\n");
/* reset the toggles and endpoint flags */ /* reset the toggles and endpoint flags */
usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe),
usb_pipeout(pipe)); usb_pipeout(pipe));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment