Commit 592a607bbc053bc6f614a0e619326009f4b3829e

Authored by Benjamin Herrenschmidt
Committed by Paul Mackerras
1 parent a4ffc0a0b2

[POWERPC] Disable G5 NAP mode during SMU commands on U3

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>

Showing 3 changed files with 42 additions and 2 deletions Side-by-side Diff

arch/powerpc/platforms/powermac/feature.c
... ... @@ -2565,6 +2565,8 @@
2565 2565  
2566 2566 /* Locate core99 Uni-N */
2567 2567 uninorth_node = of_find_node_by_name(NULL, "uni-n");
  2568 + uninorth_maj = 1;
  2569 +
2568 2570 /* Locate G5 u3 */
2569 2571 if (uninorth_node == NULL) {
2570 2572 uninorth_node = of_find_node_by_name(NULL, "u3");
2571 2573  
... ... @@ -2575,8 +2577,10 @@
2575 2577 uninorth_node = of_find_node_by_name(NULL, "u4");
2576 2578 uninorth_maj = 4;
2577 2579 }
2578   - if (uninorth_node == NULL)
  2580 + if (uninorth_node == NULL) {
  2581 + uninorth_maj = 0;
2579 2582 return;
  2583 + }
2580 2584  
2581 2585 addrp = of_get_property(uninorth_node, "reg", NULL);
2582 2586 if (addrp == NULL)
... ... @@ -3029,4 +3033,9 @@
3029 3033 pmac_agp_resume(pmac_agp_bridge);
3030 3034 }
3031 3035 EXPORT_SYMBOL(pmac_resume_agp_for_card);
  3036 +
  3037 +int pmac_get_uninorth_variant(void)
  3038 +{
  3039 + return uninorth_maj;
  3040 +}
drivers/macintosh/smu.c
... ... @@ -85,6 +85,7 @@
85 85 u32 cmd_buf_abs; /* command buffer absolute */
86 86 struct list_head cmd_list;
87 87 struct smu_cmd *cmd_cur; /* pending command */
  88 + int broken_nap;
88 89 struct list_head cmd_i2c_list;
89 90 struct smu_i2c_cmd *cmd_i2c_cur; /* pending i2c command */
90 91 struct timer_list i2c_timer;
... ... @@ -135,6 +136,19 @@
135 136 fend = faddr + smu->cmd_buf->length + 2;
136 137 flush_inval_dcache_range(faddr, fend);
137 138  
  139 +
  140 + /* We also disable NAP mode for the duration of the command
  141 + * on U3 based machines.
  142 + * This is slightly racy as it can be written back to 1 by a sysctl
  143 + * but that never happens in practice. There seem to be an issue with
  144 + * U3 based machines such as the iMac G5 where napping for the
  145 + * whole duration of the command prevents the SMU from fetching it
  146 + * from memory. This might be related to the strange i2c based
  147 + * mechanism the SMU uses to access memory.
  148 + */
  149 + if (smu->broken_nap)
  150 + powersave_nap = 0;
  151 +
138 152 /* This isn't exactly a DMA mapping here, I suspect
139 153 * the SMU is actually communicating with us via i2c to the
140 154 * northbridge or the CPU to access RAM.
... ... @@ -211,6 +225,10 @@
211 225 misc = cmd->misc;
212 226 mb();
213 227 cmd->status = rc;
  228 +
  229 + /* Re-enable NAP mode */
  230 + if (smu->broken_nap)
  231 + powersave_nap = 1;
214 232 bail:
215 233 /* Start next command if any */
216 234 smu_start_cmd();
... ... @@ -461,7 +479,7 @@
461 479 if (np == NULL)
462 480 return -ENODEV;
463 481  
464   - printk(KERN_INFO "SMU driver %s %s\n", VERSION, AUTHOR);
  482 + printk(KERN_INFO "SMU: Driver %s %s\n", VERSION, AUTHOR);
465 483  
466 484 if (smu_cmdbuf_abs == 0) {
467 485 printk(KERN_ERR "SMU: Command buffer not allocated !\n");
... ... @@ -532,6 +550,11 @@
532 550 printk(KERN_ERR "SMU: Can't map doorbell buffer pointer !\n");
533 551 goto fail;
534 552 }
  553 +
  554 + /* U3 has an issue with NAP mode when issuing SMU commands */
  555 + smu->broken_nap = pmac_get_uninorth_variant() < 4;
  556 + if (smu->broken_nap)
  557 + printk(KERN_INFO "SMU: using NAP mode workaround\n");
535 558  
536 559 sys_ctrler = SYS_CTRLER_SMU;
537 560 return 0;
include/asm-powerpc/pmac_feature.h
... ... @@ -392,6 +392,14 @@
392 392 #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v)))
393 393 #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v)))
394 394  
  395 +/* Uninorth variant:
  396 + *
  397 + * 0 = not uninorth
  398 + * 1 = U1.x or U2.x
  399 + * 3 = U3
  400 + * 4 = U4
  401 + */
  402 +extern int pmac_get_uninorth_variant(void);
395 403  
396 404 #endif /* __ASM_POWERPC_PMAC_FEATURE_H */
397 405 #endif /* __KERNEL__ */