Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 312722 Details for
Bug 450786
[Stratus 5.3 bug] kernel NULL pointer dereference at usbdev_read
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Test 3 - ad-hoc history
linux-2.6.18-81.el5-u3.diff (text/plain), 27.55 KB, created by
Pete Zaitcev
on 2008-07-27 05:53:57 UTC
(
hide
)
Description:
Test 3 - ad-hoc history
Filename:
MIME Type:
Creator:
Pete Zaitcev
Created:
2008-07-27 05:53:57 UTC
Size:
27.55 KB
patch
obsolete
>Report NOTIFY_OK on oops only. > >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/core/devio.c linux-2.6.18-81.el5-u/drivers/usb/core/devio.c >--- linux-2.6.18-81.el5/drivers/usb/core/devio.c 2008-02-18 14:51:04.000000000 -0800 >+++ linux-2.6.18-81.el5-u/drivers/usb/core/devio.c 2008-07-26 13:08:10.000000000 -0700 >@@ -128,6 +128,7 @@ static ssize_t usbdev_read(struct file * > loff_t pos; > int i; > >+ xtr_mark(&uxtr, 'r', (unsigned long)ps); > pos = *ppos; > usb_lock_device(dev); > if (!connected(dev)) { >@@ -383,6 +384,7 @@ static void driver_disconnect(struct usb > struct dev_state *ps = usb_get_intfdata (intf); > unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber; > >+ xtr_mark(&uxtr, 'x', (unsigned long)ps); > if (!ps) > return; > >@@ -532,6 +534,8 @@ static struct usb_device *usbdev_lookup_ > } > up(&usb_device_class->sem); > >+ if (dev != NULL && dev->class_dev == NULL) >+ dev = NULL; > return dev; > }; > >@@ -550,13 +554,19 @@ static int usbdev_open(struct inode *ino > ret = -ENOMEM; > if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL))) > goto out; >+ xtr_mark(&uxtr, 'u', (unsigned long)ps); > > ret = -ENOENT; > /* check if we are called from a real node or usbfs */ >- if (imajor(inode) == USB_DEVICE_MAJOR) >+ if (imajor(inode) == USB_DEVICE_MAJOR) { > dev = usbdev_lookup_minor(iminor(inode)); >- if (!dev) >+ xtr_mark(&uxtr, 'a', (unsigned long)dev); >+ } >+ if (!dev) /* Why this is not "else"? */ >+ { > dev = inode->i_private; >+ xtr_mark(&uxtr, 'b', (unsigned long)dev); >+ } > if (!dev) { > kfree(ps); > goto out; >@@ -579,6 +589,7 @@ static int usbdev_open(struct inode *ino > wmb(); > list_add_tail(&ps->list, &dev->filelist); > file->private_data = ps; >+ xtr_mark(&uxtr, 'v', (unsigned long)ps); > out: > mutex_unlock(&usbfs_mutex); > return ret; >@@ -590,6 +601,7 @@ static int usbdev_release(struct inode * > struct usb_device *dev = ps->dev; > unsigned int ifnum; > >+ xtr_mark(&uxtr, 'w', (unsigned long)ps); > usb_lock_device(dev); > > /* Protect against simultaneous open */ >@@ -1579,20 +1591,48 @@ struct file_operations usbfs_device_file > .release = usbdev_release, > }; > >+void usb_fs_classdev_common_remove(struct usb_device *udev) >+{ >+ struct dev_state *ps; >+ struct siginfo sinfo; >+ >+ while (!list_empty(&udev->filelist)) { >+ ps = list_entry(udev->filelist.next, struct dev_state, list); >+ wake_up_all(&ps->wait); >+ list_del_init(&ps->list); >+ if (ps->discsignr) { >+ sinfo.si_signo = ps->discsignr; >+ sinfo.si_errno = EPIPE; >+ sinfo.si_code = SI_ASYNCIO; >+ sinfo.si_addr = ps->disccontext; >+ kill_proc_info_as_uid(ps->discsignr, &sinfo, >+ ps->disc_pid, ps->disc_uid, >+ ps->disc_euid, ps->secid); >+ } >+ } >+} >+ > static void usbdev_add(struct usb_device *dev) > { > int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); >+ struct class_device *cl_dev; > >- dev->class_dev = class_device_create(usb_device_class, NULL, >+ mutex_lock(&usbfs_mutex); >+ cl_dev = class_device_create(usb_device_class, NULL, > MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, > "usbdev%d.%d", dev->bus->busnum, dev->devnum); >- >- dev->class_dev->class_data = dev; >+ if (!IS_ERR(cl_dev)) { >+ cl_dev->class_data = dev; >+ dev->class_dev = cl_dev; >+ } >+ mutex_unlock(&usbfs_mutex); > } > > static void usbdev_remove(struct usb_device *dev) > { >- class_device_unregister(dev->class_dev); >+ if (dev->class_dev) >+ class_device_unregister(dev->class_dev); >+ usb_fs_classdev_common_remove(dev); > } > > static int usbdev_notify(struct notifier_block *self, unsigned long action, >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/core/hcd.c linux-2.6.18-81.el5-u/drivers/usb/core/hcd.c >--- linux-2.6.18-81.el5/drivers/usb/core/hcd.c 2008-02-18 14:51:04.000000000 -0800 >+++ linux-2.6.18-81.el5-u/drivers/usb/core/hcd.c 2008-06-19 17:24:11.000000000 -0700 >@@ -105,6 +105,40 @@ static DEFINE_SPINLOCK(hcd_data_lock); > /* wait queue for synchronous unlinks */ > DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue); > >+/* dead driver used after rmmod xxxx_hcd */ >+static int dhci_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, >+ struct urb *urb, gfp_t mf) { >+ printk(KERN_WARNING "usb%d: dead enqueue\n", hcd->self.busnum); >+ return -ENODEV; >+} >+static int dhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) { >+ printk(KERN_WARNING "usb%d: dead unlink\n", hcd->self.busnum); >+ return -ENODEV; >+} >+static void dhci_ep_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) { >+ printk(KERN_WARNING "usb%d: dead ep disable\n", hcd->self.busnum); >+} >+static int dhci_get_frame(struct usb_hcd *hcd) { >+ return 0; >+} >+ >+static const struct hc_driver usb_dead_hc_driver = { >+ .description = "dead", >+ .product_desc = "DHCI", >+#if 0 /* defined(CONFIG_PM) */ >+ .pci_suspend = dhci_pci_suspend, >+ .pci_resume = dhci_pci_resume, >+#endif >+ .urb_enqueue = dhci_urb_enqueue, >+ .urb_dequeue = dhci_urb_dequeue, >+ .endpoint_disable = dhci_ep_disable, >+ .get_frame_number = dhci_get_frame, >+#if 0 /* defined(CONFIG_PM) */ >+ .bus_suspend = dhci_bus_suspend, >+ .bus_resume = dhci_bus_resume, >+#endif >+}; >+ > /*-------------------------------------------------------------------------*/ > > /* >@@ -1758,6 +1792,18 @@ void usb_put_hcd (struct usb_hcd *hcd) > } > EXPORT_SYMBOL (usb_put_hcd); > >+static ssize_t >+show_hcd_state(struct device *dev, struct device_attribute *attr, char *buf) >+{ >+ struct usb_hcd *hcd; >+ >+ hcd = dev_get_drvdata(dev); >+ if (hcd == NULL) >+ return 0; >+ return sprintf(buf, "%d\n", hcd->state); >+} >+static DEVICE_ATTR(hcd_state, S_IRUGO, show_hcd_state, NULL); >+ > /** > * usb_add_hcd - finish generic HCD structure initialization and register > * @hcd: the usb_hcd structure to initialize >@@ -1776,6 +1822,8 @@ int usb_add_hcd(struct usb_hcd *hcd, > > dev_info(hcd->self.controller, "%s\n", hcd->product_desc); > >+ /* P3 */ device_create_file(hcd->self.controller, &dev_attr_hcd_state); >+ > set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); > > /* HC is in reset state, but accessible. Now do the one-time init, >@@ -1903,10 +1951,19 @@ void usb_remove_hcd(struct usb_hcd *hcd) > hcd->driver->stop(hcd); > hcd->state = HC_STATE_HALT; > >+ { >+ if (hcd->self.controller == NULL) { >+ printk(KERN_ERR "NULL self controller\n"); >+ } else { >+ /* P3 */ device_remove_file(hcd->self.controller, &dev_attr_hcd_state); >+ } >+ } >+ > if (hcd->irq >= 0) > free_irq(hcd->irq, hcd); > usb_deregister_bus(&hcd->self); > hcd_buffer_destroy(hcd); >+ hcd->driver = &usb_dead_hc_driver; > } > EXPORT_SYMBOL (usb_remove_hcd); > >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/core/hcd-pci.c linux-2.6.18-81.el5-u/drivers/usb/core/hcd-pci.c >--- linux-2.6.18-81.el5/drivers/usb/core/hcd-pci.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/core/hcd-pci.c 2008-06-19 17:03:46.000000000 -0700 >@@ -164,13 +164,15 @@ EXPORT_SYMBOL (usb_hcd_pci_probe); > void usb_hcd_pci_remove (struct pci_dev *dev) > { > struct usb_hcd *hcd; >+ int driver_flags; > > hcd = pci_get_drvdata(dev); > if (!hcd) > return; > >+ driver_flags = hcd->driver->flags; > usb_remove_hcd (hcd); >- if (hcd->driver->flags & HCD_MEMORY) { >+ if (driver_flags & HCD_MEMORY) { > iounmap (hcd->regs); > release_mem_region (hcd->rsrc_start, hcd->rsrc_len); > } else { >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/core/hub.c linux-2.6.18-81.el5-u/drivers/usb/core/hub.c >--- linux-2.6.18-81.el5/drivers/usb/core/hub.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/core/hub.c 2008-06-19 19:23:28.000000000 -0700 >@@ -1244,7 +1244,7 @@ static int choose_configuration(struct u > && desc->bInterfaceClass == USB_CLASS_COMM > && desc->bInterfaceSubClass == 2 > && desc->bInterfaceProtocol == 0xff) { >-#ifndef CONFIG_USB_NET_RNDIS_HOST >+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) > continue; > #else > best = c; >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/core/inode.c linux-2.6.18-81.el5-u/drivers/usb/core/inode.c >--- linux-2.6.18-81.el5/drivers/usb/core/inode.c 2008-02-18 14:50:57.000000000 -0800 >+++ linux-2.6.18-81.el5-u/drivers/usb/core/inode.c 2008-07-26 19:29:14.000000000 -0700 >@@ -331,6 +331,7 @@ static int usbfs_empty (struct dentry *d > static int usbfs_unlink (struct inode *dir, struct dentry *dentry) > { > struct inode *inode = dentry->d_inode; >+ xtr_mark(&uxtr, 'o', (unsigned long) inode->i_private); > mutex_lock(&inode->i_mutex); > dentry->d_inode->i_nlink--; > dput(dentry); >@@ -682,29 +683,17 @@ static void usbfs_add_device(struct usb_ > > static void usbfs_remove_device(struct usb_device *dev) > { >- struct dev_state *ds; >- struct siginfo sinfo; >- > if (dev->usbfs_dentry) { > fs_remove_file (dev->usbfs_dentry); > dev->usbfs_dentry = NULL; > } >- while (!list_empty(&dev->filelist)) { >- ds = list_entry(dev->filelist.next, struct dev_state, list); >- wake_up_all(&ds->wait); >- list_del_init(&ds->list); >- if (ds->discsignr) { >- sinfo.si_signo = ds->discsignr; >- sinfo.si_errno = EPIPE; >- sinfo.si_code = SI_ASYNCIO; >- sinfo.si_addr = ds->disccontext; >- kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid); >- } >- } >+ usb_fs_classdev_common_remove(dev); > } > > static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) > { >+ xtr_mark(&uxtr, 'n', (unsigned long)dev); >+ xtr_mark(&uxtr, 'm', action); > switch (action) { > case USB_DEVICE_ADD: > usbfs_add_device(dev); >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/core/usb.c linux-2.6.18-81.el5-u/drivers/usb/core/usb.c >--- linux-2.6.18-81.el5/drivers/usb/core/usb.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/core/usb.c 2008-07-26 18:42:51.000000000 -0700 >@@ -33,6 +33,8 @@ > #include <linux/smp_lock.h> > #include <linux/usb.h> > #include <linux/mutex.h> >+#include <linux/sysrq.h> >+#include <asm/kdebug.h> > > #include <asm/io.h> > #include <asm/scatterlist.h> >@@ -1110,6 +1112,36 @@ int usb_disabled(void) > } > > /* >+ * Ad-hoc tracing >+ */ >+static void uxtr_sysrq(int key, struct pt_regs *pt_regs, >+ struct tty_struct *tty) >+{ >+ xtr_dump(&uxtr); >+} >+ >+static struct sysrq_key_op sysrq_uxtr_op = { >+ .handler = uxtr_sysrq, >+ .help_msg = "(z)tracedump", >+ .action_msg = "z-uxtr", >+ .enable_mask = SYSRQ_ENABLE_BOOT, >+}; >+ >+static int uxtr_die(struct notifier_block *nb, unsigned long reason, void *x) >+{ >+ if (reason == DIE_OOPS) { >+ xtr_dump(&uxtr); >+ return NOTIFY_OK; >+ } >+ return NOTIFY_DONE; >+} >+ >+static struct notifier_block die_uxtr_notifier = { >+ .notifier_call = uxtr_die, >+ .priority = 0x7FFFFFFF, >+}; >+ >+/* > * Init > */ > static int __init usb_init(void) >@@ -1120,6 +1152,9 @@ static int __init usb_init(void) > return 0; > } > >+ register_sysrq_key('z', &sysrq_uxtr_op); >+ register_die_notifier(&die_uxtr_notifier); >+ > retval = bus_register(&usb_bus_type); > if (retval) > goto out; >@@ -1158,6 +1193,8 @@ major_init_failed: > usb_host_cleanup(); > host_init_failed: > bus_unregister(&usb_bus_type); >+ unregister_die_notifier(&die_uxtr_notifier); >+ unregister_sysrq_key('z', &sysrq_uxtr_op); > out: > return retval; > } >@@ -1179,6 +1216,8 @@ static void __exit usb_exit(void) > usb_hub_cleanup(); > usb_host_cleanup(); > bus_unregister(&usb_bus_type); >+ unregister_die_notifier(&die_uxtr_notifier); >+ unregister_sysrq_key('z', &sysrq_uxtr_op); > } > > subsys_initcall(usb_init); >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/core/usb.h linux-2.6.18-81.el5-u/drivers/usb/core/usb.h >--- linux-2.6.18-81.el5/drivers/usb/core/usb.h 2008-02-18 14:50:55.000000000 -0800 >+++ linux-2.6.18-81.el5-u/drivers/usb/core/usb.h 2008-06-19 14:37:21.000000000 -0700 >@@ -64,6 +64,7 @@ extern struct usb_driver usbfs_driver; > extern struct file_operations usbfs_devices_fops; > extern struct file_operations usbfs_device_file_operations; > extern void usbfs_conn_disc_event(void); >+extern void usb_fs_classdev_common_remove(struct usb_device *udev); > > extern int usbdev_init(void); > extern void usbdev_cleanup(void); >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/host/ehci-dbg.c linux-2.6.18-81.el5-u/drivers/usb/host/ehci-dbg.c >--- linux-2.6.18-81.el5/drivers/usb/host/ehci-dbg.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/host/ehci-dbg.c 2008-03-10 21:02:18.000000000 -0700 >@@ -754,9 +754,7 @@ show_registers (struct class_device *cla > } > > if (ehci->reclaim) { >- temp = scnprintf (next, size, "reclaim qh %p%s\n", >- ehci->reclaim, >- ehci->reclaim_ready ? " ready" : ""); >+ temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim); > size -= temp; > next += temp; > } >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/host/ehci.h linux-2.6.18-81.el5-u/drivers/usb/host/ehci.h >--- linux-2.6.18-81.el5/drivers/usb/host/ehci.h 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/host/ehci.h 2008-03-10 21:02:18.000000000 -0700 >@@ -58,7 +58,6 @@ struct ehci_hcd { /* one per controlle > /* async schedule support */ > struct ehci_qh *async; > struct ehci_qh *reclaim; >- unsigned reclaim_ready : 1; > unsigned scanning : 1; > > /* periodic schedule support */ >@@ -81,6 +80,7 @@ struct ehci_hcd { /* one per controlle > struct dma_pool *itd_pool; /* itd per iso urb */ > struct dma_pool *sitd_pool; /* sitd per split iso urb */ > >+ struct timer_list iaa_watchdog; > struct timer_list watchdog; > struct notifier_block reboot_notifier; > unsigned long actions; >@@ -115,9 +115,21 @@ static inline struct usb_hcd *ehci_to_hc > } > > >+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 { > TIMER_IO_WATCHDOG, >- TIMER_IAA_WATCHDOG, > TIMER_ASYNC_SHRINK, > TIMER_ASYNC_OFF, > }; >@@ -135,9 +147,6 @@ timer_action (struct ehci_hcd *ehci, enu > unsigned long t; > > switch (action) { >- case TIMER_IAA_WATCHDOG: >- t = EHCI_IAA_JIFFIES; >- break; > case TIMER_IO_WATCHDOG: > t = EHCI_IO_JIFFIES; > break; >@@ -154,8 +163,7 @@ timer_action (struct ehci_hcd *ehci, enu > // async queue SHRINK often precedes IAA. while it's ready > // to go OFF neither can matter, and afterwards the IO > // watchdog stops unless there's still periodic traffic. >- if (action != TIMER_IAA_WATCHDOG >- && t > ehci->watchdog.expires >+ if (time_before_eq(t, ehci->watchdog.expires) > && timer_pending (&ehci->watchdog)) > return; > mod_timer (&ehci->watchdog, t); >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/host/ehci-hcd.c linux-2.6.18-81.el5-u/drivers/usb/host/ehci-hcd.c >--- linux-2.6.18-81.el5/drivers/usb/host/ehci-hcd.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/host/ehci-hcd.c 2008-03-10 21:02:22.000000000 -0700 >@@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hc > #define EHCI_TUNE_MULT_TT 1 > #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ > >-#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ >+#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_JIFFIES (HZ/200) /* async qh unlink delay */ >@@ -254,6 +254,7 @@ static void ehci_quiesce (struct ehci_hc > > /*-------------------------------------------------------------------------*/ > >+static void end_unlink_async(struct ehci_hcd *ehci, struct pt_regs *regs); > static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); > > #include "ehci-hub.c" >@@ -263,26 +264,62 @@ static void ehci_work(struct ehci_hcd *e > > /*-------------------------------------------------------------------------*/ > >-static void ehci_watchdog (unsigned long param) >+static void ehci_iaa_watchdog(unsigned long param) > { > struct ehci_hcd *ehci = (struct ehci_hcd *) param; > unsigned long flags; > > spin_lock_irqsave (&ehci->lock, flags); > >- /* 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"); >+ /* Lost IAA irqs wedge things badly; seen first with a vt8235. >+ * So we need this watchdog, but must protect it against both >+ * (a) SMP races against real IAA firing and retriggering, and >+ * (b) clean HC shutdown, when IAA watchdog was pending. >+ */ >+ if (ehci->reclaim >+ && !timer_pending(&ehci->iaa_watchdog) >+ && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { >+ u32 cmd, status; >+ >+ /* If we get here, IAA is *REALLY* late. It's barely >+ * conceivable that the system is so busy that CMD_IAAD >+ * is still legitimately set, so let's be sure it's >+ * clear before we read STS_IAA. (The HC should clear >+ * CMD_IAAD when it sets STS_IAA.) >+ */ >+ cmd = readl(&ehci->regs->command); >+ if (cmd & CMD_IAAD) >+ writel(cmd & ~CMD_IAAD, >+ &ehci->regs->command); >+ >+ /* If IAA is set here it either legitimately triggered >+ * before we cleared IAAD above (but _way_ late, so we'll >+ * still count it as lost) ... or a silicon erratum: >+ * - VIA seems to set IAA without triggering the IRQ; >+ * - IAAD potentially cleared without setting IAA. >+ */ >+ status = readl(&ehci->regs->status); >+ if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { > COUNT (ehci->stats.lost_iaa); > writel (STS_IAA, &ehci->regs->status); >- ehci->reclaim_ready = 1; > } >+ >+ ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", >+ status, cmd); >+ end_unlink_async(ehci, NULL); > } > >- /* stop async processing after it's idled a bit */ >+ spin_unlock_irqrestore(&ehci->lock, flags); >+} >+ >+static void ehci_watchdog(unsigned long param) >+{ >+ struct ehci_hcd *ehci = (struct ehci_hcd *) param; >+ unsigned long flags; >+ >+ spin_lock_irqsave(&ehci->lock, flags); >+ >+ /* stop async processing after it's idled a bit */ > if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) > start_unlink_async (ehci, ehci->async); > >@@ -334,8 +371,6 @@ static void ehci_port_power (struct ehci > static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) > { > timer_action_done (ehci, TIMER_IO_WATCHDOG); >- if (ehci->reclaim_ready) >- end_unlink_async (ehci, regs); > > /* another CPU may drop ehci->lock during a schedule scan while > * it reports urb completions. this flag guards against bogus >@@ -370,6 +405,7 @@ static void ehci_stop (struct usb_hcd *h > > /* no more interrupts ... */ > del_timer_sync (&ehci->watchdog); >+ del_timer_sync(&ehci->iaa_watchdog); > > spin_lock_irq(&ehci->lock); > if (HC_IS_RUNNING (hcd->state)) >@@ -417,6 +453,10 @@ static int ehci_init(struct usb_hcd *hcd > ehci->watchdog.function = ehci_watchdog; > 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. > * periodic_size can shrink by USBCMD update if hcc_params allows. >@@ -433,7 +473,6 @@ static int ehci_init(struct usb_hcd *hcd > ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); > > ehci->reclaim = NULL; >- ehci->reclaim_ready = 0; > ehci->next_uframe = -1; > > /* >@@ -568,7 +607,7 @@ static int ehci_run (struct usb_hcd *hcd > static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) > { > struct ehci_hcd *ehci = hcd_to_ehci (hcd); >- u32 status; >+ u32 status, cmd; > int bh; > > spin_lock (&ehci->lock); >@@ -589,7 +628,7 @@ static irqreturn_t ehci_irq (struct usb_ > > /* clear (just) interrupts */ > writel (status, &ehci->regs->status); >- readl (&ehci->regs->command); /* unblock posted write */ >+ cmd = readl(&ehci->regs->command); > bh = 0; > > #ifdef EHCI_VERBOSE_DEBUG >@@ -610,9 +649,17 @@ static irqreturn_t ehci_irq (struct usb_ > > /* complete the unlinking of some qh [4.15.2.3] */ > if (status & STS_IAA) { >- COUNT (ehci->stats.reclaim); >- ehci->reclaim_ready = 1; >- bh = 1; >+ /* guard against (alleged) silicon errata */ >+ if (cmd & CMD_IAAD) { >+ writel(cmd & ~CMD_IAAD, >+ &ehci->regs->command); >+ ehci_dbg(ehci, "IAA with IAAD still set?\n"); >+ } >+ if (ehci->reclaim) { >+ COUNT(ehci->stats.reclaim); >+ end_unlink_async(ehci, NULL); >+ } else >+ ehci_dbg(ehci, "IAA with nothing to reclaim?\n"); > } > > /* remote wakeup [4.3.1] */ >@@ -715,10 +762,16 @@ static int ehci_urb_enqueue ( > > static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) > { >- /* if we need to use IAA and it's busy, defer */ >- if (qh->qh_state == QH_STATE_LINKED >- && ehci->reclaim >- && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { >+ /* failfast */ >+ if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) >+ end_unlink_async(ehci, NULL); >+ >+ /* if it's not linked then there's nothing to do */ >+ if (qh->qh_state != QH_STATE_LINKED) >+ ; >+ >+ /* defer till later if busy */ >+ else if (ehci->reclaim) { > struct ehci_qh *last; > > for (last = ehci->reclaim; >@@ -728,12 +781,8 @@ static void unlink_async (struct ehci_hc > qh->qh_state = QH_STATE_UNLINK_WAIT; > last->reclaim = qh; > >- /* bypass IAA if the hc can't care */ >- } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) >- end_unlink_async (ehci, NULL); >- >- /* something else might have unlinked the qh by now */ >- if (qh->qh_state == QH_STATE_LINKED) >+ /* start IAA cycle */ >+ } else > start_unlink_async (ehci, qh); > } > >@@ -755,7 +804,19 @@ static int ehci_urb_dequeue (struct usb_ > qh = (struct ehci_qh *) urb->hcpriv; > if (!qh) > break; >- unlink_async (ehci, qh); >+ switch (qh->qh_state) { >+ 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; > > case PIPE_INTERRUPT: >@@ -847,6 +908,7 @@ rescan: > unlink_async (ehci, qh); > /* FALL THROUGH */ > case QH_STATE_UNLINK: /* wait for hw to finish? */ >+ case QH_STATE_UNLINK_WAIT: > idle_timeout: > spin_unlock_irqrestore (&ehci->lock, flags); > schedule_timeout_uninterruptible(1); >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/host/ehci-hub.c linux-2.6.18-81.el5-u/drivers/usb/host/ehci-hub.c >--- linux-2.6.18-81.el5/drivers/usb/host/ehci-hub.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/host/ehci-hub.c 2008-06-19 21:42:58.000000000 -0700 >@@ -37,6 +37,8 @@ static int ehci_bus_suspend (struct usb_ > > if (time_before (jiffies, ehci->next_statechange)) > msleep(5); >+ del_timer_sync(&ehci->watchdog); >+ del_timer_sync(&ehci->iaa_watchdog); > > port = HCS_N_PORTS (ehci->hcs_params); > spin_lock_irq (&ehci->lock); >@@ -47,8 +49,6 @@ static int ehci_bus_suspend (struct usb_ > hcd->state = HC_STATE_QUIESCING; > } > ehci->command = readl (&ehci->regs->command); >- if (ehci->reclaim) >- ehci->reclaim_ready = 1; > ehci_work(ehci, NULL); > > /* suspend any active/unsuspended ports, maybe allow wakeup */ >@@ -65,17 +65,19 @@ static int ehci_bus_suspend (struct usb_ > t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); > > if (t1 != t2) { >- ehci_vdbg (ehci, "port %d, %08x -> %08x\n", >- port + 1, t1, t2); >+ printk("ehci bus %d port %d, %08x -> %08x\n", >+ hcd->self.busnum, port + 1, t1, t2); > writel (t2, reg); > } > } > > /* turn off now-idle HC */ >- del_timer_sync (&ehci->watchdog); > ehci_halt (ehci); > hcd->state = HC_STATE_SUSPENDED; > >+ if (ehci->reclaim) >+ end_unlink_async(ehci, NULL); >+ > ehci->next_statechange = jiffies + msecs_to_jiffies(10); > spin_unlock_irq (&ehci->lock); > return 0; >@@ -112,7 +114,8 @@ static int ehci_bus_resume (struct usb_h > writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); > } else > intr_enable = 0; >- ehci_dbg(ehci, "resume root hub%s\n", >+ printk("ehci %d resume root hub%s\n", >+ hcd->self.busnum, > intr_enable ? " after power loss" : ""); > > /* restore CMD_RUN, framelist size, and irq threshold */ >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/host/ehci-pci.c linux-2.6.18-81.el5-u/drivers/usb/host/ehci-pci.c >--- linux-2.6.18-81.el5/drivers/usb/host/ehci-pci.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/host/ehci-pci.c 2008-03-10 21:02:18.000000000 -0700 >@@ -297,7 +297,7 @@ restart: > /* emptying the schedule aborts any urbs */ > spin_lock_irq(&ehci->lock); > if (ehci->reclaim) >- ehci->reclaim_ready = 1; >+ end_unlink_async(ehci, NULL); > ehci_work(ehci, NULL); > spin_unlock_irq(&ehci->lock); > >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/host/ehci-q.c linux-2.6.18-81.el5-u/drivers/usb/host/ehci-q.c >--- linux-2.6.18-81.el5/drivers/usb/host/ehci-q.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/host/ehci-q.c 2008-03-10 21:02:22.000000000 -0700 >@@ -967,7 +967,7 @@ static void end_unlink_async (struct ehc > struct ehci_qh *qh = ehci->reclaim; > struct ehci_qh *next; > >- timer_action_done (ehci, TIMER_IAA_WATCHDOG); >+ iaa_watchdog_done(ehci); > > // qh->hw_next = cpu_to_le32 (qh->qh_dma); > qh->qh_state = QH_STATE_IDLE; >@@ -977,7 +977,6 @@ static void end_unlink_async (struct ehc > /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ > next = qh->reclaim; > ehci->reclaim = next; >- ehci->reclaim_ready = 0; > qh->reclaim = NULL; > > qh_completions (ehci, qh, regs); >@@ -1052,11 +1051,10 @@ static void start_unlink_async (struct e > return; > } > >- ehci->reclaim_ready = 0; > cmd |= CMD_IAAD; > writel (cmd, &ehci->regs->command); > (void) readl (&ehci->regs->command); >- timer_action (ehci, TIMER_IAA_WATCHDOG); >+ iaa_watchdog_start(ehci); > } > > /*-------------------------------------------------------------------------*/ >diff -urp -X dontdiff linux-2.6.18-81.el5/drivers/usb/host/ohci-q.c linux-2.6.18-81.el5-u/drivers/usb/host/ohci-q.c >--- linux-2.6.18-81.el5/drivers/usb/host/ohci-q.c 2006-09-19 20:42:06.000000000 -0700 >+++ linux-2.6.18-81.el5-u/drivers/usb/host/ohci-q.c 2008-06-19 16:56:09.000000000 -0700 >@@ -172,9 +172,6 @@ static int ed_schedule (struct ohci_hcd > { > int branch; > >- if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING) >- return -EAGAIN; >- > ed->state = ED_OPER; > ed->ed_prev = NULL; > ed->ed_next = NULL; >diff -urp -X dontdiff linux-2.6.18-81.el5/include/linux/kernel.h linux-2.6.18-81.el5-u/include/linux/kernel.h >--- linux-2.6.18-81.el5/include/linux/kernel.h 2008-02-18 14:51:22.000000000 -0800 >+++ linux-2.6.18-81.el5-u/include/linux/kernel.h 2008-07-26 13:02:24.000000000 -0700 >@@ -361,4 +361,22 @@ struct sysinfo { > /* Trap pasters of __FUNCTION__ at compile-time */ > #define __FUNCTION__ (__func__) > >+/* >+ * Ad-hoc tracing for a quick peek >+ */ >+struct xtr_ent { >+ char tag; >+ unsigned long w; >+}; >+#define XTR_SZ 40 >+struct xtr { >+ int cur; >+ struct xtr_ent vec[XTR_SZ]; >+}; >+ >+void xtr_mark(struct xtr *tr, char tag, unsigned long w); >+void xtr_dump(struct xtr *tr); >+ >+extern struct xtr uxtr; /* USB */ >+ > #endif >diff -urp -X dontdiff linux-2.6.18-81.el5/kernel/panic.c linux-2.6.18-81.el5-u/kernel/panic.c >--- linux-2.6.18-81.el5/kernel/panic.c 2008-02-18 14:50:58.000000000 -0800 >+++ linux-2.6.18-81.el5-u/kernel/panic.c 2008-07-26 13:24:42.000000000 -0700 >@@ -19,6 +19,7 @@ > #include <linux/nmi.h> > #include <linux/kexec.h> > #include <linux/debug_locks.h> >+#include <linux/kernel.h> > > int panic_on_oops = 1; > int tainted; >@@ -271,3 +272,46 @@ void oops_exit(void) > { > do_oops_enter_exit(); > } >+ >+/* >+ * Ad-hoc tracing for a quick peek >+ */ >+static spinlock_t xtr_lock = SPIN_LOCK_UNLOCKED; >+ >+void xtr_mark(struct xtr *tr, char tag, unsigned long w) >+{ >+ unsigned long flags; >+ int n; >+ struct xtr_ent *t; >+ >+ spin_lock_irqsave(&xtr_lock, flags); >+ >+ if ((n = tr->cur + 1) == XTR_SZ) n = 0; >+ t = &tr->vec[n]; >+ >+ t->tag = tag; >+ t->w = w; >+ >+ tr->cur = n; >+ spin_unlock_irqrestore(&xtr_lock, flags); >+} >+EXPORT_SYMBOL(xtr_mark); >+ >+void xtr_dump(struct xtr *tr) >+{ >+ int n; >+ int j; >+ struct xtr_ent *t; >+ >+ if ((n = tr->cur + 1) == XTR_SZ) n = 0; >+ for (j = 0; j < XTR_SZ; j++) { >+ t = &tr->vec[n]; >+ >+ if (t->tag) >+ printk(" %c %lx\n", t->tag, t->w); >+ >+ if (++n == XTR_SZ) n = 0; >+ } >+} >+ >+struct xtr uxtr; /* USB */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 450786
:
308923
|
309101
|
309120
|
309142
|
309305
|
309692
|
310292
|
312710
| 312722 |
313707
|
313771