diff options
author | Finn Thain <fthain@telegraphics.com.au> | 2016-12-05 01:07:20 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2016-12-08 16:57:58 -0500 |
commit | 145c3ae4c1933d0dceb11d19a36de3458d1872cb (patch) | |
tree | c47c5d1f19042afb9f56fce1ac61809452c8b553 | |
parent | 906e4a3c7e03701008d343daec8952d6cf49f82b (diff) |
scsi: g_NCR5380: Fix automatic IRQ on HP C2502 cards
When IRQ_AUTO is used, the interrupt for HP C2502 cards gets disabled.
Fix this by programming the card for a suitable free irq. The code for
the free irq search comes from ALSA.
Also allow IRQ 9 to work (it aliases to IRQ 2 on the card), as per
Ondrej Zary's patch.
Suggested-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Tested-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/scsi/g_NCR5380.c | 70 |
1 files changed, 57 insertions, 13 deletions
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 6d245a7b9363..58a0b826eb51 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c | |||
@@ -131,14 +131,33 @@ static void magic_configure(int idx, u8 irq, u8 magic[]) | |||
131 | outb(magic[3], 0x379); | 131 | outb(magic[3], 0x379); |
132 | outb(magic[4], 0x379); | 132 | outb(magic[4], 0x379); |
133 | 133 | ||
134 | /* allowed IRQs for HP C2502 */ | 134 | if (irq == 9) |
135 | if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7) | 135 | irq = 2; |
136 | irq = 0; | 136 | |
137 | if (idx >= 0 && idx <= 7) | 137 | if (idx >= 0 && idx <= 7) |
138 | cfg = 0x80 | idx | (irq << 4); | 138 | cfg = 0x80 | idx | (irq << 4); |
139 | outb(cfg, 0x379); | 139 | outb(cfg, 0x379); |
140 | } | 140 | } |
141 | 141 | ||
142 | static irqreturn_t legacy_empty_irq_handler(int irq, void *dev_id) | ||
143 | { | ||
144 | return IRQ_HANDLED; | ||
145 | } | ||
146 | |||
147 | static int legacy_find_free_irq(int *irq_table) | ||
148 | { | ||
149 | while (*irq_table != -1) { | ||
150 | if (!request_irq(*irq_table, legacy_empty_irq_handler, | ||
151 | IRQF_PROBE_SHARED, "Test IRQ", | ||
152 | (void *)irq_table)) { | ||
153 | free_irq(*irq_table, (void *) irq_table); | ||
154 | return *irq_table; | ||
155 | } | ||
156 | irq_table++; | ||
157 | } | ||
158 | return -1; | ||
159 | } | ||
160 | |||
142 | static unsigned int ncr_53c400a_ports[] = { | 161 | static unsigned int ncr_53c400a_ports[] = { |
143 | 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 | 162 | 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 |
144 | }; | 163 | }; |
@@ -151,6 +170,9 @@ static u8 ncr_53c400a_magic[] = { /* 53C400A & DTC436 */ | |||
151 | static u8 hp_c2502_magic[] = { /* HP C2502 */ | 170 | static u8 hp_c2502_magic[] = { /* HP C2502 */ |
152 | 0x0f, 0x22, 0xf0, 0x20, 0x80 | 171 | 0x0f, 0x22, 0xf0, 0x20, 0x80 |
153 | }; | 172 | }; |
173 | static int hp_c2502_irqs[] = { | ||
174 | 9, 5, 7, 3, 4, -1 | ||
175 | }; | ||
154 | 176 | ||
155 | static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, | 177 | static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, |
156 | struct device *pdev, int base, int irq, int board) | 178 | struct device *pdev, int base, int irq, int board) |
@@ -319,19 +341,41 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, | |||
319 | 341 | ||
320 | NCR5380_maybe_reset_bus(instance); | 342 | NCR5380_maybe_reset_bus(instance); |
321 | 343 | ||
322 | if (irq != IRQ_AUTO) | ||
323 | instance->irq = irq; | ||
324 | else | ||
325 | instance->irq = g_NCR5380_probe_irq(instance); | ||
326 | |||
327 | /* Compatibility with documented NCR5380 kernel parameters */ | 344 | /* Compatibility with documented NCR5380 kernel parameters */ |
328 | if (instance->irq == 255) | 345 | if (irq == 255 || irq == 0) |
329 | instance->irq = NO_IRQ; | 346 | irq = NO_IRQ; |
347 | |||
348 | if (board == BOARD_HP_C2502) { | ||
349 | int *irq_table = hp_c2502_irqs; | ||
350 | int board_irq = -1; | ||
351 | |||
352 | switch (irq) { | ||
353 | case NO_IRQ: | ||
354 | board_irq = 0; | ||
355 | break; | ||
356 | case IRQ_AUTO: | ||
357 | board_irq = legacy_find_free_irq(irq_table); | ||
358 | break; | ||
359 | default: | ||
360 | while (*irq_table != -1) | ||
361 | if (*irq_table++ == irq) | ||
362 | board_irq = irq; | ||
363 | } | ||
364 | |||
365 | if (board_irq <= 0) { | ||
366 | board_irq = 0; | ||
367 | irq = NO_IRQ; | ||
368 | } | ||
369 | |||
370 | magic_configure(port_idx, board_irq, magic); | ||
371 | } | ||
372 | |||
373 | if (irq == IRQ_AUTO) | ||
374 | instance->irq = g_NCR5380_probe_irq(instance); | ||
375 | else | ||
376 | instance->irq = irq; | ||
330 | 377 | ||
331 | if (instance->irq != NO_IRQ) { | 378 | if (instance->irq != NO_IRQ) { |
332 | /* set IRQ for HP C2502 */ | ||
333 | if (board == BOARD_HP_C2502) | ||
334 | magic_configure(port_idx, instance->irq, magic); | ||
335 | if (request_irq(instance->irq, generic_NCR5380_intr, | 379 | if (request_irq(instance->irq, generic_NCR5380_intr, |
336 | 0, "NCR5380", instance)) { | 380 | 0, "NCR5380", instance)) { |
337 | printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); | 381 | printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); |