diff options
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/entry_32.S | 17 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/legacy_serial.c | 44 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 39 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 54 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup-common.c | 24 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.c | 23 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 119 | ||||
-rw-r--r-- | arch/powerpc/kernel/stacktrace.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/sysfs.c | 311 | ||||
-rw-r--r-- | arch/powerpc/kernel/vio.c | 6 |
13 files changed, 517 insertions, 142 deletions
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 81c8324a4a3c..1cbbf7033641 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -148,7 +148,7 @@ transfer_to_handler: | |||
148 | /* Check to see if the dbcr0 register is set up to debug. Use the | 148 | /* Check to see if the dbcr0 register is set up to debug. Use the |
149 | internal debug mode bit to do this. */ | 149 | internal debug mode bit to do this. */ |
150 | lwz r12,THREAD_DBCR0(r12) | 150 | lwz r12,THREAD_DBCR0(r12) |
151 | andis. r12,r12,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h | 151 | andis. r12,r12,DBCR0_IDM@h |
152 | beq+ 3f | 152 | beq+ 3f |
153 | /* From user and task is ptraced - load up global dbcr0 */ | 153 | /* From user and task is ptraced - load up global dbcr0 */ |
154 | li r12,-1 /* clear all pending debug events */ | 154 | li r12,-1 /* clear all pending debug events */ |
@@ -292,7 +292,7 @@ syscall_exit_cont: | |||
292 | /* If the process has its own DBCR0 value, load it up. The internal | 292 | /* If the process has its own DBCR0 value, load it up. The internal |
293 | debug mode bit tells us that dbcr0 should be loaded. */ | 293 | debug mode bit tells us that dbcr0 should be loaded. */ |
294 | lwz r0,THREAD+THREAD_DBCR0(r2) | 294 | lwz r0,THREAD+THREAD_DBCR0(r2) |
295 | andis. r10,r0,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h | 295 | andis. r10,r0,DBCR0_IDM@h |
296 | bnel- load_dbcr0 | 296 | bnel- load_dbcr0 |
297 | #endif | 297 | #endif |
298 | #ifdef CONFIG_44x | 298 | #ifdef CONFIG_44x |
@@ -343,7 +343,12 @@ syscall_dotrace: | |||
343 | stw r0,_TRAP(r1) | 343 | stw r0,_TRAP(r1) |
344 | addi r3,r1,STACK_FRAME_OVERHEAD | 344 | addi r3,r1,STACK_FRAME_OVERHEAD |
345 | bl do_syscall_trace_enter | 345 | bl do_syscall_trace_enter |
346 | lwz r0,GPR0(r1) /* Restore original registers */ | 346 | /* |
347 | * Restore argument registers possibly just changed. | ||
348 | * We use the return value of do_syscall_trace_enter | ||
349 | * for call number to look up in the table (r0). | ||
350 | */ | ||
351 | mr r0,r3 | ||
347 | lwz r3,GPR3(r1) | 352 | lwz r3,GPR3(r1) |
348 | lwz r4,GPR4(r1) | 353 | lwz r4,GPR4(r1) |
349 | lwz r5,GPR5(r1) | 354 | lwz r5,GPR5(r1) |
@@ -720,7 +725,7 @@ restore_user: | |||
720 | /* Check whether this process has its own DBCR0 value. The internal | 725 | /* Check whether this process has its own DBCR0 value. The internal |
721 | debug mode bit tells us that dbcr0 should be loaded. */ | 726 | debug mode bit tells us that dbcr0 should be loaded. */ |
722 | lwz r0,THREAD+THREAD_DBCR0(r2) | 727 | lwz r0,THREAD+THREAD_DBCR0(r2) |
723 | andis. r10,r0,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h | 728 | andis. r10,r0,DBCR0_IDM@h |
724 | bnel- load_dbcr0 | 729 | bnel- load_dbcr0 |
725 | #endif | 730 | #endif |
726 | 731 | ||
@@ -1055,8 +1060,8 @@ do_user_signal: /* r10 contains MSR_KERNEL here */ | |||
1055 | SAVE_NVGPRS(r1) | 1060 | SAVE_NVGPRS(r1) |
1056 | rlwinm r3,r3,0,0,30 | 1061 | rlwinm r3,r3,0,0,30 |
1057 | stw r3,_TRAP(r1) | 1062 | stw r3,_TRAP(r1) |
1058 | 2: li r3,0 | 1063 | 2: addi r3,r1,STACK_FRAME_OVERHEAD |
1059 | addi r4,r1,STACK_FRAME_OVERHEAD | 1064 | mr r4,r9 |
1060 | bl do_signal | 1065 | bl do_signal |
1061 | REST_NVGPRS(r1) | 1066 | REST_NVGPRS(r1) |
1062 | b recheck | 1067 | b recheck |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index d7369243ae44..2d802e97097c 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -214,7 +214,12 @@ syscall_dotrace: | |||
214 | bl .save_nvgprs | 214 | bl .save_nvgprs |
215 | addi r3,r1,STACK_FRAME_OVERHEAD | 215 | addi r3,r1,STACK_FRAME_OVERHEAD |
216 | bl .do_syscall_trace_enter | 216 | bl .do_syscall_trace_enter |
217 | ld r0,GPR0(r1) /* Restore original registers */ | 217 | /* |
218 | * Restore argument registers possibly just changed. | ||
219 | * We use the return value of do_syscall_trace_enter | ||
220 | * for the call number to look up in the table (r0). | ||
221 | */ | ||
222 | mr r0,r3 | ||
218 | ld r3,GPR3(r1) | 223 | ld r3,GPR3(r1) |
219 | ld r4,GPR4(r1) | 224 | ld r4,GPR4(r1) |
220 | ld r5,GPR5(r1) | 225 | ld r5,GPR5(r1) |
@@ -638,8 +643,7 @@ user_work: | |||
638 | b .ret_from_except_lite | 643 | b .ret_from_except_lite |
639 | 644 | ||
640 | 1: bl .save_nvgprs | 645 | 1: bl .save_nvgprs |
641 | li r3,0 | 646 | addi r3,r1,STACK_FRAME_OVERHEAD |
642 | addi r4,r1,STACK_FRAME_OVERHEAD | ||
643 | bl .do_signal | 647 | bl .do_signal |
644 | b .ret_from_except | 648 | b .ret_from_except |
645 | 649 | ||
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 4d96e1db55ee..9ddfaef1a184 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c | |||
@@ -493,18 +493,18 @@ static int __init serial_dev_init(void) | |||
493 | device_initcall(serial_dev_init); | 493 | device_initcall(serial_dev_init); |
494 | 494 | ||
495 | 495 | ||
496 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
496 | /* | 497 | /* |
497 | * This is called very early, as part of console_init() (typically just after | 498 | * This is called very early, as part of console_init() (typically just after |
498 | * time_init()). This function is respondible for trying to find a good | 499 | * time_init()). This function is respondible for trying to find a good |
499 | * default console on serial ports. It tries to match the open firmware | 500 | * default console on serial ports. It tries to match the open firmware |
500 | * default output with one of the available serial console drivers, either | 501 | * default output with one of the available serial console drivers that have |
501 | * one of the platform serial ports that have been probed earlier by | 502 | * been probed earlier by find_legacy_serial_ports() |
502 | * find_legacy_serial_ports() or some more platform specific ones. | ||
503 | */ | 503 | */ |
504 | static int __init check_legacy_serial_console(void) | 504 | static int __init check_legacy_serial_console(void) |
505 | { | 505 | { |
506 | struct device_node *prom_stdout = NULL; | 506 | struct device_node *prom_stdout = NULL; |
507 | int speed = 0, offset = 0; | 507 | int i, speed = 0, offset = 0; |
508 | const char *name; | 508 | const char *name; |
509 | const u32 *spd; | 509 | const u32 *spd; |
510 | 510 | ||
@@ -548,31 +548,20 @@ static int __init check_legacy_serial_console(void) | |||
548 | if (spd) | 548 | if (spd) |
549 | speed = *spd; | 549 | speed = *spd; |
550 | 550 | ||
551 | if (0) | 551 | if (strcmp(name, "serial") != 0) |
552 | ; | 552 | goto not_found; |
553 | #ifdef CONFIG_SERIAL_8250_CONSOLE | 553 | |
554 | else if (strcmp(name, "serial") == 0) { | 554 | /* Look for it in probed array */ |
555 | int i; | 555 | for (i = 0; i < legacy_serial_count; i++) { |
556 | /* Look for it in probed array */ | 556 | if (prom_stdout != legacy_serial_infos[i].np) |
557 | for (i = 0; i < legacy_serial_count; i++) { | 557 | continue; |
558 | if (prom_stdout != legacy_serial_infos[i].np) | 558 | offset = i; |
559 | continue; | 559 | speed = legacy_serial_infos[i].speed; |
560 | offset = i; | 560 | break; |
561 | speed = legacy_serial_infos[i].speed; | ||
562 | break; | ||
563 | } | ||
564 | if (i >= legacy_serial_count) | ||
565 | goto not_found; | ||
566 | } | 561 | } |
567 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ | 562 | if (i >= legacy_serial_count) |
568 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE | ||
569 | else if (strcmp(name, "ch-a") == 0) | ||
570 | offset = 0; | ||
571 | else if (strcmp(name, "ch-b") == 0) | ||
572 | offset = 1; | ||
573 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ | ||
574 | else | ||
575 | goto not_found; | 563 | goto not_found; |
564 | |||
576 | of_node_put(prom_stdout); | 565 | of_node_put(prom_stdout); |
577 | 566 | ||
578 | DBG("Found serial console at ttyS%d\n", offset); | 567 | DBG("Found serial console at ttyS%d\n", offset); |
@@ -591,3 +580,4 @@ static int __init check_legacy_serial_console(void) | |||
591 | } | 580 | } |
592 | console_initcall(check_legacy_serial_console); | 581 | console_initcall(check_legacy_serial_console); |
593 | 582 | ||
583 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ | ||
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index db2497ccc111..e030f3bd5024 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -254,7 +254,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address, | |||
254 | return; | 254 | return; |
255 | 255 | ||
256 | /* Clear the DAC and struct entries. One shot trigger */ | 256 | /* Clear the DAC and struct entries. One shot trigger */ |
257 | #if (defined(CONFIG_44x) || defined(CONFIG_BOOKE)) | 257 | #if defined(CONFIG_BOOKE) |
258 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | DBSR_DAC1W | 258 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | DBSR_DAC1W |
259 | | DBCR0_IDM)); | 259 | | DBCR0_IDM)); |
260 | #endif | 260 | #endif |
@@ -286,7 +286,7 @@ int set_dabr(unsigned long dabr) | |||
286 | mtspr(SPRN_DABR, dabr); | 286 | mtspr(SPRN_DABR, dabr); |
287 | #endif | 287 | #endif |
288 | 288 | ||
289 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | 289 | #if defined(CONFIG_BOOKE) |
290 | mtspr(SPRN_DAC1, dabr); | 290 | mtspr(SPRN_DAC1, dabr); |
291 | #endif | 291 | #endif |
292 | 292 | ||
@@ -373,7 +373,7 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
373 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) | 373 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) |
374 | set_dabr(new->thread.dabr); | 374 | set_dabr(new->thread.dabr); |
375 | 375 | ||
376 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | 376 | #if defined(CONFIG_BOOKE) |
377 | /* If new thread DAC (HW breakpoint) is the same then leave it */ | 377 | /* If new thread DAC (HW breakpoint) is the same then leave it */ |
378 | if (new->thread.dabr) | 378 | if (new->thread.dabr) |
379 | set_dabr(new->thread.dabr); | 379 | set_dabr(new->thread.dabr); |
@@ -568,7 +568,7 @@ void flush_thread(void) | |||
568 | current->thread.dabr = 0; | 568 | current->thread.dabr = 0; |
569 | set_dabr(0); | 569 | set_dabr(0); |
570 | 570 | ||
571 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | 571 | #if defined(CONFIG_BOOKE) |
572 | current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W); | 572 | current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W); |
573 | #endif | 573 | #endif |
574 | } | 574 | } |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index c4ab2195b9cb..b72849ac7db3 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -205,8 +205,6 @@ static int __initdata mem_reserve_cnt; | |||
205 | static cell_t __initdata regbuf[1024]; | 205 | static cell_t __initdata regbuf[1024]; |
206 | 206 | ||
207 | 207 | ||
208 | #define MAX_CPU_THREADS 2 | ||
209 | |||
210 | /* | 208 | /* |
211 | * Error results ... some OF calls will return "-1" on error, some | 209 | * Error results ... some OF calls will return "-1" on error, some |
212 | * will return 0, some will return either. To simplify, here are | 210 | * will return 0, some will return either. To simplify, here are |
@@ -1339,10 +1337,6 @@ static void __init prom_hold_cpus(void) | |||
1339 | unsigned int reg; | 1337 | unsigned int reg; |
1340 | phandle node; | 1338 | phandle node; |
1341 | char type[64]; | 1339 | char type[64]; |
1342 | int cpuid = 0; | ||
1343 | unsigned int interrupt_server[MAX_CPU_THREADS]; | ||
1344 | unsigned int cpu_threads, hw_cpu_num; | ||
1345 | int propsize; | ||
1346 | struct prom_t *_prom = &RELOC(prom); | 1340 | struct prom_t *_prom = &RELOC(prom); |
1347 | unsigned long *spinloop | 1341 | unsigned long *spinloop |
1348 | = (void *) LOW_ADDR(__secondary_hold_spinloop); | 1342 | = (void *) LOW_ADDR(__secondary_hold_spinloop); |
@@ -1386,7 +1380,6 @@ static void __init prom_hold_cpus(void) | |||
1386 | reg = -1; | 1380 | reg = -1; |
1387 | prom_getprop(node, "reg", ®, sizeof(reg)); | 1381 | prom_getprop(node, "reg", ®, sizeof(reg)); |
1388 | 1382 | ||
1389 | prom_debug("\ncpuid = 0x%x\n", cpuid); | ||
1390 | prom_debug("cpu hw idx = 0x%x\n", reg); | 1383 | prom_debug("cpu hw idx = 0x%x\n", reg); |
1391 | 1384 | ||
1392 | /* Init the acknowledge var which will be reset by | 1385 | /* Init the acknowledge var which will be reset by |
@@ -1395,28 +1388,9 @@ static void __init prom_hold_cpus(void) | |||
1395 | */ | 1388 | */ |
1396 | *acknowledge = (unsigned long)-1; | 1389 | *acknowledge = (unsigned long)-1; |
1397 | 1390 | ||
1398 | propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", | 1391 | if (reg != _prom->cpu) { |
1399 | &interrupt_server, | ||
1400 | sizeof(interrupt_server)); | ||
1401 | if (propsize < 0) { | ||
1402 | /* no property. old hardware has no SMT */ | ||
1403 | cpu_threads = 1; | ||
1404 | interrupt_server[0] = reg; /* fake it with phys id */ | ||
1405 | } else { | ||
1406 | /* We have a threaded processor */ | ||
1407 | cpu_threads = propsize / sizeof(u32); | ||
1408 | if (cpu_threads > MAX_CPU_THREADS) { | ||
1409 | prom_printf("SMT: too many threads!\n" | ||
1410 | "SMT: found %x, max is %x\n", | ||
1411 | cpu_threads, MAX_CPU_THREADS); | ||
1412 | cpu_threads = 1; /* ToDo: panic? */ | ||
1413 | } | ||
1414 | } | ||
1415 | |||
1416 | hw_cpu_num = interrupt_server[0]; | ||
1417 | if (hw_cpu_num != _prom->cpu) { | ||
1418 | /* Primary Thread of non-boot cpu */ | 1392 | /* Primary Thread of non-boot cpu */ |
1419 | prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); | 1393 | prom_printf("starting cpu hw idx %x... ", reg); |
1420 | call_prom("start-cpu", 3, 0, node, | 1394 | call_prom("start-cpu", 3, 0, node, |
1421 | secondary_hold, reg); | 1395 | secondary_hold, reg); |
1422 | 1396 | ||
@@ -1431,17 +1405,10 @@ static void __init prom_hold_cpus(void) | |||
1431 | } | 1405 | } |
1432 | #ifdef CONFIG_SMP | 1406 | #ifdef CONFIG_SMP |
1433 | else | 1407 | else |
1434 | prom_printf("%x : boot cpu %x\n", cpuid, reg); | 1408 | prom_printf("boot cpu hw idx %x\n", reg); |
1435 | #endif /* CONFIG_SMP */ | 1409 | #endif /* CONFIG_SMP */ |
1436 | |||
1437 | /* Reserve cpu #s for secondary threads. They start later. */ | ||
1438 | cpuid += cpu_threads; | ||
1439 | } | 1410 | } |
1440 | 1411 | ||
1441 | if (cpuid > NR_CPUS) | ||
1442 | prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) | ||
1443 | ") exceeded: ignoring extras\n"); | ||
1444 | |||
1445 | prom_debug("prom_hold_cpus: end...\n"); | 1412 | prom_debug("prom_hold_cpus: end...\n"); |
1446 | } | 1413 | } |
1447 | 1414 | ||
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index a5d0e78779c8..6b66cd85b433 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
23 | #include <linux/ptrace.h> | 23 | #include <linux/ptrace.h> |
24 | #include <linux/regset.h> | 24 | #include <linux/regset.h> |
25 | #include <linux/tracehook.h> | ||
25 | #include <linux/elf.h> | 26 | #include <linux/elf.h> |
26 | #include <linux/user.h> | 27 | #include <linux/user.h> |
27 | #include <linux/security.h> | 28 | #include <linux/security.h> |
@@ -717,7 +718,7 @@ void user_disable_single_step(struct task_struct *task) | |||
717 | struct pt_regs *regs = task->thread.regs; | 718 | struct pt_regs *regs = task->thread.regs; |
718 | 719 | ||
719 | 720 | ||
720 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | 721 | #if defined(CONFIG_BOOKE) |
721 | /* If DAC then do not single step, skip */ | 722 | /* If DAC then do not single step, skip */ |
722 | if (task->thread.dabr) | 723 | if (task->thread.dabr) |
723 | return; | 724 | return; |
@@ -744,10 +745,11 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
744 | if (addr > 0) | 745 | if (addr > 0) |
745 | return -EINVAL; | 746 | return -EINVAL; |
746 | 747 | ||
748 | /* The bottom 3 bits in dabr are flags */ | ||
747 | if ((data & ~0x7UL) >= TASK_SIZE) | 749 | if ((data & ~0x7UL) >= TASK_SIZE) |
748 | return -EIO; | 750 | return -EIO; |
749 | 751 | ||
750 | #ifdef CONFIG_PPC64 | 752 | #ifndef CONFIG_BOOKE |
751 | 753 | ||
752 | /* For processors using DABR (i.e. 970), the bottom 3 bits are flags. | 754 | /* For processors using DABR (i.e. 970), the bottom 3 bits are flags. |
753 | * It was assumed, on previous implementations, that 3 bits were | 755 | * It was assumed, on previous implementations, that 3 bits were |
@@ -769,7 +771,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
769 | task->thread.dabr = data; | 771 | task->thread.dabr = data; |
770 | 772 | ||
771 | #endif | 773 | #endif |
772 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | 774 | #if defined(CONFIG_BOOKE) |
773 | 775 | ||
774 | /* As described above, it was assumed 3 bits were passed with the data | 776 | /* As described above, it was assumed 3 bits were passed with the data |
775 | * address, but we will assume only the mode bits will be passed | 777 | * address, but we will assume only the mode bits will be passed |
@@ -1013,31 +1015,24 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1013 | return ret; | 1015 | return ret; |
1014 | } | 1016 | } |
1015 | 1017 | ||
1016 | static void do_syscall_trace(void) | 1018 | /* |
1019 | * We must return the syscall number to actually look up in the table. | ||
1020 | * This can be -1L to skip running any syscall at all. | ||
1021 | */ | ||
1022 | long do_syscall_trace_enter(struct pt_regs *regs) | ||
1017 | { | 1023 | { |
1018 | /* the 0x80 provides a way for the tracing parent to distinguish | 1024 | long ret = 0; |
1019 | between a syscall stop and SIGTRAP delivery */ | ||
1020 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
1021 | ? 0x80 : 0)); | ||
1022 | |||
1023 | /* | ||
1024 | * this isn't the same as continuing with a signal, but it will do | ||
1025 | * for normal use. strace only continues with a signal if the | ||
1026 | * stopping signal is not SIGTRAP. -brl | ||
1027 | */ | ||
1028 | if (current->exit_code) { | ||
1029 | send_sig(current->exit_code, current, 1); | ||
1030 | current->exit_code = 0; | ||
1031 | } | ||
1032 | } | ||
1033 | 1025 | ||
1034 | void do_syscall_trace_enter(struct pt_regs *regs) | ||
1035 | { | ||
1036 | secure_computing(regs->gpr[0]); | 1026 | secure_computing(regs->gpr[0]); |
1037 | 1027 | ||
1038 | if (test_thread_flag(TIF_SYSCALL_TRACE) | 1028 | if (test_thread_flag(TIF_SYSCALL_TRACE) && |
1039 | && (current->ptrace & PT_PTRACED)) | 1029 | tracehook_report_syscall_entry(regs)) |
1040 | do_syscall_trace(); | 1030 | /* |
1031 | * Tracing decided this syscall should not happen. | ||
1032 | * We'll return a bogus call number to get an ENOSYS | ||
1033 | * error, but leave the original number in regs->gpr[0]. | ||
1034 | */ | ||
1035 | ret = -1L; | ||
1041 | 1036 | ||
1042 | if (unlikely(current->audit_context)) { | 1037 | if (unlikely(current->audit_context)) { |
1043 | #ifdef CONFIG_PPC64 | 1038 | #ifdef CONFIG_PPC64 |
@@ -1055,16 +1050,19 @@ void do_syscall_trace_enter(struct pt_regs *regs) | |||
1055 | regs->gpr[5] & 0xffffffff, | 1050 | regs->gpr[5] & 0xffffffff, |
1056 | regs->gpr[6] & 0xffffffff); | 1051 | regs->gpr[6] & 0xffffffff); |
1057 | } | 1052 | } |
1053 | |||
1054 | return ret ?: regs->gpr[0]; | ||
1058 | } | 1055 | } |
1059 | 1056 | ||
1060 | void do_syscall_trace_leave(struct pt_regs *regs) | 1057 | void do_syscall_trace_leave(struct pt_regs *regs) |
1061 | { | 1058 | { |
1059 | int step; | ||
1060 | |||
1062 | if (unlikely(current->audit_context)) | 1061 | if (unlikely(current->audit_context)) |
1063 | audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, | 1062 | audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, |
1064 | regs->result); | 1063 | regs->result); |
1065 | 1064 | ||
1066 | if ((test_thread_flag(TIF_SYSCALL_TRACE) | 1065 | step = test_thread_flag(TIF_SINGLESTEP); |
1067 | || test_thread_flag(TIF_SINGLESTEP)) | 1066 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) |
1068 | && (current->ptrace & PT_PTRACED)) | 1067 | tracehook_report_syscall_exit(regs, step); |
1069 | do_syscall_trace(); | ||
1070 | } | 1068 | } |
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 61a3f4132087..9cc5a52711e5 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -367,7 +367,6 @@ static void __init cpu_init_thread_core_maps(int tpc) | |||
367 | * setup_cpu_maps - initialize the following cpu maps: | 367 | * setup_cpu_maps - initialize the following cpu maps: |
368 | * cpu_possible_map | 368 | * cpu_possible_map |
369 | * cpu_present_map | 369 | * cpu_present_map |
370 | * cpu_sibling_map | ||
371 | * | 370 | * |
372 | * Having the possible map set up early allows us to restrict allocations | 371 | * Having the possible map set up early allows us to restrict allocations |
373 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. | 372 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. |
@@ -475,29 +474,6 @@ void __init smp_setup_cpu_maps(void) | |||
475 | */ | 474 | */ |
476 | cpu_init_thread_core_maps(nthreads); | 475 | cpu_init_thread_core_maps(nthreads); |
477 | } | 476 | } |
478 | |||
479 | /* | ||
480 | * Being that cpu_sibling_map is now a per_cpu array, then it cannot | ||
481 | * be initialized until the per_cpu areas have been created. This | ||
482 | * function is now called from setup_per_cpu_areas(). | ||
483 | */ | ||
484 | void __init smp_setup_cpu_sibling_map(void) | ||
485 | { | ||
486 | #ifdef CONFIG_PPC64 | ||
487 | int i, cpu, base; | ||
488 | |||
489 | for_each_possible_cpu(cpu) { | ||
490 | DBG("Sibling map for CPU %d:", cpu); | ||
491 | base = cpu_first_thread_in_core(cpu); | ||
492 | for (i = 0; i < threads_per_core; i++) { | ||
493 | cpu_set(base + i, per_cpu(cpu_sibling_map, cpu)); | ||
494 | DBG(" %d", base + i); | ||
495 | } | ||
496 | DBG("\n"); | ||
497 | } | ||
498 | |||
499 | #endif /* CONFIG_PPC64 */ | ||
500 | } | ||
501 | #endif /* CONFIG_SMP */ | 477 | #endif /* CONFIG_SMP */ |
502 | 478 | ||
503 | #ifdef CONFIG_PCSPKR_PLATFORM | 479 | #ifdef CONFIG_PCSPKR_PLATFORM |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 04d8de9f0fc6..8b25f51f03bf 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -611,9 +611,6 @@ void __init setup_per_cpu_areas(void) | |||
611 | paca[i].data_offset = ptr - __per_cpu_start; | 611 | paca[i].data_offset = ptr - __per_cpu_start; |
612 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); | 612 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); |
613 | } | 613 | } |
614 | |||
615 | /* Now that per_cpu is setup, initialize cpu_sibling_map */ | ||
616 | smp_setup_cpu_sibling_map(); | ||
617 | } | 614 | } |
618 | #endif | 615 | #endif |
619 | 616 | ||
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 7aada783ec6a..a54405ebd7b0 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * this archive for more details. | 9 | * this archive for more details. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/ptrace.h> | 12 | #include <linux/tracehook.h> |
13 | #include <linux/signal.h> | 13 | #include <linux/signal.h> |
14 | #include <asm/uaccess.h> | 14 | #include <asm/uaccess.h> |
15 | #include <asm/unistd.h> | 15 | #include <asm/unistd.h> |
@@ -112,7 +112,7 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, | |||
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | int do_signal(sigset_t *oldset, struct pt_regs *regs) | 115 | static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs) |
116 | { | 116 | { |
117 | siginfo_t info; | 117 | siginfo_t info; |
118 | int signr; | 118 | int signr; |
@@ -147,7 +147,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
147 | */ | 147 | */ |
148 | if (current->thread.dabr) { | 148 | if (current->thread.dabr) { |
149 | set_dabr(current->thread.dabr); | 149 | set_dabr(current->thread.dabr); |
150 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | 150 | #if defined(CONFIG_BOOKE) |
151 | mtspr(SPRN_DBCR0, current->thread.dbcr0); | 151 | mtspr(SPRN_DBCR0, current->thread.dbcr0); |
152 | #endif | 152 | #endif |
153 | } | 153 | } |
@@ -177,11 +177,28 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
177 | * its frame, and we can clear the TLF_RESTORE_SIGMASK flag. | 177 | * its frame, and we can clear the TLF_RESTORE_SIGMASK flag. |
178 | */ | 178 | */ |
179 | current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK; | 179 | current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK; |
180 | |||
181 | /* | ||
182 | * Let tracing know that we've done the handler setup. | ||
183 | */ | ||
184 | tracehook_signal_handler(signr, &info, &ka, regs, | ||
185 | test_thread_flag(TIF_SINGLESTEP)); | ||
180 | } | 186 | } |
181 | 187 | ||
182 | return ret; | 188 | return ret; |
183 | } | 189 | } |
184 | 190 | ||
191 | void do_signal(struct pt_regs *regs, unsigned long thread_info_flags) | ||
192 | { | ||
193 | if (thread_info_flags & _TIF_SIGPENDING) | ||
194 | do_signal_pending(NULL, regs); | ||
195 | |||
196 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
197 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
198 | tracehook_notify_resume(regs); | ||
199 | } | ||
200 | } | ||
201 | |||
185 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 202 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
186 | unsigned long r5, unsigned long r6, unsigned long r7, | 203 | unsigned long r5, unsigned long r6, unsigned long r7, |
187 | unsigned long r8, struct pt_regs *regs) | 204 | unsigned long r8, struct pt_regs *regs) |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index f5ae9fa222ea..5337ca7bb649 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <asm/smp.h> | 41 | #include <asm/smp.h> |
42 | #include <asm/time.h> | 42 | #include <asm/time.h> |
43 | #include <asm/machdep.h> | 43 | #include <asm/machdep.h> |
44 | #include <asm/cputhreads.h> | ||
44 | #include <asm/cputable.h> | 45 | #include <asm/cputable.h> |
45 | #include <asm/system.h> | 46 | #include <asm/system.h> |
46 | #include <asm/mpic.h> | 47 | #include <asm/mpic.h> |
@@ -62,10 +63,12 @@ struct thread_info *secondary_ti; | |||
62 | cpumask_t cpu_possible_map = CPU_MASK_NONE; | 63 | cpumask_t cpu_possible_map = CPU_MASK_NONE; |
63 | cpumask_t cpu_online_map = CPU_MASK_NONE; | 64 | cpumask_t cpu_online_map = CPU_MASK_NONE; |
64 | DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; | 65 | DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; |
66 | DEFINE_PER_CPU(cpumask_t, cpu_core_map) = CPU_MASK_NONE; | ||
65 | 67 | ||
66 | EXPORT_SYMBOL(cpu_online_map); | 68 | EXPORT_SYMBOL(cpu_online_map); |
67 | EXPORT_SYMBOL(cpu_possible_map); | 69 | EXPORT_SYMBOL(cpu_possible_map); |
68 | EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); | 70 | EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); |
71 | EXPORT_PER_CPU_SYMBOL(cpu_core_map); | ||
69 | 72 | ||
70 | /* SMP operations for this machine */ | 73 | /* SMP operations for this machine */ |
71 | struct smp_ops_t *smp_ops; | 74 | struct smp_ops_t *smp_ops; |
@@ -228,6 +231,8 @@ void __devinit smp_prepare_boot_cpu(void) | |||
228 | BUG_ON(smp_processor_id() != boot_cpuid); | 231 | BUG_ON(smp_processor_id() != boot_cpuid); |
229 | 232 | ||
230 | cpu_set(boot_cpuid, cpu_online_map); | 233 | cpu_set(boot_cpuid, cpu_online_map); |
234 | cpu_set(boot_cpuid, per_cpu(cpu_sibling_map, boot_cpuid)); | ||
235 | cpu_set(boot_cpuid, per_cpu(cpu_core_map, boot_cpuid)); | ||
231 | #ifdef CONFIG_PPC64 | 236 | #ifdef CONFIG_PPC64 |
232 | paca[boot_cpuid].__current = current; | 237 | paca[boot_cpuid].__current = current; |
233 | #endif | 238 | #endif |
@@ -375,11 +380,60 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
375 | return 0; | 380 | return 0; |
376 | } | 381 | } |
377 | 382 | ||
383 | /* Return the value of the reg property corresponding to the given | ||
384 | * logical cpu. | ||
385 | */ | ||
386 | int cpu_to_core_id(int cpu) | ||
387 | { | ||
388 | struct device_node *np; | ||
389 | const int *reg; | ||
390 | int id = -1; | ||
391 | |||
392 | np = of_get_cpu_node(cpu, NULL); | ||
393 | if (!np) | ||
394 | goto out; | ||
395 | |||
396 | reg = of_get_property(np, "reg", NULL); | ||
397 | if (!reg) | ||
398 | goto out; | ||
399 | |||
400 | id = *reg; | ||
401 | out: | ||
402 | of_node_put(np); | ||
403 | return id; | ||
404 | } | ||
405 | |||
406 | /* Must be called when no change can occur to cpu_present_map, | ||
407 | * i.e. during cpu online or offline. | ||
408 | */ | ||
409 | static struct device_node *cpu_to_l2cache(int cpu) | ||
410 | { | ||
411 | struct device_node *np; | ||
412 | const phandle *php; | ||
413 | phandle ph; | ||
414 | |||
415 | if (!cpu_present(cpu)) | ||
416 | return NULL; | ||
417 | |||
418 | np = of_get_cpu_node(cpu, NULL); | ||
419 | if (np == NULL) | ||
420 | return NULL; | ||
421 | |||
422 | php = of_get_property(np, "l2-cache", NULL); | ||
423 | if (php == NULL) | ||
424 | return NULL; | ||
425 | ph = *php; | ||
426 | of_node_put(np); | ||
427 | |||
428 | return of_find_node_by_phandle(ph); | ||
429 | } | ||
378 | 430 | ||
379 | /* Activate a secondary processor. */ | 431 | /* Activate a secondary processor. */ |
380 | int __devinit start_secondary(void *unused) | 432 | int __devinit start_secondary(void *unused) |
381 | { | 433 | { |
382 | unsigned int cpu = smp_processor_id(); | 434 | unsigned int cpu = smp_processor_id(); |
435 | struct device_node *l2_cache; | ||
436 | int i, base; | ||
383 | 437 | ||
384 | atomic_inc(&init_mm.mm_count); | 438 | atomic_inc(&init_mm.mm_count); |
385 | current->active_mm = &init_mm; | 439 | current->active_mm = &init_mm; |
@@ -400,6 +454,33 @@ int __devinit start_secondary(void *unused) | |||
400 | 454 | ||
401 | ipi_call_lock(); | 455 | ipi_call_lock(); |
402 | cpu_set(cpu, cpu_online_map); | 456 | cpu_set(cpu, cpu_online_map); |
457 | /* Update sibling maps */ | ||
458 | base = cpu_first_thread_in_core(cpu); | ||
459 | for (i = 0; i < threads_per_core; i++) { | ||
460 | if (cpu_is_offline(base + i)) | ||
461 | continue; | ||
462 | cpu_set(cpu, per_cpu(cpu_sibling_map, base + i)); | ||
463 | cpu_set(base + i, per_cpu(cpu_sibling_map, cpu)); | ||
464 | |||
465 | /* cpu_core_map should be a superset of | ||
466 | * cpu_sibling_map even if we don't have cache | ||
467 | * information, so update the former here, too. | ||
468 | */ | ||
469 | cpu_set(cpu, per_cpu(cpu_core_map, base +i)); | ||
470 | cpu_set(base + i, per_cpu(cpu_core_map, cpu)); | ||
471 | } | ||
472 | l2_cache = cpu_to_l2cache(cpu); | ||
473 | for_each_online_cpu(i) { | ||
474 | struct device_node *np = cpu_to_l2cache(i); | ||
475 | if (!np) | ||
476 | continue; | ||
477 | if (np == l2_cache) { | ||
478 | cpu_set(cpu, per_cpu(cpu_core_map, i)); | ||
479 | cpu_set(i, per_cpu(cpu_core_map, cpu)); | ||
480 | } | ||
481 | of_node_put(np); | ||
482 | } | ||
483 | of_node_put(l2_cache); | ||
403 | ipi_call_unlock(); | 484 | ipi_call_unlock(); |
404 | 485 | ||
405 | local_irq_enable(); | 486 | local_irq_enable(); |
@@ -437,10 +518,42 @@ void __init smp_cpus_done(unsigned int max_cpus) | |||
437 | #ifdef CONFIG_HOTPLUG_CPU | 518 | #ifdef CONFIG_HOTPLUG_CPU |
438 | int __cpu_disable(void) | 519 | int __cpu_disable(void) |
439 | { | 520 | { |
440 | if (smp_ops->cpu_disable) | 521 | struct device_node *l2_cache; |
441 | return smp_ops->cpu_disable(); | 522 | int cpu = smp_processor_id(); |
523 | int base, i; | ||
524 | int err; | ||
442 | 525 | ||
443 | return -ENOSYS; | 526 | if (!smp_ops->cpu_disable) |
527 | return -ENOSYS; | ||
528 | |||
529 | err = smp_ops->cpu_disable(); | ||
530 | if (err) | ||
531 | return err; | ||
532 | |||
533 | /* Update sibling maps */ | ||
534 | base = cpu_first_thread_in_core(cpu); | ||
535 | for (i = 0; i < threads_per_core; i++) { | ||
536 | cpu_clear(cpu, per_cpu(cpu_sibling_map, base + i)); | ||
537 | cpu_clear(base + i, per_cpu(cpu_sibling_map, cpu)); | ||
538 | cpu_clear(cpu, per_cpu(cpu_core_map, base +i)); | ||
539 | cpu_clear(base + i, per_cpu(cpu_core_map, cpu)); | ||
540 | } | ||
541 | |||
542 | l2_cache = cpu_to_l2cache(cpu); | ||
543 | for_each_present_cpu(i) { | ||
544 | struct device_node *np = cpu_to_l2cache(i); | ||
545 | if (!np) | ||
546 | continue; | ||
547 | if (np == l2_cache) { | ||
548 | cpu_clear(cpu, per_cpu(cpu_core_map, i)); | ||
549 | cpu_clear(i, per_cpu(cpu_core_map, cpu)); | ||
550 | } | ||
551 | of_node_put(np); | ||
552 | } | ||
553 | of_node_put(l2_cache); | ||
554 | |||
555 | |||
556 | return 0; | ||
444 | } | 557 | } |
445 | 558 | ||
446 | void __cpu_die(unsigned int cpu) | 559 | void __cpu_die(unsigned int cpu) |
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index f2589645870a..b0dbb1daa4df 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/stacktrace.h> | 15 | #include <linux/stacktrace.h> |
16 | #include <linux/module.h> | ||
17 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
18 | #include <asm/processor.h> | 17 | #include <asm/processor.h> |
19 | 18 | ||
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 800e5e9a087b..56d172d16e56 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -22,6 +22,8 @@ | |||
22 | 22 | ||
23 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 23 | static DEFINE_PER_CPU(struct cpu, cpu_devices); |
24 | 24 | ||
25 | static DEFINE_PER_CPU(struct kobject *, cache_toplevel); | ||
26 | |||
25 | /* SMT stuff */ | 27 | /* SMT stuff */ |
26 | 28 | ||
27 | #ifdef CONFIG_PPC_MULTIPLATFORM | 29 | #ifdef CONFIG_PPC_MULTIPLATFORM |
@@ -297,8 +299,289 @@ static struct sysdev_attribute pa6t_attrs[] = { | |||
297 | #endif /* CONFIG_DEBUG_KERNEL */ | 299 | #endif /* CONFIG_DEBUG_KERNEL */ |
298 | }; | 300 | }; |
299 | 301 | ||
302 | struct cache_desc { | ||
303 | struct kobject kobj; | ||
304 | struct cache_desc *next; | ||
305 | const char *type; /* Instruction, Data, or Unified */ | ||
306 | u32 size; /* total cache size in KB */ | ||
307 | u32 line_size; /* in bytes */ | ||
308 | u32 nr_sets; /* number of sets */ | ||
309 | u32 level; /* e.g. 1, 2, 3... */ | ||
310 | u32 associativity; /* e.g. 8-way... 0 is fully associative */ | ||
311 | }; | ||
312 | |||
313 | DEFINE_PER_CPU(struct cache_desc *, cache_desc); | ||
314 | |||
315 | static struct cache_desc *kobj_to_cache_desc(struct kobject *k) | ||
316 | { | ||
317 | return container_of(k, struct cache_desc, kobj); | ||
318 | } | ||
319 | |||
320 | static void cache_desc_release(struct kobject *k) | ||
321 | { | ||
322 | struct cache_desc *desc = kobj_to_cache_desc(k); | ||
323 | |||
324 | pr_debug("%s: releasing %s\n", __func__, kobject_name(k)); | ||
325 | |||
326 | if (desc->next) | ||
327 | kobject_put(&desc->next->kobj); | ||
328 | |||
329 | kfree(kobj_to_cache_desc(k)); | ||
330 | } | ||
331 | |||
332 | static ssize_t cache_desc_show(struct kobject *k, struct attribute *attr, char *buf) | ||
333 | { | ||
334 | struct kobj_attribute *kobj_attr; | ||
335 | |||
336 | kobj_attr = container_of(attr, struct kobj_attribute, attr); | ||
337 | |||
338 | return kobj_attr->show(k, kobj_attr, buf); | ||
339 | } | ||
340 | |||
341 | static struct sysfs_ops cache_desc_sysfs_ops = { | ||
342 | .show = cache_desc_show, | ||
343 | }; | ||
344 | |||
345 | static struct kobj_type cache_desc_type = { | ||
346 | .release = cache_desc_release, | ||
347 | .sysfs_ops = &cache_desc_sysfs_ops, | ||
348 | }; | ||
349 | |||
350 | static ssize_t cache_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf) | ||
351 | { | ||
352 | struct cache_desc *cache = kobj_to_cache_desc(k); | ||
353 | |||
354 | return sprintf(buf, "%uK\n", cache->size); | ||
355 | } | ||
356 | |||
357 | static struct kobj_attribute cache_size_attr = | ||
358 | __ATTR(size, 0444, cache_size_show, NULL); | ||
359 | |||
360 | static ssize_t cache_line_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf) | ||
361 | { | ||
362 | struct cache_desc *cache = kobj_to_cache_desc(k); | ||
363 | |||
364 | return sprintf(buf, "%u\n", cache->line_size); | ||
365 | } | ||
366 | |||
367 | static struct kobj_attribute cache_line_size_attr = | ||
368 | __ATTR(coherency_line_size, 0444, cache_line_size_show, NULL); | ||
369 | |||
370 | static ssize_t cache_nr_sets_show(struct kobject *k, struct kobj_attribute *attr, char *buf) | ||
371 | { | ||
372 | struct cache_desc *cache = kobj_to_cache_desc(k); | ||
373 | |||
374 | return sprintf(buf, "%u\n", cache->nr_sets); | ||
375 | } | ||
376 | |||
377 | static struct kobj_attribute cache_nr_sets_attr = | ||
378 | __ATTR(number_of_sets, 0444, cache_nr_sets_show, NULL); | ||
379 | |||
380 | static ssize_t cache_type_show(struct kobject *k, struct kobj_attribute *attr, char *buf) | ||
381 | { | ||
382 | struct cache_desc *cache = kobj_to_cache_desc(k); | ||
383 | |||
384 | return sprintf(buf, "%s\n", cache->type); | ||
385 | } | ||
386 | |||
387 | static struct kobj_attribute cache_type_attr = | ||
388 | __ATTR(type, 0444, cache_type_show, NULL); | ||
389 | |||
390 | static ssize_t cache_level_show(struct kobject *k, struct kobj_attribute *attr, char *buf) | ||
391 | { | ||
392 | struct cache_desc *cache = kobj_to_cache_desc(k); | ||
393 | |||
394 | return sprintf(buf, "%u\n", cache->level); | ||
395 | } | ||
396 | |||
397 | static struct kobj_attribute cache_level_attr = | ||
398 | __ATTR(level, 0444, cache_level_show, NULL); | ||
399 | |||
400 | static ssize_t cache_assoc_show(struct kobject *k, struct kobj_attribute *attr, char *buf) | ||
401 | { | ||
402 | struct cache_desc *cache = kobj_to_cache_desc(k); | ||
403 | |||
404 | return sprintf(buf, "%u\n", cache->associativity); | ||
405 | } | ||
406 | |||
407 | static struct kobj_attribute cache_assoc_attr = | ||
408 | __ATTR(ways_of_associativity, 0444, cache_assoc_show, NULL); | ||
409 | |||
410 | struct cache_desc_info { | ||
411 | const char *type; | ||
412 | const char *size_prop; | ||
413 | const char *line_size_prop; | ||
414 | const char *nr_sets_prop; | ||
415 | }; | ||
416 | |||
417 | /* PowerPC Processor binding says the [di]-cache-* must be equal on | ||
418 | * unified caches, so just use d-cache properties. */ | ||
419 | static struct cache_desc_info ucache_info = { | ||
420 | .type = "Unified", | ||
421 | .size_prop = "d-cache-size", | ||
422 | .line_size_prop = "d-cache-line-size", | ||
423 | .nr_sets_prop = "d-cache-sets", | ||
424 | }; | ||
300 | 425 | ||
301 | static void register_cpu_online(unsigned int cpu) | 426 | static struct cache_desc_info dcache_info = { |
427 | .type = "Data", | ||
428 | .size_prop = "d-cache-size", | ||
429 | .line_size_prop = "d-cache-line-size", | ||
430 | .nr_sets_prop = "d-cache-sets", | ||
431 | }; | ||
432 | |||
433 | static struct cache_desc_info icache_info = { | ||
434 | .type = "Instruction", | ||
435 | .size_prop = "i-cache-size", | ||
436 | .line_size_prop = "i-cache-line-size", | ||
437 | .nr_sets_prop = "i-cache-sets", | ||
438 | }; | ||
439 | |||
440 | static struct cache_desc * __cpuinit create_cache_desc(struct device_node *np, struct kobject *parent, int index, int level, struct cache_desc_info *info) | ||
441 | { | ||
442 | const u32 *cache_line_size; | ||
443 | struct cache_desc *new; | ||
444 | const u32 *cache_size; | ||
445 | const u32 *nr_sets; | ||
446 | int rc; | ||
447 | |||
448 | new = kzalloc(sizeof(*new), GFP_KERNEL); | ||
449 | if (!new) | ||
450 | return NULL; | ||
451 | |||
452 | rc = kobject_init_and_add(&new->kobj, &cache_desc_type, parent, | ||
453 | "index%d", index); | ||
454 | if (rc) | ||
455 | goto err; | ||
456 | |||
457 | /* type */ | ||
458 | new->type = info->type; | ||
459 | rc = sysfs_create_file(&new->kobj, &cache_type_attr.attr); | ||
460 | WARN_ON(rc); | ||
461 | |||
462 | /* level */ | ||
463 | new->level = level; | ||
464 | rc = sysfs_create_file(&new->kobj, &cache_level_attr.attr); | ||
465 | WARN_ON(rc); | ||
466 | |||
467 | /* size */ | ||
468 | cache_size = of_get_property(np, info->size_prop, NULL); | ||
469 | if (cache_size) { | ||
470 | new->size = *cache_size / 1024; | ||
471 | rc = sysfs_create_file(&new->kobj, | ||
472 | &cache_size_attr.attr); | ||
473 | WARN_ON(rc); | ||
474 | } | ||
475 | |||
476 | /* coherency_line_size */ | ||
477 | cache_line_size = of_get_property(np, info->line_size_prop, NULL); | ||
478 | if (cache_line_size) { | ||
479 | new->line_size = *cache_line_size; | ||
480 | rc = sysfs_create_file(&new->kobj, | ||
481 | &cache_line_size_attr.attr); | ||
482 | WARN_ON(rc); | ||
483 | } | ||
484 | |||
485 | /* number_of_sets */ | ||
486 | nr_sets = of_get_property(np, info->nr_sets_prop, NULL); | ||
487 | if (nr_sets) { | ||
488 | new->nr_sets = *nr_sets; | ||
489 | rc = sysfs_create_file(&new->kobj, | ||
490 | &cache_nr_sets_attr.attr); | ||
491 | WARN_ON(rc); | ||
492 | } | ||
493 | |||
494 | /* ways_of_associativity */ | ||
495 | if (new->nr_sets == 1) { | ||
496 | /* fully associative */ | ||
497 | new->associativity = 0; | ||
498 | goto create_assoc; | ||
499 | } | ||
500 | |||
501 | if (new->nr_sets && new->size && new->line_size) { | ||
502 | /* If we have values for all of these we can derive | ||
503 | * the associativity. */ | ||
504 | new->associativity = | ||
505 | ((new->size * 1024) / new->nr_sets) / new->line_size; | ||
506 | create_assoc: | ||
507 | rc = sysfs_create_file(&new->kobj, | ||
508 | &cache_assoc_attr.attr); | ||
509 | WARN_ON(rc); | ||
510 | } | ||
511 | |||
512 | return new; | ||
513 | err: | ||
514 | kfree(new); | ||
515 | return NULL; | ||
516 | } | ||
517 | |||
518 | static bool cache_is_unified(struct device_node *np) | ||
519 | { | ||
520 | return of_get_property(np, "cache-unified", NULL); | ||
521 | } | ||
522 | |||
523 | static struct cache_desc * __cpuinit create_cache_index_info(struct device_node *np, struct kobject *parent, int index, int level) | ||
524 | { | ||
525 | const phandle *next_cache_phandle; | ||
526 | struct device_node *next_cache; | ||
527 | struct cache_desc *new, **end; | ||
528 | |||
529 | pr_debug("%s(node = %s, index = %d)\n", __func__, np->full_name, index); | ||
530 | |||
531 | if (cache_is_unified(np)) { | ||
532 | new = create_cache_desc(np, parent, index, level, | ||
533 | &ucache_info); | ||
534 | } else { | ||
535 | new = create_cache_desc(np, parent, index, level, | ||
536 | &dcache_info); | ||
537 | if (new) { | ||
538 | index++; | ||
539 | new->next = create_cache_desc(np, parent, index, level, | ||
540 | &icache_info); | ||
541 | } | ||
542 | } | ||
543 | if (!new) | ||
544 | return NULL; | ||
545 | |||
546 | end = &new->next; | ||
547 | while (*end) | ||
548 | end = &(*end)->next; | ||
549 | |||
550 | next_cache_phandle = of_get_property(np, "l2-cache", NULL); | ||
551 | if (!next_cache_phandle) | ||
552 | goto out; | ||
553 | |||
554 | next_cache = of_find_node_by_phandle(*next_cache_phandle); | ||
555 | if (!next_cache) | ||
556 | goto out; | ||
557 | |||
558 | *end = create_cache_index_info(next_cache, parent, ++index, ++level); | ||
559 | |||
560 | of_node_put(next_cache); | ||
561 | out: | ||
562 | return new; | ||
563 | } | ||
564 | |||
565 | static void __cpuinit create_cache_info(struct sys_device *sysdev) | ||
566 | { | ||
567 | struct kobject *cache_toplevel; | ||
568 | struct device_node *np = NULL; | ||
569 | int cpu = sysdev->id; | ||
570 | |||
571 | cache_toplevel = kobject_create_and_add("cache", &sysdev->kobj); | ||
572 | if (!cache_toplevel) | ||
573 | return; | ||
574 | per_cpu(cache_toplevel, cpu) = cache_toplevel; | ||
575 | np = of_get_cpu_node(cpu, NULL); | ||
576 | if (np != NULL) { | ||
577 | per_cpu(cache_desc, cpu) = | ||
578 | create_cache_index_info(np, cache_toplevel, 0, 1); | ||
579 | of_node_put(np); | ||
580 | } | ||
581 | return; | ||
582 | } | ||
583 | |||
584 | static void __cpuinit register_cpu_online(unsigned int cpu) | ||
302 | { | 585 | { |
303 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 586 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
304 | struct sys_device *s = &c->sysdev; | 587 | struct sys_device *s = &c->sysdev; |
@@ -346,9 +629,33 @@ static void register_cpu_online(unsigned int cpu) | |||
346 | 629 | ||
347 | if (cpu_has_feature(CPU_FTR_DSCR)) | 630 | if (cpu_has_feature(CPU_FTR_DSCR)) |
348 | sysdev_create_file(s, &attr_dscr); | 631 | sysdev_create_file(s, &attr_dscr); |
632 | |||
633 | create_cache_info(s); | ||
349 | } | 634 | } |
350 | 635 | ||
351 | #ifdef CONFIG_HOTPLUG_CPU | 636 | #ifdef CONFIG_HOTPLUG_CPU |
637 | static void remove_cache_info(struct sys_device *sysdev) | ||
638 | { | ||
639 | struct kobject *cache_toplevel; | ||
640 | struct cache_desc *cache_desc; | ||
641 | int cpu = sysdev->id; | ||
642 | |||
643 | cache_desc = per_cpu(cache_desc, cpu); | ||
644 | if (cache_desc != NULL) { | ||
645 | sysfs_remove_file(&cache_desc->kobj, &cache_size_attr.attr); | ||
646 | sysfs_remove_file(&cache_desc->kobj, &cache_line_size_attr.attr); | ||
647 | sysfs_remove_file(&cache_desc->kobj, &cache_type_attr.attr); | ||
648 | sysfs_remove_file(&cache_desc->kobj, &cache_level_attr.attr); | ||
649 | sysfs_remove_file(&cache_desc->kobj, &cache_nr_sets_attr.attr); | ||
650 | sysfs_remove_file(&cache_desc->kobj, &cache_assoc_attr.attr); | ||
651 | |||
652 | kobject_put(&cache_desc->kobj); | ||
653 | } | ||
654 | cache_toplevel = per_cpu(cache_toplevel, cpu); | ||
655 | if (cache_toplevel != NULL) | ||
656 | kobject_put(cache_toplevel); | ||
657 | } | ||
658 | |||
352 | static void unregister_cpu_online(unsigned int cpu) | 659 | static void unregister_cpu_online(unsigned int cpu) |
353 | { | 660 | { |
354 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 661 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
@@ -399,6 +706,8 @@ static void unregister_cpu_online(unsigned int cpu) | |||
399 | 706 | ||
400 | if (cpu_has_feature(CPU_FTR_DSCR)) | 707 | if (cpu_has_feature(CPU_FTR_DSCR)) |
401 | sysdev_remove_file(s, &attr_dscr); | 708 | sysdev_remove_file(s, &attr_dscr); |
709 | |||
710 | remove_cache_info(s); | ||
402 | } | 711 | } |
403 | #endif /* CONFIG_HOTPLUG_CPU */ | 712 | #endif /* CONFIG_HOTPLUG_CPU */ |
404 | 713 | ||
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index ade8aeaa2e70..22a3c33fd751 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
@@ -530,7 +530,7 @@ static dma_addr_t vio_dma_iommu_map_single(struct device *dev, void *vaddr, | |||
530 | } | 530 | } |
531 | 531 | ||
532 | ret = dma_iommu_ops.map_single(dev, vaddr, size, direction, attrs); | 532 | ret = dma_iommu_ops.map_single(dev, vaddr, size, direction, attrs); |
533 | if (unlikely(dma_mapping_error(ret))) { | 533 | if (unlikely(dma_mapping_error(dev, ret))) { |
534 | vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); | 534 | vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); |
535 | atomic_inc(&viodev->cmo.allocs_failed); | 535 | atomic_inc(&viodev->cmo.allocs_failed); |
536 | } | 536 | } |
@@ -1031,8 +1031,8 @@ void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {} | |||
1031 | static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; } | 1031 | static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; } |
1032 | static void vio_cmo_bus_remove(struct vio_dev *viodev) {} | 1032 | static void vio_cmo_bus_remove(struct vio_dev *viodev) {} |
1033 | static void vio_cmo_set_dma_ops(struct vio_dev *viodev) {} | 1033 | static void vio_cmo_set_dma_ops(struct vio_dev *viodev) {} |
1034 | static void vio_cmo_bus_init() {} | 1034 | static void vio_cmo_bus_init(void) {} |
1035 | static void vio_cmo_sysfs_init() { } | 1035 | static void vio_cmo_sysfs_init(void) { } |
1036 | #endif /* CONFIG_PPC_SMLPAR */ | 1036 | #endif /* CONFIG_PPC_SMLPAR */ |
1037 | EXPORT_SYMBOL(vio_cmo_entitlement_update); | 1037 | EXPORT_SYMBOL(vio_cmo_entitlement_update); |
1038 | EXPORT_SYMBOL(vio_cmo_set_dev_desired); | 1038 | EXPORT_SYMBOL(vio_cmo_set_dev_desired); |