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

[PATCH] powerpc: fix SMU driver interrupt mapping

The SMU driver tries to map an interrupt from the device-tree before the
interrupt controllers in the machine have been enumerated. This doesn't work
properly and cause machines like the Quad g5 to fail booting later on when
some drivers waits endlessly for an SMU request to complete. This is the
second problem preventing boot on the Quad g5. This fixes it and also makes
the SMU driver a bit more resilient to not having an interrupt.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Benjamin Herrenschmidt and committed by
Linus Torvalds
f620753b 06fe98e6

+38 -15
+38 -15
drivers/macintosh/smu.c
··· 75 75 struct of_device *of_dev; 76 76 int doorbell; /* doorbell gpio */ 77 77 u32 __iomem *db_buf; /* doorbell buffer */ 78 - int db_irq; 78 + struct device_node *db_node; 79 + unsigned int db_irq; 79 80 int msg; 80 - int msg_irq; 81 + struct device_node *msg_node; 82 + unsigned int msg_irq; 81 83 struct smu_cmd_buf *cmd_buf; /* command buffer virtual */ 82 84 u32 cmd_buf_abs; /* command buffer absolute */ 83 85 struct list_head cmd_list; ··· 95 93 */ 96 94 static struct smu_device *smu; 97 95 static DEFINE_MUTEX(smu_part_access); 96 + static int smu_irq_inited; 98 97 99 98 static void smu_i2c_retry(unsigned long data); 100 99 ··· 259 256 if (smu->cmd_cur == NULL) 260 257 smu_start_cmd(); 261 258 spin_unlock_irqrestore(&smu->lock, flags); 259 + 260 + /* Workaround for early calls when irq isn't available */ 261 + if (!smu_irq_inited || smu->db_irq == NO_IRQ) 262 + smu_spinwait_cmd(cmd); 262 263 263 264 return 0; 264 265 } ··· 485 478 smu->cmd_buf_abs = (u32)smu_cmdbuf_abs; 486 479 smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs); 487 480 488 - np = of_find_node_by_name(NULL, "smu-doorbell"); 489 - if (np == NULL) { 481 + smu->db_node = of_find_node_by_name(NULL, "smu-doorbell"); 482 + if (smu->db_node == NULL) { 490 483 printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n"); 491 484 goto fail; 492 485 } 493 - data = (u32 *)get_property(np, "reg", NULL); 486 + data = (u32 *)get_property(smu->db_node, "reg", NULL); 494 487 if (data == NULL) { 495 - of_node_put(np); 488 + of_node_put(smu->db_node); 489 + smu->db_node = NULL; 496 490 printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n"); 497 491 goto fail; 498 492 } ··· 505 497 smu->doorbell = *data; 506 498 if (smu->doorbell < 0x50) 507 499 smu->doorbell += 0x50; 508 - smu->db_irq = irq_of_parse_and_map(np, 0); 509 - 510 - of_node_put(np); 511 500 512 501 /* Now look for the smu-interrupt GPIO */ 513 502 do { 514 - np = of_find_node_by_name(NULL, "smu-interrupt"); 515 - if (np == NULL) 503 + smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt"); 504 + if (smu->msg_node == NULL) 516 505 break; 517 - data = (u32 *)get_property(np, "reg", NULL); 506 + data = (u32 *)get_property(smu->msg_node, "reg", NULL); 518 507 if (data == NULL) { 519 - of_node_put(np); 508 + of_node_put(smu->msg_node); 509 + smu->msg_node = NULL; 520 510 break; 521 511 } 522 512 smu->msg = *data; 523 513 if (smu->msg < 0x50) 524 514 smu->msg += 0x50; 525 - smu->msg_irq = irq_of_parse_and_map(np, 0); 526 - of_node_put(np); 527 515 } while(0); 528 516 529 517 /* Doorbell buffer is currently hard-coded, I didn't find a proper ··· 551 547 smu->i2c_timer.function = smu_i2c_retry; 552 548 smu->i2c_timer.data = (unsigned long)smu; 553 549 550 + if (smu->db_node) { 551 + smu->db_irq = irq_of_parse_and_map(smu->db_node, 0); 552 + if (smu->db_irq == NO_IRQ) 553 + printk(KERN_ERR "smu: failed to map irq for node %s\n", 554 + smu->db_node->full_name); 555 + } 556 + if (smu->msg_node) { 557 + smu->msg_irq = irq_of_parse_and_map(smu->msg_node, 0); 558 + if (smu->msg_irq == NO_IRQ) 559 + printk(KERN_ERR "smu: failed to map irq for node %s\n", 560 + smu->msg_node->full_name); 561 + } 562 + 554 563 /* 555 564 * Try to request the interrupts 556 565 */ ··· 588 571 } 589 572 } 590 573 574 + smu_irq_inited = 1; 591 575 return 0; 592 576 } 593 577 /* This has to be before arch_initcall as the low i2c stuff relies on the ··· 760 742 if (fail && --cmd->retries > 0) { 761 743 DPRINTK("SMU: i2c failure, starting timer...\n"); 762 744 BUG_ON(cmd != smu->cmd_i2c_cur); 745 + if (!smu_irq_inited) { 746 + mdelay(5); 747 + smu_i2c_retry(0); 748 + return; 749 + } 763 750 mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5)); 764 751 return; 765 752 }