Message ID | 4A11DBD4.7070706@free.fr |
---|---|
State | Not Applicable, archived |
Headers | show |
On Tuesday 19 May 2009 00:06:12 matthieu castet wrote: > Hi, > > the current ssb irq setup (in ssb_mipscore_init) have some problem : > it configure some device on some irq without checking that the irq is > not taken by an other device. > > For example in my case PCI host is on irq 0 and IPSEC on irq 3. > The current code : > - store in dev->irq that IPSEC irq is 3+2 > - do a set_irq 0->3 on PCI host > > But now IPSEC irq is not routed anymore to the mips code and dev->irq is > wrong. This cause problem described in [1]. > > This patch try to solve the problem by making set_irq configure the > device we want to take the irq on the shared irq0. > The previous example become : > - store in dev->irq that IPSEC irq is 3+2 > - do a set_irq 0->3 on PCI host : > - irq 3 is already taken by IPSEC. do a set_irq 3->0 on IPSEC > > > I also added some code to print the irq configuration before and after > irq setup to allow easier debugging. And I add extra checking in > ssb_mips_irq to report device without irq or device with not routed irq. > > > [1] http://www.danm.de/files/src/bcm5365p/REPORTED_DEVICES > > Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr> > If this works on all devices, I'm OK with this. Please submit to linville@tuxdriver.com You can add my ack.
Michael Buesch wrote: > On Tuesday 19 May 2009 00:06:12 matthieu castet wrote: >> Hi, >> >> >> [1] http://www.danm.de/files/src/bcm5365p/REPORTED_DEVICES >> >> Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr> >> > > If this works on all devices, I'm OK with this. Please submit to linville@tuxdriver.com > You can add my ack. > Well I have only a wl500gd. I have submit it on openwrt project in order to test in more devices. Matthieu -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Matthieu, Michael, Le Monday 25 May 2009 19:55:58 matthieu castet, vous avez écrit : > Michael Buesch wrote: > > On Tuesday 19 May 2009 00:06:12 matthieu castet wrote: > >> Hi, > >> > >> > >> [1] http://www.danm.de/files/src/bcm5365p/REPORTED_DEVICES > >> > >> Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr> > > > > If this works on all devices, I'm OK with this. Please submit to > > linville@tuxdriver.com You can add my ack. > > Well I have only a wl500gd. > I have submit it on openwrt project in order to test in more devices. It makes the IPsec core work on my Netgear WGT634U and I did not see any regression on a Linksys WRT54GS. Tested-by: Florian Fainelli <florian@openwrt.org>
Le Thursday 11 June 2009 09:59:36 Florian Fainelli, vous avez écrit : > Hi Matthieu, Michael, > > Le Monday 25 May 2009 19:55:58 matthieu castet, vous avez écrit : > > Michael Buesch wrote: > > > On Tuesday 19 May 2009 00:06:12 matthieu castet wrote: > > >> Hi, > > >> > > >> > > >> [1] http://www.danm.de/files/src/bcm5365p/REPORTED_DEVICES > > >> > > >> Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr> > > > > > > If this works on all devices, I'm OK with this. Please submit to > > > linville@tuxdriver.com You can add my ack. > > > > Well I have only a wl500gd. > > I have submit it on openwrt project in order to test in more devices. > > It makes the IPsec core work on my Netgear WGT634U and I did not see any > regression on a Linksys WRT54GS. > > Tested-by: Florian Fainelli <florian@openwrt.org> One minor thing, please remove the dump_irqs call, it is convenient for debugging to print the IRQ routing, but I find it a little too verbose for production. This can be a follow-up patch if you prefer not to respin it.
Quoting Florian Fainelli <florian@openwrt.org>: > Le Thursday 11 June 2009 09:59:36 Florian Fainelli, vous avez écrit : > > Hi Matthieu, Michael, > > > > Le Monday 25 May 2009 19:55:58 matthieu castet, vous avez écrit : > > > Michael Buesch wrote: > > > > On Tuesday 19 May 2009 00:06:12 matthieu castet wrote: > > > >> Hi, > > > >> > > > >> > > > >> [1] http://www.danm.de/files/src/bcm5365p/REPORTED_DEVICES > > > >> > > > >> Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr> > > > > > > > > If this works on all devices, I'm OK with this. Please submit to > > > > linville@tuxdriver.com You can add my ack. > > > > > > Well I have only a wl500gd. > > > I have submit it on openwrt project in order to test in more devices. > > > > It makes the IPsec core work on my Netgear WGT634U and I did not see any > > regression on a Linksys WRT54GS. > > > > Tested-by: Florian Fainelli <florian@openwrt.org> > > One minor thing, please remove the dump_irqs call, it is convenient for > debugging to print the IRQ routing, but I find it a little too verbose for > production. This can be a follow-up patch if you prefer not to respin it. Well all x86 does something similar, with acpi dumping the pci interrupt Routing Table even in production kernel. But it can removed if people don't want it. Matthieu -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 3fd3e3b..6acf43f 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c @@ -49,29 +49,54 @@ static const u32 ipsflag_irq_shift[] = { static inline u32 ssb_irqflag(struct ssb_device *dev) { - return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG; + u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG); + if (tpsflag) + return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG; + else + /* not irq supported */ + return 0x3f; +} + +static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag) +{ + struct ssb_bus *bus = rdev->bus; + int i; + for (i = 0; i < bus->nr_devices; i++) { + struct ssb_device *dev; + dev = &(bus->devices[i]); + if (ssb_irqflag(dev) == irqflag) + return dev; + } + return NULL; } /* Get the MIPS IRQ assignment for a specified device. * If unassigned, 0 is returned. + * If disabled, 5 is returned. + * If not supported, 6 is returned. */ unsigned int ssb_mips_irq(struct ssb_device *dev) { struct ssb_bus *bus = dev->bus; + struct ssb_device *mdev = bus->mipscore.dev; u32 irqflag; u32 ipsflag; u32 tmp; unsigned int irq; irqflag = ssb_irqflag(dev); + if (irqflag == 0x3f) + return 6; ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG); for (irq = 1; irq <= 4; irq++) { tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]); if (tmp == irqflag) break; } - if (irq == 5) - irq = 0; + if (irq == 5) { + if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)) + irq = 0; + } return irq; } @@ -97,25 +122,56 @@ static void set_irq(struct ssb_device *dev, unsigned int irq) struct ssb_device *mdev = bus->mipscore.dev; u32 irqflag = ssb_irqflag(dev); + BUG_ON(oldirq == 6); + dev->irq = irq + 2; - ssb_dprintk(KERN_INFO PFX - "set_irq: core 0x%04x, irq %d => %d\n", - dev->id.coreid, oldirq, irq); /* clear the old irq */ if (oldirq == 0) ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))); - else + else if (oldirq != 5) clear_irq(bus, oldirq); /* assign the new one */ if (irq == 0) { ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC))); } else { + u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG); + if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) { + u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]; + struct ssb_device *olddev = find_device(dev, oldipsflag); + if (olddev) + set_irq(olddev, 0); + } irqflag <<= ipsflag_irq_shift[irq]; - irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]); + irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]); ssb_write32(mdev, SSB_IPSFLAG, irqflag); } + ssb_dprintk(KERN_INFO PFX + "set_irq: core 0x%04x, irq %d => %d\n", + dev->id.coreid, oldirq+2, irq+2); +} + +static void print_irq(struct ssb_device *dev, unsigned int irq) +{ + int i; + static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; + ssb_dprintk(KERN_INFO PFX + "core 0x%04x, irq :", dev->id.coreid); + for (i = 0; i <= 6; i++) { + ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" "); + } + ssb_dprintk("\n"); +} + +static void dump_irq(struct ssb_bus *bus) +{ + int i; + for (i = 0; i < bus->nr_devices; i++) { + struct ssb_device *dev; + dev = &(bus->devices[i]); + print_irq(dev, ssb_mips_irq(dev)); + } } static void ssb_mips_serial_init(struct ssb_mipscore *mcore) @@ -195,18 +251,26 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) else if (bus->chipco.dev) ssb_chipco_timing_init(&bus->chipco, ns); + dump_irq(bus); /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ for (irq = 2, i = 0; i < bus->nr_devices; i++) { + int mips_irq; dev = &(bus->devices[i]); - dev->irq = ssb_mips_irq(dev) + 2; + mips_irq = ssb_mips_irq(dev); + if (mips_irq > 4) + dev->irq = 0; + else + dev->irq = mips_irq + 2; + if (dev->irq > 5) + continue; 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) && (irq <= 4)) { set_irq(dev, irq++); - break; } + break; /* fallthrough */ case SSB_DEV_PCI: case SSB_DEV_ETHERNET: @@ -220,6 +284,8 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) } } } + ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n"); + dump_irq(bus); ssb_mips_serial_init(mcore); ssb_mips_flash_detect(mcore);
Hi, the current ssb irq setup (in ssb_mipscore_init) have some problem : it configure some device on some irq without checking that the irq is not taken by an other device. For example in my case PCI host is on irq 0 and IPSEC on irq 3. The current code : - store in dev->irq that IPSEC irq is 3+2 - do a set_irq 0->3 on PCI host But now IPSEC irq is not routed anymore to the mips code and dev->irq is wrong. This cause problem described in [1]. This patch try to solve the problem by making set_irq configure the device we want to take the irq on the shared irq0. The previous example become : - store in dev->irq that IPSEC irq is 3+2 - do a set_irq 0->3 on PCI host : - irq 3 is already taken by IPSEC. do a set_irq 3->0 on IPSEC I also added some code to print the irq configuration before and after irq setup to allow easier debugging. And I add extra checking in ssb_mips_irq to report device without irq or device with not routed irq. [1] http://www.danm.de/files/src/bcm5365p/REPORTED_DEVICES Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>