]> err.no Git - linux-2.6/commitdiff
[POWERPC] Disable G5 NAP mode during SMU commands on U3
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 7 Feb 2008 03:29:43 +0000 (14:29 +1100)
committerPaul Mackerras <paulus@samba.org>
Fri, 8 Feb 2008 08:52:35 +0000 (19:52 +1100)
It appears that with the U3 northbridge, if the processor is in NAP
mode the whole time while waiting for an SMU command to complete,
then the SMU will fail.  It could be related to the weird backward
mechanism the SMU uses to get to system memory via i2c to the
northbridge that doesn't operate properly when the said bridge is
in napping along with the CPU.  That is on U3 at least, U4 doesn't
seem to be affected.

This didn't show before NO_HZ as the timer wakeup was enough to make
it work it seems, but that is no longer the case.

This fixes it by disabling NAP mode on those machines while
an SMU command is in flight.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/powermac/feature.c
drivers/macintosh/smu.c
include/asm-powerpc/pmac_feature.h

index ba931be2175c89addaa3c488d465de37a29fca10..5169ecc37123c07edd3a3344d37434031923eea9 100644 (file)
@@ -2565,6 +2565,8 @@ static void __init probe_uninorth(void)
 
        /* Locate core99 Uni-N */
        uninorth_node = of_find_node_by_name(NULL, "uni-n");
+       uninorth_maj = 1;
+
        /* Locate G5 u3 */
        if (uninorth_node == NULL) {
                uninorth_node = of_find_node_by_name(NULL, "u3");
@@ -2575,8 +2577,10 @@ static void __init probe_uninorth(void)
                uninorth_node = of_find_node_by_name(NULL, "u4");
                uninorth_maj = 4;
        }
-       if (uninorth_node == NULL)
+       if (uninorth_node == NULL) {
+               uninorth_maj = 0;
                return;
+       }
 
        addrp = of_get_property(uninorth_node, "reg", NULL);
        if (addrp == NULL)
@@ -3029,3 +3033,8 @@ void pmac_resume_agp_for_card(struct pci_dev *dev)
        pmac_agp_resume(pmac_agp_bridge);
 }
 EXPORT_SYMBOL(pmac_resume_agp_for_card);
+
+int pmac_get_uninorth_variant(void)
+{
+       return uninorth_maj;
+}
index 8ba49385c3ff4fd149c21980eabf0cc1996ee32b..77ad192962c55acac9cba759471890a4538f5625 100644 (file)
@@ -85,6 +85,7 @@ struct smu_device {
        u32                     cmd_buf_abs;    /* command buffer absolute */
        struct list_head        cmd_list;
        struct smu_cmd          *cmd_cur;       /* pending command */
+       int                     broken_nap;
        struct list_head        cmd_i2c_list;
        struct smu_i2c_cmd      *cmd_i2c_cur;   /* pending i2c command */
        struct timer_list       i2c_timer;
@@ -135,6 +136,19 @@ static void smu_start_cmd(void)
        fend = faddr + smu->cmd_buf->length + 2;
        flush_inval_dcache_range(faddr, fend);
 
+
+       /* We also disable NAP mode for the duration of the command
+        * on U3 based machines.
+        * This is slightly racy as it can be written back to 1 by a sysctl
+        * but that never happens in practice. There seem to be an issue with
+        * U3 based machines such as the iMac G5 where napping for the
+        * whole duration of the command prevents the SMU from fetching it
+        * from memory. This might be related to the strange i2c based
+        * mechanism the SMU uses to access memory.
+        */
+       if (smu->broken_nap)
+               powersave_nap = 0;
+
        /* This isn't exactly a DMA mapping here, I suspect
         * the SMU is actually communicating with us via i2c to the
         * northbridge or the CPU to access RAM.
@@ -211,6 +225,10 @@ static irqreturn_t smu_db_intr(int irq, void *arg)
        misc = cmd->misc;
        mb();
        cmd->status = rc;
+
+       /* Re-enable NAP mode */
+       if (smu->broken_nap)
+               powersave_nap = 1;
  bail:
        /* Start next command if any */
        smu_start_cmd();
@@ -461,7 +479,7 @@ int __init smu_init (void)
         if (np == NULL)
                return -ENODEV;
 
-       printk(KERN_INFO "SMU driver %s %s\n", VERSION, AUTHOR);
+       printk(KERN_INFO "SMU: Driver %s %s\n", VERSION, AUTHOR);
 
        if (smu_cmdbuf_abs == 0) {
                printk(KERN_ERR "SMU: Command buffer not allocated !\n");
@@ -533,6 +551,11 @@ int __init smu_init (void)
                goto fail;
        }
 
+       /* U3 has an issue with NAP mode when issuing SMU commands */
+       smu->broken_nap = pmac_get_uninorth_variant() < 4;
+       if (smu->broken_nap)
+               printk(KERN_INFO "SMU: using NAP mode workaround\n");
+
        sys_ctrler = SYS_CTRLER_SMU;
        return 0;
 
index 26bcb0aa164a2a470e2058b7384a8584440941b7..877c35a4356ed954317e1aa0546b07980f57a434 100644 (file)
@@ -392,6 +392,14 @@ extern u32 __iomem *uninorth_base;
 #define UN_BIS(r,v)    (UN_OUT((r), UN_IN(r) | (v)))
 #define UN_BIC(r,v)    (UN_OUT((r), UN_IN(r) & ~(v)))
 
+/* Uninorth variant:
+ *
+ * 0 = not uninorth
+ * 1 = U1.x or U2.x
+ * 3 = U3
+ * 4 = U4
+ */
+extern int pmac_get_uninorth_variant(void);
 
 #endif /* __ASM_POWERPC_PMAC_FEATURE_H */
 #endif /* __KERNEL__ */