diff options
Diffstat (limited to 'arch/sparc/kernel/smp_64.c')
-rw-r--r-- | arch/sparc/kernel/smp_64.c | 196 |
1 files changed, 167 insertions, 29 deletions
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index f7642e5a94db..fa44eaf8d897 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c | |||
@@ -20,7 +20,8 @@ | |||
20 | #include <linux/cache.h> | 20 | #include <linux/cache.h> |
21 | #include <linux/jiffies.h> | 21 | #include <linux/jiffies.h> |
22 | #include <linux/profile.h> | 22 | #include <linux/profile.h> |
23 | #include <linux/lmb.h> | 23 | #include <linux/bootmem.h> |
24 | #include <linux/vmalloc.h> | ||
24 | #include <linux/cpu.h> | 25 | #include <linux/cpu.h> |
25 | 26 | ||
26 | #include <asm/head.h> | 27 | #include <asm/head.h> |
@@ -47,6 +48,8 @@ | |||
47 | #include <asm/ldc.h> | 48 | #include <asm/ldc.h> |
48 | #include <asm/hypervisor.h> | 49 | #include <asm/hypervisor.h> |
49 | 50 | ||
51 | #include "cpumap.h" | ||
52 | |||
50 | int sparc64_multi_core __read_mostly; | 53 | int sparc64_multi_core __read_mostly; |
51 | 54 | ||
52 | DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; | 55 | DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; |
@@ -278,7 +281,7 @@ static unsigned long kimage_addr_to_ra(void *p) | |||
278 | return kern_base + (val - KERNBASE); | 281 | return kern_base + (val - KERNBASE); |
279 | } | 282 | } |
280 | 283 | ||
281 | static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg) | 284 | static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg, void **descrp) |
282 | { | 285 | { |
283 | extern unsigned long sparc64_ttable_tl0; | 286 | extern unsigned long sparc64_ttable_tl0; |
284 | extern unsigned long kern_locked_tte_data; | 287 | extern unsigned long kern_locked_tte_data; |
@@ -298,12 +301,12 @@ static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread | |||
298 | "hvtramp_descr.\n"); | 301 | "hvtramp_descr.\n"); |
299 | return; | 302 | return; |
300 | } | 303 | } |
304 | *descrp = hdesc; | ||
301 | 305 | ||
302 | hdesc->cpu = cpu; | 306 | hdesc->cpu = cpu; |
303 | hdesc->num_mappings = num_kernel_image_mappings; | 307 | hdesc->num_mappings = num_kernel_image_mappings; |
304 | 308 | ||
305 | tb = &trap_block[cpu]; | 309 | tb = &trap_block[cpu]; |
306 | tb->hdesc = hdesc; | ||
307 | 310 | ||
308 | hdesc->fault_info_va = (unsigned long) &tb->fault_info; | 311 | hdesc->fault_info_va = (unsigned long) &tb->fault_info; |
309 | hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info); | 312 | hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info); |
@@ -341,12 +344,12 @@ static struct thread_info *cpu_new_thread = NULL; | |||
341 | 344 | ||
342 | static int __cpuinit smp_boot_one_cpu(unsigned int cpu) | 345 | static int __cpuinit smp_boot_one_cpu(unsigned int cpu) |
343 | { | 346 | { |
344 | struct trap_per_cpu *tb = &trap_block[cpu]; | ||
345 | unsigned long entry = | 347 | unsigned long entry = |
346 | (unsigned long)(&sparc64_cpu_startup); | 348 | (unsigned long)(&sparc64_cpu_startup); |
347 | unsigned long cookie = | 349 | unsigned long cookie = |
348 | (unsigned long)(&cpu_new_thread); | 350 | (unsigned long)(&cpu_new_thread); |
349 | struct task_struct *p; | 351 | struct task_struct *p; |
352 | void *descr = NULL; | ||
350 | int timeout, ret; | 353 | int timeout, ret; |
351 | 354 | ||
352 | p = fork_idle(cpu); | 355 | p = fork_idle(cpu); |
@@ -359,7 +362,8 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu) | |||
359 | #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) | 362 | #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) |
360 | if (ldom_domaining_enabled) | 363 | if (ldom_domaining_enabled) |
361 | ldom_startcpu_cpuid(cpu, | 364 | ldom_startcpu_cpuid(cpu, |
362 | (unsigned long) cpu_new_thread); | 365 | (unsigned long) cpu_new_thread, |
366 | &descr); | ||
363 | else | 367 | else |
364 | #endif | 368 | #endif |
365 | prom_startcpu_cpuid(cpu, entry, cookie); | 369 | prom_startcpu_cpuid(cpu, entry, cookie); |
@@ -383,10 +387,7 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu) | |||
383 | } | 387 | } |
384 | cpu_new_thread = NULL; | 388 | cpu_new_thread = NULL; |
385 | 389 | ||
386 | if (tb->hdesc) { | 390 | kfree(descr); |
387 | kfree(tb->hdesc); | ||
388 | tb->hdesc = NULL; | ||
389 | } | ||
390 | 391 | ||
391 | return ret; | 392 | return ret; |
392 | } | 393 | } |
@@ -1315,6 +1316,8 @@ int __cpu_disable(void) | |||
1315 | cpu_clear(cpu, cpu_online_map); | 1316 | cpu_clear(cpu, cpu_online_map); |
1316 | ipi_call_unlock(); | 1317 | ipi_call_unlock(); |
1317 | 1318 | ||
1319 | cpu_map_rebuild(); | ||
1320 | |||
1318 | return 0; | 1321 | return 0; |
1319 | } | 1322 | } |
1320 | 1323 | ||
@@ -1373,36 +1376,171 @@ void smp_send_stop(void) | |||
1373 | { | 1376 | { |
1374 | } | 1377 | } |
1375 | 1378 | ||
1376 | unsigned long __per_cpu_base __read_mostly; | 1379 | /** |
1377 | unsigned long __per_cpu_shift __read_mostly; | 1380 | * pcpu_alloc_bootmem - NUMA friendly alloc_bootmem wrapper for percpu |
1381 | * @cpu: cpu to allocate for | ||
1382 | * @size: size allocation in bytes | ||
1383 | * @align: alignment | ||
1384 | * | ||
1385 | * Allocate @size bytes aligned at @align for cpu @cpu. This wrapper | ||
1386 | * does the right thing for NUMA regardless of the current | ||
1387 | * configuration. | ||
1388 | * | ||
1389 | * RETURNS: | ||
1390 | * Pointer to the allocated area on success, NULL on failure. | ||
1391 | */ | ||
1392 | static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size, | ||
1393 | unsigned long align) | ||
1394 | { | ||
1395 | const unsigned long goal = __pa(MAX_DMA_ADDRESS); | ||
1396 | #ifdef CONFIG_NEED_MULTIPLE_NODES | ||
1397 | int node = cpu_to_node(cpu); | ||
1398 | void *ptr; | ||
1399 | |||
1400 | if (!node_online(node) || !NODE_DATA(node)) { | ||
1401 | ptr = __alloc_bootmem(size, align, goal); | ||
1402 | pr_info("cpu %d has no node %d or node-local memory\n", | ||
1403 | cpu, node); | ||
1404 | pr_debug("per cpu data for cpu%d %lu bytes at %016lx\n", | ||
1405 | cpu, size, __pa(ptr)); | ||
1406 | } else { | ||
1407 | ptr = __alloc_bootmem_node(NODE_DATA(node), | ||
1408 | size, align, goal); | ||
1409 | pr_debug("per cpu data for cpu%d %lu bytes on node%d at " | ||
1410 | "%016lx\n", cpu, size, node, __pa(ptr)); | ||
1411 | } | ||
1412 | return ptr; | ||
1413 | #else | ||
1414 | return __alloc_bootmem(size, align, goal); | ||
1415 | #endif | ||
1416 | } | ||
1378 | 1417 | ||
1379 | EXPORT_SYMBOL(__per_cpu_base); | 1418 | static size_t pcpur_size __initdata; |
1380 | EXPORT_SYMBOL(__per_cpu_shift); | 1419 | static void **pcpur_ptrs __initdata; |
1381 | 1420 | ||
1382 | void __init real_setup_per_cpu_areas(void) | 1421 | static struct page * __init pcpur_get_page(unsigned int cpu, int pageno) |
1383 | { | 1422 | { |
1384 | unsigned long paddr, goal, size, i; | 1423 | size_t off = (size_t)pageno << PAGE_SHIFT; |
1385 | char *ptr; | ||
1386 | 1424 | ||
1387 | /* Copy section for each CPU (we discard the original) */ | 1425 | if (off >= pcpur_size) |
1388 | goal = PERCPU_ENOUGH_ROOM; | 1426 | return NULL; |
1389 | 1427 | ||
1390 | __per_cpu_shift = PAGE_SHIFT; | 1428 | return virt_to_page(pcpur_ptrs[cpu] + off); |
1391 | for (size = PAGE_SIZE; size < goal; size <<= 1UL) | 1429 | } |
1392 | __per_cpu_shift++; | 1430 | |
1431 | #define PCPU_CHUNK_SIZE (4UL * 1024UL * 1024UL) | ||
1432 | |||
1433 | static void __init pcpu_map_range(unsigned long start, unsigned long end, | ||
1434 | struct page *page) | ||
1435 | { | ||
1436 | unsigned long pfn = page_to_pfn(page); | ||
1437 | unsigned long pte_base; | ||
1438 | |||
1439 | BUG_ON((pfn<<PAGE_SHIFT)&(PCPU_CHUNK_SIZE - 1UL)); | ||
1440 | |||
1441 | pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4U | | ||
1442 | _PAGE_CP_4U | _PAGE_CV_4U | | ||
1443 | _PAGE_P_4U | _PAGE_W_4U); | ||
1444 | if (tlb_type == hypervisor) | ||
1445 | pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4V | | ||
1446 | _PAGE_CP_4V | _PAGE_CV_4V | | ||
1447 | _PAGE_P_4V | _PAGE_W_4V); | ||
1448 | |||
1449 | while (start < end) { | ||
1450 | pgd_t *pgd = pgd_offset_k(start); | ||
1451 | unsigned long this_end; | ||
1452 | pud_t *pud; | ||
1453 | pmd_t *pmd; | ||
1454 | pte_t *pte; | ||
1455 | |||
1456 | pud = pud_offset(pgd, start); | ||
1457 | if (pud_none(*pud)) { | ||
1458 | pmd_t *new; | ||
1459 | |||
1460 | new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE); | ||
1461 | pud_populate(&init_mm, pud, new); | ||
1462 | } | ||
1463 | |||
1464 | pmd = pmd_offset(pud, start); | ||
1465 | if (!pmd_present(*pmd)) { | ||
1466 | pte_t *new; | ||
1467 | |||
1468 | new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE); | ||
1469 | pmd_populate_kernel(&init_mm, pmd, new); | ||
1470 | } | ||
1393 | 1471 | ||
1394 | paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE); | 1472 | pte = pte_offset_kernel(pmd, start); |
1395 | if (!paddr) { | 1473 | this_end = (start + PMD_SIZE) & PMD_MASK; |
1396 | prom_printf("Cannot allocate per-cpu memory.\n"); | 1474 | if (this_end > end) |
1397 | prom_halt(); | 1475 | this_end = end; |
1476 | |||
1477 | while (start < this_end) { | ||
1478 | unsigned long paddr = pfn << PAGE_SHIFT; | ||
1479 | |||
1480 | pte_val(*pte) = (paddr | pte_base); | ||
1481 | |||
1482 | start += PAGE_SIZE; | ||
1483 | pte++; | ||
1484 | pfn++; | ||
1485 | } | ||
1486 | } | ||
1487 | } | ||
1488 | |||
1489 | void __init setup_per_cpu_areas(void) | ||
1490 | { | ||
1491 | size_t dyn_size, static_size = __per_cpu_end - __per_cpu_start; | ||
1492 | static struct vm_struct vm; | ||
1493 | unsigned long delta, cpu; | ||
1494 | size_t pcpu_unit_size; | ||
1495 | size_t ptrs_size; | ||
1496 | |||
1497 | pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE + | ||
1498 | PERCPU_DYNAMIC_RESERVE); | ||
1499 | dyn_size = pcpur_size - static_size - PERCPU_MODULE_RESERVE; | ||
1500 | |||
1501 | |||
1502 | ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpur_ptrs[0])); | ||
1503 | pcpur_ptrs = alloc_bootmem(ptrs_size); | ||
1504 | |||
1505 | for_each_possible_cpu(cpu) { | ||
1506 | pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PCPU_CHUNK_SIZE, | ||
1507 | PCPU_CHUNK_SIZE); | ||
1508 | |||
1509 | free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size), | ||
1510 | PCPU_CHUNK_SIZE - pcpur_size); | ||
1511 | |||
1512 | memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size); | ||
1398 | } | 1513 | } |
1399 | 1514 | ||
1400 | ptr = __va(paddr); | 1515 | /* allocate address and map */ |
1401 | __per_cpu_base = ptr - __per_cpu_start; | 1516 | vm.flags = VM_ALLOC; |
1517 | vm.size = num_possible_cpus() * PCPU_CHUNK_SIZE; | ||
1518 | vm_area_register_early(&vm, PCPU_CHUNK_SIZE); | ||
1519 | |||
1520 | for_each_possible_cpu(cpu) { | ||
1521 | unsigned long start = (unsigned long) vm.addr; | ||
1522 | unsigned long end; | ||
1523 | |||
1524 | start += cpu * PCPU_CHUNK_SIZE; | ||
1525 | end = start + PCPU_CHUNK_SIZE; | ||
1526 | pcpu_map_range(start, end, virt_to_page(pcpur_ptrs[cpu])); | ||
1527 | } | ||
1402 | 1528 | ||
1403 | for (i = 0; i < NR_CPUS; i++, ptr += size) | 1529 | pcpu_unit_size = pcpu_setup_first_chunk(pcpur_get_page, static_size, |
1404 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); | 1530 | PERCPU_MODULE_RESERVE, dyn_size, |
1531 | PCPU_CHUNK_SIZE, vm.addr, NULL); | ||
1532 | |||
1533 | free_bootmem(__pa(pcpur_ptrs), ptrs_size); | ||
1534 | |||
1535 | delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; | ||
1536 | for_each_possible_cpu(cpu) { | ||
1537 | __per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size; | ||
1538 | } | ||
1405 | 1539 | ||
1406 | /* Setup %g5 for the boot cpu. */ | 1540 | /* Setup %g5 for the boot cpu. */ |
1407 | __local_per_cpu_offset = __per_cpu_offset(smp_processor_id()); | 1541 | __local_per_cpu_offset = __per_cpu_offset(smp_processor_id()); |
1542 | |||
1543 | of_fill_in_cpu_data(); | ||
1544 | if (tlb_type == hypervisor) | ||
1545 | mdesc_fill_in_cpu_data(cpu_all_mask); | ||
1408 | } | 1546 | } |