The existing IRQ logic incorrectly indicates cores that have no IRQ
assignment as being assigned to the shared IRQ; this includes setting
the "irq" field in the bcma_device struct to "2".  This is evidenced by
output of bcma_core_mips_print_irq, which is as follows:

[    0.112000] bcma: bus0: Initializing MIPS core...
[    0.112000] bcma: bus0: Moved i2s interrupt to oob line 7 instead of 8
[    0.112000] bcma: bus0: set_irq: core 0x0800, irq 2 => 2
[    0.112000] bcma: bus0: set_irq: core 0x0812, irq 3 => 3
[    0.112000] bcma: bus0: set_irq: core 0x082d, irq 4 => 4
[    0.112000] bcma: bus0: set_irq: core 0x0819, irq 5 => 5
[    0.112000] bcma: bus0: set_irq: core 0x0820, irq 6 => 6
[    0.112000] bcma: bus0: set_irq: core 0x0834, irq 2 => 2
[    0.112000] bcma: bus0: IRQ reconfiguration done
[    0.112000] bcma: core 0x0800, irq : 2(S)* 3  4  5  6  D  I 
[    0.112000] bcma: core 0x082c, irq : 2(S)* 3  4  5  6  D  I <-- Incorrect
[    0.112000] bcma: core 0x0812, irq : 2(S)  3* 4  5  6  D  I 
[    0.112000] bcma: core 0x082d, irq : 2(S)  3  4* 5  6  D  I 
[    0.112000] bcma: core 0x0819, irq : 2(S)  3  4  5* 6  D  I 
[    0.112000] bcma: core 0x0820, irq : 2(S)  3  4  5  6* D  I 
[    0.112000] bcma: core 0x082e, irq : 2(S)* 3  4  5  6  D  I <-- Incorrect
[    0.112000] bcma: core 0x080e, irq : 2(S)* 3  4  5  6  D  I <-- Incorrect
[    0.112000] bcma: core 0x0834, irq : 2(S)* 3  4  5  6  D  I 
[    0.116000] bcma: bus0: PCIEcore in host mode found

This is corrected by the following patch.

v2: Modified the signature of bcma_core_mips_irq to return negative values
    as was suggested, and adjusted the logic accordingly.  Modified output
    of bcma_core_mips_print_irq slightly to accomodate the change.  Please
    disregard the previous version of this patch (4/4); patches 1 through
    3 of the series still apply.

Signed-off-by: Nathan Hintz <[email protected]>

--- /dev/null
+++ target/linux/brcm47xx/patches-3.6/239-bcma-fix-irq-assignment.patch
@@ -0,0 +1,150 @@
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -65,7 +65,10 @@
+       BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
+ };
+ 
+-static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++#define IRQ_FLAG_VALIDITY_MASK        0x80
++#define IRQ_FLAG_MASK         0x1F
++#define EINVALID_IRQ_FLAG     1
++static s32 bcma_core_mips_irqflag(struct bcma_device *dev)
+ {
+       u32 flag;
+ 
+@@ -75,43 +78,52 @@
+               return dev->core_index;
+       flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
+ 
+-      return flag & 0x1F;
++      if (flag & IRQ_FLAG_VALIDITY_MASK)
++              return (flag & IRQ_FLAG_MASK);
++      else
++              return -EINVALID_IRQ_FLAG;
+ }
+ 
+ /* Get the MIPS IRQ assignment for a specified device.
+- * If unassigned, 0 is returned.
++ * If unassigned, -1 is returned; if no IRQ is required, -2 is returned
+  */
+-static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++#define EIRQ_NOT_ASSIGNED     1
++#define EIRQ_NOT_REQUIRED     2
++static int bcma_core_mips_irq(struct bcma_device *dev)
+ {
+       struct bcma_device *mdev = dev->bus->drv_mips.core;
+-      u32 irqflag;
+-      unsigned int irq;
++      s32 irqflag;
++      int irq;
+ 
+       irqflag = bcma_core_mips_irqflag(dev);
++      if (irqflag == -EINVALID_IRQ_FLAG)
++              return -EIRQ_NOT_REQUIRED;
+ 
+-      for (irq = 1; irq <= 4; irq++)
++      for (irq = 0; irq <= 4; irq++)
+               if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
+                   (1 << irqflag))
+                       return irq;
+ 
+-      return 0;
++      return -EIRQ_NOT_ASSIGNED;
+ }
+ 
+ unsigned int bcma_core_irq(struct bcma_device *dev)
+ {
+-      return bcma_core_mips_irq(dev) + 2;
++      int irq = bcma_core_mips_irq(dev);
++      return (irq >= 0) ? (irq + 2) : 0;
+ }
+ EXPORT_SYMBOL(bcma_core_irq);
+ 
+ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
+ {
+-      unsigned int oldirq = bcma_core_mips_irq(dev);
++      int oldirq = bcma_core_mips_irq(dev);
+       struct bcma_bus *bus = dev->bus;
+       struct bcma_device *mdev = bus->drv_mips.core;
+-      u32 irqflag;
++      s32 irqflag;
+ 
+       irqflag = bcma_core_mips_irqflag(dev);
+-      BUG_ON(oldirq == 6);
++      if (irqflag == -EINVALID_IRQ_FLAG)
++              return;
+ 
+       dev->irq = irq + 2;
+ 
+@@ -120,7 +132,7 @@
+               bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
+                           bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
+                           ~(1 << irqflag));
+-      else
++      else if (oldirq > 0)
+               bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
+ 
+       /* assign the new one */
+@@ -129,17 +141,18 @@
+                           bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
+                           (1 << irqflag));
+       } else {
+-              u32 oldirqflag = bcma_read32(mdev,
+-                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
+-              if (oldirqflag) {
++              u32 intmask = bcma_read32(mdev,
++                                        BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (intmask) {
+                       struct bcma_device *core;
+ 
+                       /* backplane irq line is in use, find out who uses
+                        * it and set user to irq 0
+                        */
+                       list_for_each_entry(core, &bus->cores, list) {
+-                              if ((1 << bcma_core_mips_irqflag(core)) ==
+-                                  oldirqflag) {
++                              s32 oldirqflag = bcma_core_mips_irqflag(core);
++                              if (oldirqflag != -EINVALID_IRQ_FLAG &&
++                                  (1 << oldirqflag) == intmask) {
+                                       bcma_core_mips_set_irq(core, 0);
+                                       break;
+                               }
+@@ -150,16 +163,16 @@
+       }
+ 
+       bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n",
+-                dev->id.id, oldirq + 2, irq + 2);
++                dev->id.id, (oldirq >= 0) ? (oldirq + 2) : 0, irq + 2);
+ }
+ 
+-static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int 
irq)
++static void bcma_core_mips_print_irq(struct bcma_device *dev, int irq)
+ {
+       int i;
+-      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      static const char *irq_name[] = {"I", "D", "2(S)", "3", "4", "5", "6"};
+       printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+-      for (i = 0; i <= 6; i++)
+-              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      for (i = -EIRQ_NOT_REQUIRED; i <= 4; i++)
++              printk(" %s%s", irq_name[i + EIRQ_NOT_REQUIRED], i == irq ? "*" 
: " ");
+       printk("\n");
+ }
+ 
+@@ -294,12 +307,12 @@
+ 
+       /* Assign IRQs to all cores on the bus */
+       list_for_each_entry(core, &bus->cores, list) {
+-              int mips_irq;
+-              if (core->irq)
++              int mips_irq = bcma_core_mips_irq(core);
++
++              if (mips_irq == -EIRQ_NOT_REQUIRED || core->irq)
+                       continue;
+ 
+-              mips_irq = bcma_core_mips_irq(core);
+-              if (mips_irq > 4)
++              if (mips_irq < 0)
+                       core->irq = 0;
+               else
+                       core->irq = mips_irq + 2;

_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to