1 the current ssb irq setup (in ssb_mipscore_init) have some problem :
2 it configure some device on some irq without checking that the irq is not taken by an other device.
4 For example in my case PCI host is on irq 0 and IPSEC on irq 3.
6 - store in dev->irq that IPSEC irq is 3+2
7 - do a set_irq 0->3 on PCI host
9 But now IPSEC irq is not routed anymore to the mips code and dev->irq is wrong. This cause problem described in [1].
11 This patch try to solve the problem by making set_irq configure the device we want to take the irq on the shared irq0.
12 The previous example become :
13 - store in dev->irq that IPSEC irq is 3+2
14 - do a set_irq 0->3 on PCI host :
15 - irq 3 is already taken by IPSEC. do a set_irq 3->0 on IPSEC
18 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.
21 [1] http://www.danm.de/files/src/bcm5365p/REPORTED_DEVICES
23 Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>
24 Index: linux-2.6/drivers/ssb/driver_mipscore.c
25 ===================================================================
26 --- linux-2.6.orig/drivers/ssb/driver_mipscore.c 2009-05-25 19:47:26.000000000 +0200
27 +++ linux-2.6/drivers/ssb/driver_mipscore.c 2009-05-25 19:47:42.000000000 +0200
30 static inline u32 ssb_irqflag(struct ssb_device *dev)
32 - return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
33 + u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
35 + return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
37 + /* not irq supported */
41 +static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
43 + struct ssb_bus *bus = rdev->bus;
45 + for (i = 0; i < bus->nr_devices; i++) {
46 + struct ssb_device *dev;
47 + dev = &(bus->devices[i]);
48 + if (ssb_irqflag(dev) == irqflag)
54 /* Get the MIPS IRQ assignment for a specified device.
55 * If unassigned, 0 is returned.
56 + * If disabled, 5 is returned.
57 + * If not supported, 6 is returned.
59 unsigned int ssb_mips_irq(struct ssb_device *dev)
61 struct ssb_bus *bus = dev->bus;
62 + struct ssb_device *mdev = bus->mipscore.dev;
68 irqflag = ssb_irqflag(dev);
69 + if (irqflag == 0x3f)
71 ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
72 for (irq = 1; irq <= 4; irq++) {
73 tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
80 + if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
87 struct ssb_device *mdev = bus->mipscore.dev;
88 u32 irqflag = ssb_irqflag(dev);
90 + BUG_ON(oldirq == 6);
94 - ssb_dprintk(KERN_INFO PFX
95 - "set_irq: core 0x%04x, irq %d => %d\n",
96 - dev->id.coreid, oldirq, irq);
97 /* clear the old irq */
99 ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
101 + else if (oldirq != 5)
102 clear_irq(bus, oldirq);
104 /* assign the new one */
106 ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
108 + u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
109 + if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
110 + u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
111 + struct ssb_device *olddev = find_device(dev, oldipsflag);
113 + set_irq(olddev, 0);
115 irqflag <<= ipsflag_irq_shift[irq];
116 - irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
117 + irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
118 ssb_write32(mdev, SSB_IPSFLAG, irqflag);
120 + ssb_dprintk(KERN_INFO PFX
121 + "set_irq: core 0x%04x, irq %d => %d\n",
122 + dev->id.coreid, oldirq+2, irq+2);
125 +static void print_irq(struct ssb_device *dev, unsigned int irq)
128 + static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
129 + ssb_dprintk(KERN_INFO PFX
130 + "core 0x%04x, irq :", dev->id.coreid);
131 + for (i = 0; i <= 6; i++) {
132 + ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
137 +static void dump_irq(struct ssb_bus *bus)
140 + for (i = 0; i < bus->nr_devices; i++) {
141 + struct ssb_device *dev;
142 + dev = &(bus->devices[i]);
143 + print_irq(dev, ssb_mips_irq(dev));
147 static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
148 @@ -195,18 +251,26 @@
149 else if (bus->chipco.dev)
150 ssb_chipco_timing_init(&bus->chipco, ns);
153 /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
154 for (irq = 2, i = 0; i < bus->nr_devices; i++) {
156 dev = &(bus->devices[i]);
157 - dev->irq = ssb_mips_irq(dev) + 2;
158 + mips_irq = ssb_mips_irq(dev);
162 + dev->irq = mips_irq + 2;
165 switch (dev->id.coreid) {
166 case SSB_DEV_USB11_HOST:
167 /* shouldn't need a separate irq line for non-4710, most of them have a proper
168 * external usb controller on the pci */
169 if ((bus->chip_id == 0x4710) && (irq <= 4)) {
176 case SSB_DEV_ETHERNET:
181 + ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
184 ssb_mips_serial_init(mcore);
185 ssb_mips_flash_detect(mcore);