Skip to content

Commit 708a15f

Browse files
Lorenzo Pieralisigregkh
authored andcommitted
alpha/PCI: Fix noname IRQ level detection
commit 86be899 upstream. The conversion of the alpha architecture PCI host bridge legacy IRQ mapping/swizzling to the new PCI host bridge map/swizzle hooks carried out through: commit 0e4c2ee ("alpha/PCI: Replace pci_fixup_irqs() call with host bridge IRQ mapping hooks") implies that IRQ for devices are now allocated through pci_assign_irq() function in pci_device_probe() that is called when a driver matching a device is found in order to probe the device through the device driver. Alpha noname platforms required IRQ level programming to be executed in sio_fixup_irq_levels(), that is called in noname_init_pci(), a platform hook called within a subsys_initcall. In noname_init_pci(), present IRQs are detected through sio_collect_irq_levels() that check the struct pci_dev->irq number to detect if an IRQ has been allocated for the device. By the time sio_collect_irq_levels() is called, some devices may still have not a matching driver loaded to match them (eg loadable module) therefore their IRQ allocation is still pending - which means that sio_collect_irq_levels() does not programme the correct IRQ level for those devices, causing their IRQ handling to be broken when the device driver is actually loaded and the device is probed. Fix the issue by adding code in the noname map_irq() function (noname_map_irq()) that, whilst mapping/swizzling the IRQ line, it also ensures that the correct IRQ level programming is executed at platform level, fixing the issue. Fixes: 0e4c2ee ("alpha/PCI: Replace pci_fixup_irqs() call with host bridge IRQ mapping hooks") Reported-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Richard Henderson <rth@twiddle.net> Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Cc: Mikulas Patocka <mpatocka@redhat.com> Cc: Meelis Roos <mroos@linux.ee> Signed-off-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 314a028 commit 708a15f

1 file changed

Lines changed: 29 additions & 6 deletions

File tree

arch/alpha/kernel/sys_sio.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ sio_pci_route(void)
102102
alpha_mv.sys.sio.route_tab);
103103
}
104104

105+
static bool sio_pci_dev_irq_needs_level(const struct pci_dev *dev)
106+
{
107+
if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
108+
(dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
109+
return false;
110+
111+
return true;
112+
}
113+
105114
static unsigned int __init
106115
sio_collect_irq_levels(void)
107116
{
@@ -110,8 +119,7 @@ sio_collect_irq_levels(void)
110119

111120
/* Iterate through the devices, collecting IRQ levels. */
112121
for_each_pci_dev(dev) {
113-
if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
114-
(dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
122+
if (!sio_pci_dev_irq_needs_level(dev))
115123
continue;
116124

117125
if (dev->irq)
@@ -120,8 +128,7 @@ sio_collect_irq_levels(void)
120128
return level_bits;
121129
}
122130

123-
static void __init
124-
sio_fixup_irq_levels(unsigned int level_bits)
131+
static void __sio_fixup_irq_levels(unsigned int level_bits, bool reset)
125132
{
126133
unsigned int old_level_bits;
127134

@@ -139,12 +146,21 @@ sio_fixup_irq_levels(unsigned int level_bits)
139146
*/
140147
old_level_bits = inb(0x4d0) | (inb(0x4d1) << 8);
141148

142-
level_bits |= (old_level_bits & 0x71ff);
149+
if (reset)
150+
old_level_bits &= 0x71ff;
151+
152+
level_bits |= old_level_bits;
143153

144154
outb((level_bits >> 0) & 0xff, 0x4d0);
145155
outb((level_bits >> 8) & 0xff, 0x4d1);
146156
}
147157

158+
static inline void
159+
sio_fixup_irq_levels(unsigned int level_bits)
160+
{
161+
__sio_fixup_irq_levels(level_bits, true);
162+
}
163+
148164
static inline int
149165
noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
150166
{
@@ -181,7 +197,14 @@ noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
181197
const long min_idsel = 6, max_idsel = 14, irqs_per_slot = 5;
182198
int irq = COMMON_TABLE_LOOKUP, tmp;
183199
tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq);
184-
return irq >= 0 ? tmp : -1;
200+
201+
irq = irq >= 0 ? tmp : -1;
202+
203+
/* Fixup IRQ level if an actual IRQ mapping is detected */
204+
if (sio_pci_dev_irq_needs_level(dev) && irq >= 0)
205+
__sio_fixup_irq_levels(1 << irq, false);
206+
207+
return irq;
185208
}
186209

187210
static inline int

0 commit comments

Comments
 (0)