Ooops, Sorry for the confusion... The patch (ehci-ssb support) wasn't
applied correctly in my distribution. I had to apply the patch manually.

Something wrong happens applying this patch (wl500gp-v2):

//////ping message/////
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
>From 192.168.1.15 icmp_seq=2 Destination Host Unreachable
>From 192.168.1.15 icmp_seq=3 Destination Host Unreachable
>From 192.168.1.15 icmp_seq=4 Destination Host Unreachable
>From 192.168.1.15 icmp_seq=6 Destination Host Unreachable
>From 192.168.1.15 icmp_seq=7 Destination Host Unreachable
>From 192.168.1.15 icmp_seq=8 Destination Host Unreachable
64 bytes from 192.168.1.1: icmp_seq=9 ttl=100 time=1807 ms
64 bytes from 192.168.1.1: icmp_seq=10 ttl=100 time=808 ms
64 bytes from 192.168.1.1: icmp_seq=11 ttl=100 time=1.92 ms
64 bytes from 192.168.1.1: icmp_seq=25 ttl=100 time=4.80 ms
64 bytes from 192.168.1.1: icmp_seq=39 ttl=100 time=4.62 ms
64 bytes from 192.168.1.1: icmp_seq=53 ttl=100 time=4.49 ms
64 bytes from 192.168.1.1: icmp_seq=58 ttl=64 time=5.73 ms

--- 192.168.1.1 ping statistics ---
59 packets transmitted, 7 received, +6 errors, 88% packet loss, time
58002ms
rtt min/avg/max/mdev = 1.924/376.922/1807.924/646.814 ms, pipe 3
////---------------------------------------


The ohci-ssb attach function looks as follow:



static int ssb_ohci_attach(struct ssb_device *dev)
{
        struct ssb_ohci_device *ohcidev;
        struct usb_hcd *hcd;
        int err = -ENOMEM;
        u32 tmp, flags = 0;

        if (!(ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET))
                goto core_already_enabled;

        /*
         * THE FOLLOWING COMMENTS PRESERVED FROM GPL SOURCE RELEASE
         *
         * The USB core requires a special bit to be set during core
         * reset to enable host (OHCI) mode. Resetting the SB core in
         * pcibios_enable_device() is a hack for compatibility with
         * vanilla usb-ohci so that it does not have to know about
         * SB. A driver that wants to use the USB core in device mode
         * should know about SB and should reset the bit back to 0
         * after calling pcibios_enable_device().
         */

        if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
                if (ssb_device_is_enabled(dev))
                        goto core_already_enabled;
                flags |= SSB_OHCI_TMSLOW_HOSTMODE;
                ssb_device_enable(dev, flags);
        }

        /*
         * USB 2.0 special considerations:
         *
         * 1. Since the core supports both OHCI and EHCI functions, it must
         *    only be reset once.
         *
         * 2. In addition to the standard SB reset sequence, the Host Control
         *    Register must be programmed to bring the USB core and various
         *    phy components out of reset.
         */
        
        //else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
        else if (dev->id.coreid == SSB_DEV_USB11_HOST) {
                if (ssb_device_is_enabled(dev))
                        goto core_already_enabled;

                ssb_device_enable(dev, 0);
                ssb_write32(dev, 0x200, 0x7ff);
                udelay(1);
        
                if (dev->id.revision == 1) { /* bug in rev 1 */

                        /* Change Flush control reg */
                        tmp = ssb_read32(dev, 0x400);
                        tmp &= ~8;
                        ssb_write32(dev, 0x400, tmp);
                        tmp = ssb_read32(dev, 0x400);
                        printk(KERN_INFO "USB20H fcr: 0x%0x\n", tmp);

                        /* Change Shim control reg */
                        tmp = ssb_read32(dev, 0x304);
                        tmp &= ~0x100;
                        ssb_write32(dev, 0x304, tmp);
                        tmp = ssb_read32(dev, 0x304);
                        printk(KERN_INFO "USB20H shim: 0x%0x\n", tmp);
                }
        } else
                ssb_device_enable(dev, 0);

core_already_enabled:
        /*
         * Set dma mask - 32 bit mask is just an assumption
         */
        if (ssb_dma_set_mask(dev, DMA_32BIT_MASK))
                return -EOPNOTSUPP;

        hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
                dev->dev->bus_id);
        if (!hcd)
                goto err_dev_disable;
        ohcidev = hcd_to_ssb_ohci(hcd);
        ohcidev->enable_flags = flags;

        tmp = ssb_read32(dev, SSB_ADMATCH0);
        hcd->rsrc_start = ssb_admatch_base(tmp);
        hcd->rsrc_len = ssb_admatch_size(tmp);
        hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
        if (!hcd->regs)
                goto err_put_hcd;
        err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
        if (err)
                goto err_iounmap;

        ssb_set_drvdata(dev, hcd);

        return err;

err_iounmap:
        iounmap(hcd->regs);
err_put_hcd:
        usb_put_hcd(hcd);
err_dev_disable:
        ssb_device_disable(dev, flags);
        return err;
}
EXPORT_SYMBOL_GPL(ssb_ohci_attach);



Thanks for any help



On Thu, 2008-06-12 at 21:35 -0400, Felipe Maya wrote:
> With the Patch submited by Michael Buesch  (follow the patch in this
> email), and the Steve Brown Patch, Simultaneously USB ports, seems work
> fine!!
> 
> good work!!!
> 
> Index: wireless-testing/drivers/ssb/main.c
> ===================================================================
> --- wireless-testing.orig/drivers/ssb/main.c        2008-05-17 
> 18:44:32.000000000 +0200
> +++ wireless-testing/drivers/ssb/main.c        2008-06-12 15:24:04.000000000 
> +0200
> @@ -1165,21 +1165,27 @@ u32 ssb_dma_translation(struct ssb_devic
>  }
>  EXPORT_SYMBOL(ssb_dma_translation);
>  
>  int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
>  {
>          struct device *dma_dev = ssb_dev->dma_dev;
> +        int err = 0;
>  
>  #ifdef CONFIG_SSB_PCIHOST
> -        if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI)
> -                return dma_set_mask(dma_dev, mask);
> +        if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI) {
> +                err = pci_set_dma_mask(ssb_dev->bus->host_pci, mask);
> +                if (err)
> +                        return err;
> +                err = pci_set_consistent_dma_mask(ssb_dev->bus->host_pci, 
> mask);
> +                return err;
> +        }
>  #endif
>          dma_dev->coherent_dma_mask = mask;
>          dma_dev->dma_mask = &dma_dev->coherent_dma_mask;
>  
> -        return 0;
> +        return err;
>  }
>  EXPORT_SYMBOL(ssb_dma_set_mask);
>  
>  int ssb_bus_may_powerdown(struct ssb_bus *bus)
>  {
>          struct ssb_chipcommon *cc;
> 
> 
> On Wed, 2008-06-11 at 15:30 -0700, Steve Brown wrote:
> > Felipe Maya wrote:
> > > The patch works with one USB port, but with two USB simultaneously
> > > something wrong happens.
> > >
> > > I changed the driver_mipscore.c to enable SSB_DEV_USB11_HOST for bcm5354
> > > at this line (208): 
> > >  
> > >
> > > if (((bus->chip_id == 0x4710) || (bus->chip_id == 0x5354)) && (irq <=
> > > 4))
> > >
> > > instead
> > >
> > > if (((bus->chip_id == 0x4710) && (irq <= 4))
> > >
> > >
> > > and it seems work fine!!!!
> > >
> > >
> > >  for (irq = 2, i = 0; i < bus->nr_devices; i++) {
> > >                 dev = &(bus->devices[i]);
> > >                 dev->irq = ssb_mips_irq(dev) + 2;
> > >                 switch (dev->id.coreid) {
> > >                 case SSB_DEV_USB11_HOST:
> > >                         /* shouldn't need a separate irq line for
> > > non-4710, most of them have a proper
> > >                          * external usb controller on the pci */
> > >                         if (((bus->chip_id == 0x4710) || (bus->chip_id
> > > == 0x5354)) && (irq <= 4)) {
> > >                                 set_irq(dev, irq++);
> > >                                 break;
> > >                         }
> > >                         /* fallthrough */
> > >                 case SSB_DEV_PCI:
> > > ....
> > > ....
> > > ....
> > >   
> > What goes wrong?
> > Are you using the patch I posted on this list?
> > Also, what router is your 5354 in?
> > 
> > This is very puzzling. One of the major changes was to get rid of the 
> > fake USB11 device. The single USB20 device now gets shared between the 
> > ehci and ohci drivers. I don't understand how the code in that case even 
> > got executed.
> > 
> > I just got a wl500gpv2 that has a 5354 and 2 usb ports. As soon as I get 
> > some headers soldered to it, I'll try both ports and see if I can get it 
> > to break.
> > 
> > Steve
> > 
> 
> My time, is my time!!
--- a/drivers/usb/host/ehci-ssb.c	2008-06-19 09:53:49.000000000 -0400
+++ b/usb/host/ehci-ssb.c	2008-06-19 09:54:20.000000000 -0400
@@ -23,6 +23,8 @@
  */
 #include <linux/ssb/ssb.h>
 
+extern int ssb_ohci_attach(struct ssb_device *dev);
+extern void ssb_ohci_detach(struct ssb_device *dev);
 
 #define SSB_OHCI_TMSLOW_HOSTMODE	(1 << 29)
 
@@ -135,14 +137,16 @@
 	.endpoint_disable	= ehci_endpoint_disable,
 
 	.get_frame_number	= ehci_get_frame,
- 
+
 	.hub_status_data	= ehci_hub_status_data,
 	.hub_control		= ehci_hub_control,
+//	.hub_irq_enable		= ehci_rhsc_enable,
 #ifdef CONFIG_PM
 	.bus_suspend		= ehci_bus_suspend,
 	.bus_resume		= ehci_bus_resume,
 #endif
 
+//	.start_port_reset	= ehci_start_port_reset,
 };
 
 static void ssb_ehci_detach(struct ssb_device *dev)
@@ -152,7 +156,14 @@
 	usb_remove_hcd(hcd);
 	iounmap(hcd->regs);
 	usb_put_hcd(hcd);
+
+/*
+ * Also detach the companion ohci device
+ */
+	ssb_ohci_detach(dev->companion);
+//	ssb_device_disable(dev, 0);
 }
+EXPORT_SYMBOL_GPL(ssb_ehci_detach);
 
 static int ssb_ehci_attach(struct ssb_device *dev)
 {
@@ -190,10 +201,7 @@
 	ssb_device_enable(dev, 0);
 	ssb_write32(dev, 0x200, 0x7ff);
 	udelay(1);
- /*
-  * Workaround for bug in rev 1
-  */
-	if (dev->id.revision == 1) {
+	if (dev->id.revision == 1) { // bug in rev 1
 
 		 /* Change Flush control reg */
 		tmp = ssb_read32(dev, 0x400);
@@ -227,8 +235,8 @@
 	ehcidev->enable_flags = flags;
 
 	tmp = ssb_read32(dev, SSB_ADMATCH0);
-	hcd->rsrc_start = ssb_admatch_base(tmp) + 0x800;/* ehci core offset */
-	hcd->rsrc_len = 0x100; /* size of ehci reg block */
+	hcd->rsrc_start = ssb_admatch_base(tmp) + 0x800; // offset for ehci core
+	hcd->rsrc_len = 0x100 /*ssb_admatch_size(tmp)*/; // size of ehci reg block
 	/*
 	 * start & size modified per sbutils.c
 	 */
@@ -241,8 +249,27 @@
 
 	ssb_set_drvdata(dev, hcd);
 
+	/*
+	 * attach ohci (companion) device in this core
+	 *
+	 * add new device as a copy of the ehci device
+         * change coreid to SSB_DEV_USB11_HOSTDEV
+	 * call ohci_ssb_attach(dev) to attach ohci device in this core
+	 */
+
+	dev->companion = &dev->bus->devices[dev->bus->nr_devices];
+	dev->bus->nr_devices;
+	if (dev->bus->nr_devices > ARRAY_SIZE(dev->bus->devices)) {
+		printk(KERN_ERR 
+			"More than %d devs, could not create ohci dev (%d)\n",
+			SSB_MAX_NR_CORES, dev->bus->nr_devices);
+			return err;
+	}
+	memcpy(dev->companion, dev, sizeof(struct ssb_device));
+	dev->companion->id.coreid = SSB_DEV_USB11_HOSTDEV;
+	err = ssb_ohci_attach(dev->companion);
 	return err;
- 
+
 err_iounmap:
 	iounmap(hcd->regs);
 err_put_hcd:
@@ -251,6 +278,7 @@
 	ssb_device_disable(dev, flags);
 	return err;
 }
+EXPORT_SYMBOL_GPL(ssb_ehci_attach);
 
 static int ssb_ehci_probe(struct ssb_device *dev,
 		 const struct ssb_device_id *id)
--- /tmp/linux-2.6.23.17/drivers/usb/host/ohci-ssb.c	2008-06-19 10:11:30.000000000 -0400
+++ drivers/usb/host/ohci-ssb.c	2008-06-19 10:24:25.000000000 -0400
@@ -17,7 +17,6 @@
  */
 #include <linux/ssb/ssb.h>
 
-
 #define SSB_OHCI_TMSLOW_HOSTMODE	(1 << 29)
 
 struct ssb_ohci_device {
@@ -128,11 +127,11 @@
 static void ssb_ohci_detach(struct ssb_device *dev)
 {
 	struct usb_hcd *hcd = ssb_get_drvdata(dev);
-
 	usb_remove_hcd(hcd);
 	iounmap(hcd->regs);
 	usb_put_hcd(hcd);
 }
+EXPORT_SYMBOL_GPL(ssb_ohci_detach);
 
 static int ssb_ohci_attach(struct ssb_device *dev)
 {
@@ -153,12 +152,12 @@
 	 * vanilla usb-ohci so that it does not have to know about
 	 * SB. A driver that wants to use the USB core in device mode
 	 * should know about SB and should reset the bit back to 0
-	 * after calling pcibios_enable_device()
+	 * after calling pcibios_enable_device().
 	 */
 
 	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
 		if (ssb_device_is_enabled(dev))
-                        goto core_already_enabled;
+			goto core_already_enabled;
 		flags |= SSB_OHCI_TMSLOW_HOSTMODE;
 		ssb_device_enable(dev, flags);
 	}
@@ -168,20 +167,22 @@
 	 *
 	 * 1. Since the core supports both OHCI and EHCI functions, it must
 	 *    only be reset once.
-	 * 
+	 *
 	 * 2. In addition to the standard SB reset sequence, the Host Control
 	 *    Register must be programmed to bring the USB core and various
-	 *    phy components out of reset. 
+	 *    phy components out of reset.
 	 */
-
-	else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
-//	else if (dev->id.coreid == SSB_DEV_USB11_HOST) {
+	
+	//else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
+	else if (dev->id.coreid == SSB_DEV_USB11_HOST) {
 		if (ssb_device_is_enabled(dev))
 			goto core_already_enabled;
+
 		ssb_device_enable(dev, 0);
 		ssb_write32(dev, 0x200, 0x7ff);
 		udelay(1);
-		if (dev->id.revision == 1) { // bug in rev 1
+	
+		if (dev->id.revision == 1) { /* bug in rev 1 */
 
 			/* Change Flush control reg */
 			tmp = ssb_read32(dev, 0x400);
@@ -197,12 +198,10 @@
 			tmp = ssb_read32(dev, 0x304);
 			printk(KERN_INFO "USB20H shim: 0x%0x\n", tmp);
 		}
-	}
-	else
+	} else
 		ssb_device_enable(dev, 0);
 
 core_already_enabled:
-
 	/*
 	* Set dma mask - 32 bit mask is just an assumption
 	*/
@@ -238,6 +237,7 @@
 	ssb_device_disable(dev, flags);
 	return err;
 }
+EXPORT_SYMBOL_GPL(ssb_ohci_attach);
 
 static int ssb_ohci_probe(struct ssb_device *dev,
 		const struct ssb_device_id *id)
@@ -275,7 +275,6 @@
 static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
 {
 	ssb_device_disable(dev, 0);
-
 	return 0;
 }
 
@@ -286,6 +285,7 @@
 
 	ssb_device_enable(dev, ohcidev->enable_flags);
 
+	ohci_finish_controller_resume(hcd);
 	return 0;
 }
 
@@ -297,7 +297,7 @@
 static const struct ssb_device_id ssb_ohci_table[] = {
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
-	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
+//	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
 	SSB_DEVTABLE_END
 };
 MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
@@ -310,4 +310,3 @@
 	.suspend	= ssb_ohci_suspend,
 	.resume		= ssb_ohci_resume,
 };
-
--- ../../toolchain-mipsel_gcc4.1.2/linux/drivers/usb/host/ehci-hcd.c	2008-02-25 19:14:28.000000000 -0500
+++ drivers/usb/host/ehci-hcd.c	2008-06-18 17:12:42.000000000 -0400
@@ -33,6 +33,7 @@
 #include <linux/usb.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
 
 #include "../core/hcd.h"
 
@@ -109,7 +110,7 @@
 #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 */
@@ -266,6 +267,7 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void end_unlink_async(struct ehci_hcd *ehci);
 static void ehci_work(struct ehci_hcd *ehci);
 
 #include "ehci-hub.c"
@@ -275,24 +277,61 @@
 
 /*-------------------------------------------------------------------------*/
 
-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 = ehci_readl(ehci, &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 = ehci_readl(ehci, &ehci->regs->command);
+		if (cmd & CMD_IAAD)
+			ehci_writel(ehci, 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 = ehci_readl(ehci, &ehci->regs->status);
+		if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
 			COUNT (ehci->stats.lost_iaa);
 			ehci_writel(ehci, 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);
 	}
 
+	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);
@@ -363,8 +402,6 @@
 static void ehci_work (struct ehci_hcd *ehci)
 {
 	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
 	 * it reports urb completions.  this flag guards against bogus
@@ -399,6 +436,7 @@
 
 	/* 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))
@@ -447,6 +485,10 @@
 	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.
@@ -463,7 +505,6 @@
 		ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
 
 	ehci->reclaim = NULL;
-	ehci->reclaim_ready = 0;
 	ehci->next_uframe = -1;
 
 	/*
@@ -611,7 +652,7 @@
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			status, pcd_status = 0;
+	u32			status, pcd_status = 0, cmd;
 	int			bh;
 
 	spin_lock (&ehci->lock);
@@ -632,7 +673,7 @@
 
 	/* clear (just) interrupts */
 	ehci_writel(ehci, status, &ehci->regs->status);
-	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted write */
+	cmd = ehci_readl(ehci, &ehci->regs->command);
 	bh = 0;
 
 #ifdef	EHCI_VERBOSE_DEBUG
@@ -653,9 +694,17 @@
 
 	/* 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) {
+			ehci_writel(ehci, 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);
+		} else
+			ehci_dbg(ehci, "IAA with nothing to reclaim?\n");
 	}
 
 	/* remote wakeup [4.3.1] */
@@ -730,7 +779,6 @@
  */
 static int ehci_urb_enqueue (
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	gfp_t		mem_flags
 ) {
@@ -745,12 +793,12 @@
 	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+		return submit_async(ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_INTERRUPT:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+		return intr_submit(ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_ISOCHRONOUS:
 		if (urb->dev->speed == USB_SPEED_HIGH)
@@ -762,10 +810,16 @@
 
 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) && ehci->reclaim)
+		end_unlink_async(ehci);
+
+	/* 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;
@@ -775,12 +829,8 @@
 		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);
-
-	/* 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);
 }
 
@@ -788,13 +838,18 @@
  * completions normally happen asynchronously
  */
 
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_qh		*qh;
 	unsigned long		flags;
+	int			rc;
 
 	spin_lock_irqsave (&ehci->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	switch (usb_pipetype (urb->pipe)) {
 	// case PIPE_CONTROL:
 	// case PIPE_BULK:
@@ -802,7 +857,19 @@
 		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:
@@ -825,18 +892,18 @@
 		/* reschedule QH iff another request is queued */
 		if (!list_empty (&qh->qtd_list)
 				&& HC_IS_RUNNING (hcd->state)) {
-			int status;
-
-			status = qh_schedule (ehci, qh);
-			spin_unlock_irqrestore (&ehci->lock, flags);
+			rc = qh_schedule(ehci, qh);
 
-			if (status != 0) {
-				// shouldn't happen often, but ...
-				// FIXME kill those tds' urbs
-				err ("can't reschedule qh %p, err %d",
-					qh, status);
-			}
-			return status;
+			/* An error here likely indicates handshake failure
+			 * or no space left in the schedule.  Neither fault
+			 * should happen often ...
+			 *
+			 * FIXME kill the now-dysfunctional queued urbs
+			 */
+			if (rc != 0)
+				ehci_err(ehci,
+					"can't reschedule qh %p, err %d",
+					qh, rc);
 		}
 		break;
 
@@ -849,7 +916,7 @@
 	}
 done:
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -894,6 +961,7 @@
 		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);
@@ -955,13 +1023,36 @@
 #define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_driver
 #endif
 
-#ifdef CONFIG_440EPX
+#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE)
 #include "ehci-ppc-soc.c"
 #define	PLATFORM_DRIVER		ehci_ppc_soc_driver
 #endif
 
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
-    !defined(PS3_SYSTEM_BUS_DRIVER)
+#ifdef CONFIG_USB_EHCI_HCD_PPC_OF
+#include "ehci-ppc-of.c"
+#define OF_PLATFORM_DRIVER	ehci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_ARCH_ORION
+#include "ehci-orion.c"
+#define	PLATFORM_DRIVER		ehci_orion_driver
+#endif
+
+#ifdef CONFIG_ARCH_IXP4XX
+#include "ehci-ixp4xx.c"
+#define	PLATFORM_DRIVER		ixp4xx_ehci_driver
+#endif
+
+#ifdef CONFIG_USB_EHCI_HCD_SSB
+#include "ehci-ssb.c"
+#define SSB_EHCI_DRIVER         ssb_ehci_driver
+#endif
+
+#if !defined(PCI_DRIVER) && \
+    !defined(PLATFORM_DRIVER) && \
+    !defined(PS3_SYSTEM_BUS_DRIVER) && \
+    !defined(OF_PLATFORM_DRIVER) && \
+    !defined(SSB_EHCI_DRIVER)
 #error "missing bus glue for ehci-hcd"
 #endif
 
@@ -974,50 +1065,93 @@
 		 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
 		 sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
 
+#ifdef DEBUG
+	ehci_debug_root = debugfs_create_dir("ehci", NULL);
+	if (!ehci_debug_root)
+		return -ENOENT;
+#endif
+
 #ifdef PLATFORM_DRIVER
 	retval = platform_driver_register(&PLATFORM_DRIVER);
 	if (retval < 0)
-		return retval;
+		goto clean0;
 #endif
 
 #ifdef PCI_DRIVER
 	retval = pci_register_driver(&PCI_DRIVER);
-	if (retval < 0) {
-#ifdef PLATFORM_DRIVER
-		platform_driver_unregister(&PLATFORM_DRIVER);
-#endif
-		return retval;
-	}
+	if (retval < 0)
+		goto clean1;
 #endif
 
 #ifdef PS3_SYSTEM_BUS_DRIVER
 	retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
-	if (retval < 0) {
-#ifdef PLATFORM_DRIVER
-		platform_driver_unregister(&PLATFORM_DRIVER);
-#endif
-#ifdef PCI_DRIVER
-		pci_unregister_driver(&PCI_DRIVER);
+	if (retval < 0)
+		goto clean2;
 #endif
-		return retval;
-	}
+
+#ifdef OF_PLATFORM_DRIVER
+	retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+	if (retval < 0)
+		goto clean3;
 #endif
 
+#ifdef SSB_EHCI_DRIVER 
+	retval = ssb_driver_register(&SSB_EHCI_DRIVER); 
+ 	if (retval < 0) 
+ 		goto clean4; 
+#endif 
+
 	return retval;
+
+#ifdef SSB_EHCI_DRIVER 
+	clean4: 
+ 		ssb_driver_unregister(&SSB_EHCI_DRIVER); 
+#endif 
+
+#ifdef OF_PLATFORM_DRIVER
+	/* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */
+clean3:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+clean2:
+#endif
+#ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
+clean1:
+#endif
+#ifdef PLATFORM_DRIVER
+	platform_driver_unregister(&PLATFORM_DRIVER);
+clean0:
+#endif
+#ifdef DEBUG
+	debugfs_remove(ehci_debug_root);
+	ehci_debug_root = NULL;
+#endif
+#ifdef SSB_EHCI_DRIVER 
+	ssb_driver_unregister(&SSB_EHCI_DRIVER); 
+#endif
+	return retval; 
 }
 module_init(ehci_hcd_init);
 
 static void __exit ehci_hcd_cleanup(void)
 {
+#ifdef OF_PLATFORM_DRIVER
+	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
 #ifdef PLATFORM_DRIVER
-	platform_driver_unregister(&PLATFORM_DRIVER);
+	platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
 #ifdef PCI_DRIVER
-	pci_unregister_driver(&PCI_DRIVER);
+	pci_unregister_driver(&PCI_DRIVER);
 #endif
 #ifdef PS3_SYSTEM_BUS_DRIVER
 	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
 #endif
+#ifdef DEBUG
+	debugfs_remove(ehci_debug_root);
+#endif
 }
 module_exit(ehci_hcd_cleanup);
 
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
http://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to