Commit 592a607bbc053bc6f614a0e619326009f4b3829e
Committed by
Paul Mackerras
1 parent
a4ffc0a0b2
Exists in
master
and in
39 other branches
[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__ */ |