Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IA64] multi-core/multi-thread identification

Version 3 - rediffed to apply on top of Ashok's hotplug cpu
patch. /proc/cpuinfo output in step with x86.

This is an updated MC/MT identification patch based on the
previous discussions on list.

Add the Multi-core and Multi-threading detection for IPF.
- Add new core and threading related fields in /proc/cpuinfo.
Physical id
Core id
Thread id
Siblings
- setup the cpu_core_map and cpu_sibling_map appropriately
- Handles Hot plug CPU

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: Gordon Jin <gordon.jin@intel.com>
Signed-off-by: Rohit Seth <rohit.seth@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>

authored by

Suresh Siddha and committed by
Tony Luck
e927ecb0 6118ec84

+365 -2
+67 -2
arch/ia64/kernel/setup.c
··· 4 4 * Copyright (C) 1998-2001, 2003-2004 Hewlett-Packard Co 5 5 * David Mosberger-Tang <davidm@hpl.hp.com> 6 6 * Stephane Eranian <eranian@hpl.hp.com> 7 - * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com> 7 + * Copyright (C) 2000, 2004 Intel Corp 8 + * Rohit Seth <rohit.seth@intel.com> 9 + * Suresh Siddha <suresh.b.siddha@intel.com> 10 + * Gordon Jin <gordon.jin@intel.com> 8 11 * Copyright (C) 1999 VA Linux Systems 9 12 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 10 13 * 14 + * 12/26/04 S.Siddha, G.Jin, R.Seth 15 + * Add multi-threading and multi-core detection 11 16 * 11/12/01 D.Mosberger Convert get_cpuinfo() to seq_file based show_cpuinfo(). 12 17 * 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map 13 18 * 03/31/00 R.Seth cpu_initialized and current->processor fixes ··· 301 296 #endif 302 297 } 303 298 299 + #ifdef CONFIG_SMP 300 + static void 301 + check_for_logical_procs (void) 302 + { 303 + pal_logical_to_physical_t info; 304 + s64 status; 305 + 306 + status = ia64_pal_logical_to_phys(0, &info); 307 + if (status == -1) { 308 + printk(KERN_INFO "No logical to physical processor mapping " 309 + "available\n"); 310 + return; 311 + } 312 + if (status) { 313 + printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", 314 + status); 315 + return; 316 + } 317 + /* 318 + * Total number of siblings that BSP has. Though not all of them 319 + * may have booted successfully. The correct number of siblings 320 + * booted is in info.overview_num_log. 321 + */ 322 + smp_num_siblings = info.overview_tpc; 323 + smp_num_cpucores = info.overview_cpp; 324 + } 325 + #endif 326 + 304 327 void __init 305 328 setup_arch (char **cmdline_p) 306 329 { ··· 389 356 390 357 #ifdef CONFIG_SMP 391 358 cpu_physical_id(0) = hard_smp_processor_id(); 359 + 360 + cpu_set(0, cpu_sibling_map[0]); 361 + cpu_set(0, cpu_core_map[0]); 362 + 363 + check_for_logical_procs(); 364 + if (smp_num_cpucores > 1) 365 + printk(KERN_INFO 366 + "cpu package is Multi-Core capable: number of cores=%d\n", 367 + smp_num_cpucores); 368 + if (smp_num_siblings > 1) 369 + printk(KERN_INFO 370 + "cpu package is Multi-Threading capable: number of siblings=%d\n", 371 + smp_num_siblings); 392 372 #endif 393 373 394 374 cpu_init(); /* initialize the bootstrap CPU */ ··· 505 459 "cpu regs : %u\n" 506 460 "cpu MHz : %lu.%06lu\n" 507 461 "itc MHz : %lu.%06lu\n" 508 - "BogoMIPS : %lu.%02lu\n\n", 462 + "BogoMIPS : %lu.%02lu\n", 509 463 cpunum, c->vendor, family, c->model, c->revision, c->archrev, 510 464 features, c->ppn, c->number, 511 465 c->proc_freq / 1000000, c->proc_freq % 1000000, 512 466 c->itc_freq / 1000000, c->itc_freq % 1000000, 513 467 lpj*HZ/500000, (lpj*HZ/5000) % 100); 468 + #ifdef CONFIG_SMP 469 + if (c->threads_per_core > 1 || c->cores_per_socket > 1) 470 + seq_printf(m, 471 + "physical id: %u\n" 472 + "core id : %u\n" 473 + "thread id : %u\n", 474 + c->socket_id, c->core_id, c->thread_id); 475 + seq_printf(m, "siblings : %u\n", c->num_log); 476 + #endif 477 + seq_printf(m,"\n"); 478 + 514 479 return 0; 515 480 } 516 481 ··· 590 533 memcpy(c->vendor, cpuid.field.vendor, 16); 591 534 #ifdef CONFIG_SMP 592 535 c->cpu = smp_processor_id(); 536 + 537 + /* below default values will be overwritten by identify_siblings() 538 + * for Multi-Threading/Multi-Core capable cpu's 539 + */ 540 + c->threads_per_core = c->cores_per_socket = c->num_log = 1; 541 + c->socket_id = -1; 542 + 543 + identify_siblings(c); 593 544 #endif 594 545 c->ppn = cpuid.field.ppn; 595 546 c->number = cpuid.field.number;
+206
arch/ia64/kernel/smpboot.c
··· 3 3 * 4 4 * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co 5 5 * David Mosberger-Tang <davidm@hpl.hp.com> 6 + * Copyright (C) 2001, 2004-2005 Intel Corp 7 + * Rohit Seth <rohit.seth@intel.com> 8 + * Suresh Siddha <suresh.b.siddha@intel.com> 9 + * Gordon Jin <gordon.jin@intel.com> 10 + * Ashok Raj <ashok.raj@intel.com> 6 11 * 7 12 * 01/05/16 Rohit Seth <rohit.seth@intel.com> Moved SMP booting functions from smp.c to here. 8 13 * 01/04/27 David Mosberger <davidm@hpl.hp.com> Added ITC synching code. ··· 15 10 * smp_boot_cpus()/smp_commence() is replaced by 16 11 * smp_prepare_cpus()/__cpu_up()/smp_cpus_done(). 17 12 * 04/06/21 Ashok Raj <ashok.raj@intel.com> Added CPU Hotplug Support 13 + * 04/12/26 Jin Gordon <gordon.jin@intel.com> 14 + * 04/12/26 Rohit Seth <rohit.seth@intel.com> 15 + * Add multi-threading and multi-core detection 16 + * 05/01/30 Suresh Siddha <suresh.b.siddha@intel.com> 17 + * Setup cpu_sibling_map and cpu_core_map 18 18 */ 19 19 #include <linux/config.h> 20 20 ··· 131 121 EXPORT_SYMBOL(cpu_online_map); 132 122 cpumask_t cpu_possible_map; 133 123 EXPORT_SYMBOL(cpu_possible_map); 124 + 125 + cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; 126 + cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; 127 + int smp_num_siblings = 1; 128 + int smp_num_cpucores = 1; 134 129 135 130 /* which logical CPU number maps to which CPU (physical APIC ID) */ 136 131 volatile int ia64_cpu_to_sapicid[NR_CPUS]; ··· 613 598 cpu_set(smp_processor_id(), cpu_callin_map); 614 599 } 615 600 601 + /* 602 + * mt_info[] is a temporary store for all info returned by 603 + * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the 604 + * specific cpu comes. 605 + */ 606 + static struct { 607 + __u32 socket_id; 608 + __u16 core_id; 609 + __u16 thread_id; 610 + __u16 proc_fixed_addr; 611 + __u8 valid; 612 + }mt_info[NR_CPUS] __devinit; 613 + 616 614 #ifdef CONFIG_HOTPLUG_CPU 615 + static inline void 616 + remove_from_mtinfo(int cpu) 617 + { 618 + int i; 619 + 620 + for_each_cpu(i) 621 + if (mt_info[i].valid && mt_info[i].socket_id == 622 + cpu_data(cpu)->socket_id) 623 + mt_info[i].valid = 0; 624 + } 625 + 626 + static inline void 627 + clear_cpu_sibling_map(int cpu) 628 + { 629 + int i; 630 + 631 + for_each_cpu_mask(i, cpu_sibling_map[cpu]) 632 + cpu_clear(cpu, cpu_sibling_map[i]); 633 + for_each_cpu_mask(i, cpu_core_map[cpu]) 634 + cpu_clear(cpu, cpu_core_map[i]); 635 + 636 + cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE; 637 + } 638 + 639 + static void 640 + remove_siblinginfo(int cpu) 641 + { 642 + int last = 0; 643 + 644 + if (cpu_data(cpu)->threads_per_core == 1 && 645 + cpu_data(cpu)->cores_per_socket == 1) { 646 + cpu_clear(cpu, cpu_core_map[cpu]); 647 + cpu_clear(cpu, cpu_sibling_map[cpu]); 648 + return; 649 + } 650 + 651 + last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0); 652 + 653 + /* remove it from all sibling map's */ 654 + clear_cpu_sibling_map(cpu); 655 + 656 + /* if this cpu is the last in the core group, remove all its info 657 + * from mt_info structure 658 + */ 659 + if (last) 660 + remove_from_mtinfo(cpu); 661 + } 662 + 617 663 extern void fixup_irqs(void); 618 664 /* must be called with cpucontrol mutex held */ 619 665 int __cpu_disable(void) ··· 687 611 if (cpu == 0) 688 612 return -EBUSY; 689 613 614 + remove_siblinginfo(cpu); 690 615 fixup_irqs(); 691 616 local_flush_tlb_all(); 692 617 cpu_clear(cpu, cpu_callin_map); ··· 740 663 (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); 741 664 } 742 665 666 + static inline void __devinit 667 + set_cpu_sibling_map(int cpu) 668 + { 669 + int i; 670 + 671 + for_each_online_cpu(i) { 672 + if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) { 673 + cpu_set(i, cpu_core_map[cpu]); 674 + cpu_set(cpu, cpu_core_map[i]); 675 + if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) { 676 + cpu_set(i, cpu_sibling_map[cpu]); 677 + cpu_set(cpu, cpu_sibling_map[i]); 678 + } 679 + } 680 + } 681 + } 682 + 743 683 int __devinit 744 684 __cpu_up (unsigned int cpu) 745 685 { ··· 778 684 ret = do_boot_cpu(sapicid, cpu); 779 685 if (ret < 0) 780 686 return ret; 687 + 688 + if (cpu_data(cpu)->threads_per_core == 1 && 689 + cpu_data(cpu)->cores_per_socket == 1) { 690 + cpu_set(cpu, cpu_sibling_map[cpu]); 691 + cpu_set(cpu, cpu_core_map[cpu]); 692 + return 0; 693 + } 694 + 695 + set_cpu_sibling_map(cpu); 781 696 782 697 return 0; 783 698 } ··· 815 712 ia64_sal_strerror(sal_ret)); 816 713 } 817 714 715 + static inline int __devinit 716 + check_for_mtinfo_index(void) 717 + { 718 + int i; 719 + 720 + for_each_cpu(i) 721 + if (!mt_info[i].valid) 722 + return i; 723 + 724 + return -1; 725 + } 726 + 727 + /* 728 + * Search the mt_info to find out if this socket's cid/tid information is 729 + * cached or not. If the socket exists, fill in the core_id and thread_id 730 + * in cpuinfo 731 + */ 732 + static int __devinit 733 + check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c) 734 + { 735 + int i; 736 + __u32 sid = c->socket_id; 737 + 738 + for_each_cpu(i) { 739 + if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address 740 + && mt_info[i].socket_id == sid) { 741 + c->core_id = mt_info[i].core_id; 742 + c->thread_id = mt_info[i].thread_id; 743 + return 1; /* not a new socket */ 744 + } 745 + } 746 + return 0; 747 + } 748 + 749 + /* 750 + * identify_siblings(cpu) gets called from identify_cpu. This populates the 751 + * information related to logical execution units in per_cpu_data structure. 752 + */ 753 + void __devinit 754 + identify_siblings(struct cpuinfo_ia64 *c) 755 + { 756 + s64 status; 757 + u16 pltid; 758 + u64 proc_fixed_addr; 759 + int count, i; 760 + pal_logical_to_physical_t info; 761 + 762 + if (smp_num_cpucores == 1 && smp_num_siblings == 1) 763 + return; 764 + 765 + if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) { 766 + printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", 767 + status); 768 + return; 769 + } 770 + if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) { 771 + printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status); 772 + return; 773 + } 774 + if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) { 775 + printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status); 776 + return; 777 + } 778 + 779 + c->socket_id = (pltid << 8) | info.overview_ppid; 780 + c->cores_per_socket = info.overview_cpp; 781 + c->threads_per_core = info.overview_tpc; 782 + count = c->num_log = info.overview_num_log; 783 + 784 + /* If the thread and core id information is already cached, then 785 + * we will simply update cpu_info and return. Otherwise, we will 786 + * do the PAL calls and cache core and thread id's of all the siblings. 787 + */ 788 + if (check_for_new_socket(proc_fixed_addr, c)) 789 + return; 790 + 791 + for (i = 0; i < count; i++) { 792 + int index; 793 + 794 + if (i && (status = ia64_pal_logical_to_phys(i, &info)) 795 + != PAL_STATUS_SUCCESS) { 796 + printk(KERN_ERR "ia64_pal_logical_to_phys failed" 797 + " with %ld\n", status); 798 + return; 799 + } 800 + if (info.log2_la == proc_fixed_addr) { 801 + c->core_id = info.log1_cid; 802 + c->thread_id = info.log1_tid; 803 + } 804 + 805 + index = check_for_mtinfo_index(); 806 + /* We will not do the mt_info caching optimization in this case. 807 + */ 808 + if (index < 0) 809 + continue; 810 + 811 + mt_info[index].valid = 1; 812 + mt_info[index].socket_id = c->socket_id; 813 + mt_info[index].core_id = info.log1_cid; 814 + mt_info[index].thread_id = info.log1_tid; 815 + mt_info[index].proc_fixed_addr = info.log2_la; 816 + } 817 + }
+68
include/asm-ia64/pal.h
··· 67 67 #define PAL_REGISTER_INFO 39 /* return AR and CR register information*/ 68 68 #define PAL_SHUTDOWN 40 /* enter processor shutdown state */ 69 69 #define PAL_PREFETCH_VISIBILITY 41 /* Make Processor Prefetches Visible */ 70 + #define PAL_LOGICAL_TO_PHYSICAL 42 /* returns information on logical to physical processor mapping */ 70 71 71 72 #define PAL_COPY_PAL 256 /* relocate PAL procedures and PAL PMI */ 72 73 #define PAL_HALT_INFO 257 /* return the low power capabilities of processor */ ··· 1560 1559 return iprv.status; 1561 1560 } 1562 1561 1562 + /* data structure for getting information on logical to physical mappings */ 1563 + typedef union pal_log_overview_u { 1564 + struct { 1565 + u64 num_log :16, /* Total number of logical 1566 + * processors on this die 1567 + */ 1568 + tpc :8, /* Threads per core */ 1569 + reserved3 :8, /* Reserved */ 1570 + cpp :8, /* Cores per processor */ 1571 + reserved2 :8, /* Reserved */ 1572 + ppid :8, /* Physical processor ID */ 1573 + reserved1 :8; /* Reserved */ 1574 + } overview_bits; 1575 + u64 overview_data; 1576 + } pal_log_overview_t; 1577 + 1578 + typedef union pal_proc_n_log_info1_u{ 1579 + struct { 1580 + u64 tid :16, /* Thread id */ 1581 + reserved2 :16, /* Reserved */ 1582 + cid :16, /* Core id */ 1583 + reserved1 :16; /* Reserved */ 1584 + } ppli1_bits; 1585 + u64 ppli1_data; 1586 + } pal_proc_n_log_info1_t; 1587 + 1588 + typedef union pal_proc_n_log_info2_u { 1589 + struct { 1590 + u64 la :16, /* Logical address */ 1591 + reserved :48; /* Reserved */ 1592 + } ppli2_bits; 1593 + u64 ppli2_data; 1594 + } pal_proc_n_log_info2_t; 1595 + 1596 + typedef struct pal_logical_to_physical_s 1597 + { 1598 + pal_log_overview_t overview; 1599 + pal_proc_n_log_info1_t ppli1; 1600 + pal_proc_n_log_info2_t ppli2; 1601 + } pal_logical_to_physical_t; 1602 + 1603 + #define overview_num_log overview.overview_bits.num_log 1604 + #define overview_tpc overview.overview_bits.tpc 1605 + #define overview_cpp overview.overview_bits.cpp 1606 + #define overview_ppid overview.overview_bits.ppid 1607 + #define log1_tid ppli1.ppli1_bits.tid 1608 + #define log1_cid ppli1.ppli1_bits.cid 1609 + #define log2_la ppli2.ppli2_bits.la 1610 + 1611 + /* Get information on logical to physical processor mappings. */ 1612 + static inline s64 1613 + ia64_pal_logical_to_phys(u64 proc_number, pal_logical_to_physical_t *mapping) 1614 + { 1615 + struct ia64_pal_retval iprv; 1616 + 1617 + PAL_CALL(iprv, PAL_LOGICAL_TO_PHYSICAL, proc_number, 0, 0); 1618 + 1619 + if (iprv.status == PAL_STATUS_SUCCESS) 1620 + { 1621 + if (proc_number == 0) 1622 + mapping->overview.overview_data = iprv.v0; 1623 + mapping->ppli1.ppli1_data = iprv.v1; 1624 + mapping->ppli2.ppli2_data = iprv.v2; 1625 + } 1626 + 1627 + return iprv.status; 1628 + } 1563 1629 #endif /* __ASSEMBLY__ */ 1564 1630 1565 1631 #endif /* _ASM_IA64_PAL_H */
+7
include/asm-ia64/processor.h
··· 148 148 #ifdef CONFIG_SMP 149 149 __u64 loops_per_jiffy; 150 150 int cpu; 151 + __u32 socket_id; /* physical processor socket id */ 152 + __u16 core_id; /* core id */ 153 + __u16 thread_id; /* thread id */ 154 + __u16 num_log; /* Total number of logical processors on 155 + * this socket that were successfully booted */ 156 + __u8 cores_per_socket; /* Cores per processor socket */ 157 + __u8 threads_per_core; /* Threads per core */ 151 158 #endif 152 159 153 160 /* CPUID-derived information: */
+12
include/asm-ia64/sal.h
··· 91 91 #define SAL_PCI_CONFIG_READ 0x01000010 92 92 #define SAL_PCI_CONFIG_WRITE 0x01000011 93 93 #define SAL_FREQ_BASE 0x01000012 94 + #define SAL_PHYSICAL_ID_INFO 0x01000013 94 95 95 96 #define SAL_UPDATE_PAL 0x01000020 96 97 ··· 813 812 *error_code = isrv.v0; 814 813 if (scratch_buf_size_needed) 815 814 *scratch_buf_size_needed = isrv.v1; 815 + return isrv.status; 816 + } 817 + 818 + /* Get physical processor die mapping in the platform. */ 819 + static inline s64 820 + ia64_sal_physical_id_info(u16 *splid) 821 + { 822 + struct ia64_sal_retval isrv; 823 + SAL_CALL(isrv, SAL_PHYSICAL_ID_INFO, 0, 0, 0, 0, 0, 0, 0); 824 + if (splid) 825 + *splid = isrv.v0; 816 826 return isrv.status; 817 827 } 818 828
+5
include/asm-ia64/smp.h
··· 56 56 extern char no_int_routing __devinitdata; 57 57 58 58 extern cpumask_t cpu_online_map; 59 + extern cpumask_t cpu_core_map[NR_CPUS]; 60 + extern cpumask_t cpu_sibling_map[NR_CPUS]; 61 + extern int smp_num_siblings; 62 + extern int smp_num_cpucores; 59 63 extern void __iomem *ipi_base_addr; 60 64 extern unsigned char smp_int_redirect; 61 65 ··· 128 124 extern void smp_send_reschedule (int cpu); 129 125 extern void lock_ipi_calllock(void); 130 126 extern void unlock_ipi_calllock(void); 127 + extern void identify_siblings (struct cpuinfo_ia64 *); 131 128 132 129 #else 133 130