Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/pmac: Simplify old pmac PIC interrupt handling

In the old days, we treated all interrupts from the legacy Apple home made
interrupt controllers as level, with a trick reading the "level" register
along with the "event" register to work arounds bugs where it would
occasionally fail to latch some events.

Doing so appeared to work fine for both level and edge interrupts.

Later on, we discovered in Darwin source the magic masks that define which
interrupts are actually level and which are edge, and implemented a
different algorithm, more similar to what Apple does, that treats those
differently.

I recently discovered however that this caused problems (including loss
of interrupts) with an old Wallstreet PowerBook when trying to use the
internal modem (connected to a cascaded controller).

It looks like some interrupts are treated as edge while they are really
level and I'm starting to seriously doubt the correctness of the Darwin
code (which has other obvious bugs when you read it, so ...)

This patch reverts to our original behaviour of treating everything as
a level interrupt. It appears to solve the problems with the modem on
the Wallstreet and everything else seems to be working properly as well.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

+6 -28
+6 -28
arch/powerpc/platforms/powermac/pic.c
··· 52 52 /* Default addresses */ 53 53 static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4]; 54 54 55 - #define GC_LEVEL_MASK 0x3ff00000 56 - #define OHARE_LEVEL_MASK 0x1ff00000 57 - #define HEATHROW_LEVEL_MASK 0x1ff00000 58 - 59 55 static int max_irqs; 60 56 static int max_real_irqs; 61 - static u32 level_mask[4]; 62 57 63 58 static DEFINE_RAW_SPINLOCK(pmac_pic_lock); 64 59 ··· 212 217 for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { 213 218 int i = irq >> 5; 214 219 bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; 215 - /* We must read level interrupts from the level register */ 216 - bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); 220 + bits |= in_le32(&pmac_irq_hw[i]->level); 217 221 bits &= ppc_cached_irq_mask[i]; 218 222 if (bits == 0) 219 223 continue; ··· 242 248 for (irq = max_real_irqs; (irq -= 32) >= 0; ) { 243 249 int i = irq >> 5; 244 250 bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; 245 - /* We must read level interrupts from the level register */ 246 - bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); 251 + bits |= in_le32(&pmac_irq_hw[i]->level); 247 252 bits &= ppc_cached_irq_mask[i]; 248 253 if (bits == 0) 249 254 continue; ··· 277 284 static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, 278 285 irq_hw_number_t hw) 279 286 { 280 - int level; 281 - 282 287 if (hw >= max_irqs) 283 288 return -EINVAL; 284 289 285 290 /* Mark level interrupts, set delayed disable for edge ones and set 286 291 * handlers 287 292 */ 288 - level = !!(level_mask[hw >> 5] & (1UL << (hw & 0x1f))); 289 - if (level) 290 - irq_set_status_flags(virq, IRQ_LEVEL); 291 - irq_set_chip_and_handler(virq, &pmac_pic, 292 - level ? handle_level_irq : handle_edge_irq); 293 + irq_set_status_flags(virq, IRQ_LEVEL); 294 + irq_set_chip_and_handler(virq, &pmac_pic, handle_level_irq); 293 295 return 0; 294 296 } 295 297 ··· 322 334 323 335 if ((master = of_find_node_by_name(NULL, "gc")) != NULL) { 324 336 max_irqs = max_real_irqs = 32; 325 - level_mask[0] = GC_LEVEL_MASK; 326 337 } else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) { 327 338 max_irqs = max_real_irqs = 32; 328 - level_mask[0] = OHARE_LEVEL_MASK; 329 - 330 339 /* We might have a second cascaded ohare */ 331 340 slave = of_find_node_by_name(NULL, "pci106b,7"); 332 - if (slave) { 341 + if (slave) 333 342 max_irqs = 64; 334 - level_mask[1] = OHARE_LEVEL_MASK; 335 - } 336 343 } else if ((master = of_find_node_by_name(NULL, "mac-io")) != NULL) { 337 344 max_irqs = max_real_irqs = 64; 338 - level_mask[0] = HEATHROW_LEVEL_MASK; 339 - level_mask[1] = 0; 340 345 341 346 /* We might have a second cascaded heathrow */ 342 347 slave = of_find_node_by_name(master, "mac-io"); ··· 344 363 } 345 364 346 365 /* We found a slave */ 347 - if (slave) { 366 + if (slave) 348 367 max_irqs = 128; 349 - level_mask[2] = HEATHROW_LEVEL_MASK; 350 - level_mask[3] = 0; 351 - } 352 368 } 353 369 BUG_ON(master == NULL); 354 370