Commit e927ecb05e1ce4bbb1e10f57008c94994e2160f5

Authored by Suresh Siddha
Committed by Tony Luck
1 parent 6118ec847e

[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>

Showing 6 changed files with 365 additions and 2 deletions Side-by-side Diff

arch/ia64/kernel/setup.c
... ... @@ -4,10 +4,15 @@
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
... ... @@ -296,6 +301,34 @@
296 301 #endif
297 302 }
298 303  
  304 +#ifdef CONFIG_SMP
  305 +static void
  306 +check_for_logical_procs (void)
  307 +{
  308 + pal_logical_to_physical_t info;
  309 + s64 status;
  310 +
  311 + status = ia64_pal_logical_to_phys(0, &info);
  312 + if (status == -1) {
  313 + printk(KERN_INFO "No logical to physical processor mapping "
  314 + "available\n");
  315 + return;
  316 + }
  317 + if (status) {
  318 + printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
  319 + status);
  320 + return;
  321 + }
  322 + /*
  323 + * Total number of siblings that BSP has. Though not all of them
  324 + * may have booted successfully. The correct number of siblings
  325 + * booted is in info.overview_num_log.
  326 + */
  327 + smp_num_siblings = info.overview_tpc;
  328 + smp_num_cpucores = info.overview_cpp;
  329 +}
  330 +#endif
  331 +
299 332 void __init
300 333 setup_arch (char **cmdline_p)
301 334 {
... ... @@ -356,6 +389,19 @@
356 389  
357 390 #ifdef CONFIG_SMP
358 391 cpu_physical_id(0) = hard_smp_processor_id();
  392 +
  393 + cpu_set(0, cpu_sibling_map[0]);
  394 + cpu_set(0, cpu_core_map[0]);
  395 +
  396 + check_for_logical_procs();
  397 + if (smp_num_cpucores > 1)
  398 + printk(KERN_INFO
  399 + "cpu package is Multi-Core capable: number of cores=%d\n",
  400 + smp_num_cpucores);
  401 + if (smp_num_siblings > 1)
  402 + printk(KERN_INFO
  403 + "cpu package is Multi-Threading capable: number of siblings=%d\n",
  404 + smp_num_siblings);
359 405 #endif
360 406  
361 407 cpu_init(); /* initialize the bootstrap CPU */
362 408  
... ... @@ -459,12 +505,23 @@
459 505 "cpu regs : %u\n"
460 506 "cpu MHz : %lu.%06lu\n"
461 507 "itc MHz : %lu.%06lu\n"
462   - "BogoMIPS : %lu.%02lu\n\n",
  508 + "BogoMIPS : %lu.%02lu\n",
463 509 cpunum, c->vendor, family, c->model, c->revision, c->archrev,
464 510 features, c->ppn, c->number,
465 511 c->proc_freq / 1000000, c->proc_freq % 1000000,
466 512 c->itc_freq / 1000000, c->itc_freq % 1000000,
467 513 lpj*HZ/500000, (lpj*HZ/5000) % 100);
  514 +#ifdef CONFIG_SMP
  515 + if (c->threads_per_core > 1 || c->cores_per_socket > 1)
  516 + seq_printf(m,
  517 + "physical id: %u\n"
  518 + "core id : %u\n"
  519 + "thread id : %u\n",
  520 + c->socket_id, c->core_id, c->thread_id);
  521 + seq_printf(m, "siblings : %u\n", c->num_log);
  522 +#endif
  523 + seq_printf(m,"\n");
  524 +
468 525 return 0;
469 526 }
470 527  
... ... @@ -533,6 +590,14 @@
533 590 memcpy(c->vendor, cpuid.field.vendor, 16);
534 591 #ifdef CONFIG_SMP
535 592 c->cpu = smp_processor_id();
  593 +
  594 + /* below default values will be overwritten by identify_siblings()
  595 + * for Multi-Threading/Multi-Core capable cpu's
  596 + */
  597 + c->threads_per_core = c->cores_per_socket = c->num_log = 1;
  598 + c->socket_id = -1;
  599 +
  600 + identify_siblings(c);
536 601 #endif
537 602 c->ppn = cpuid.field.ppn;
538 603 c->number = cpuid.field.number;
arch/ia64/kernel/smpboot.c
... ... @@ -3,6 +3,11 @@
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.
... ... @@ -10,6 +15,11 @@
10 15 * smp_boot_cpus()/smp_commence() is replaced by
11 16 * smp_prepare_cpus()/__cpu_up()/smp_cpus_done().
12 17 * 04/06/21 Ashok Raj <ashok.raj@intel.com> Added CPU Hotplug Support
  18 + * 04/12/26 Jin Gordon <gordon.jin@intel.com>
  19 + * 04/12/26 Rohit Seth <rohit.seth@intel.com>
  20 + * Add multi-threading and multi-core detection
  21 + * 05/01/30 Suresh Siddha <suresh.b.siddha@intel.com>
  22 + * Setup cpu_sibling_map and cpu_core_map
13 23 */
14 24 #include <linux/config.h>
15 25  
... ... @@ -122,6 +132,11 @@
122 132 cpumask_t cpu_possible_map;
123 133 EXPORT_SYMBOL(cpu_possible_map);
124 134  
  135 +cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
  136 +cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
  137 +int smp_num_siblings = 1;
  138 +int smp_num_cpucores = 1;
  139 +
125 140 /* which logical CPU number maps to which CPU (physical APIC ID) */
126 141 volatile int ia64_cpu_to_sapicid[NR_CPUS];
127 142 EXPORT_SYMBOL(ia64_cpu_to_sapicid);
128 143  
... ... @@ -598,7 +613,68 @@
598 613 cpu_set(smp_processor_id(), cpu_callin_map);
599 614 }
600 615  
  616 +/*
  617 + * mt_info[] is a temporary store for all info returned by
  618 + * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the
  619 + * specific cpu comes.
  620 + */
  621 +static struct {
  622 + __u32 socket_id;
  623 + __u16 core_id;
  624 + __u16 thread_id;
  625 + __u16 proc_fixed_addr;
  626 + __u8 valid;
  627 +}mt_info[NR_CPUS] __devinit;
  628 +
601 629 #ifdef CONFIG_HOTPLUG_CPU
  630 +static inline void
  631 +remove_from_mtinfo(int cpu)
  632 +{
  633 + int i;
  634 +
  635 + for_each_cpu(i)
  636 + if (mt_info[i].valid && mt_info[i].socket_id ==
  637 + cpu_data(cpu)->socket_id)
  638 + mt_info[i].valid = 0;
  639 +}
  640 +
  641 +static inline void
  642 +clear_cpu_sibling_map(int cpu)
  643 +{
  644 + int i;
  645 +
  646 + for_each_cpu_mask(i, cpu_sibling_map[cpu])
  647 + cpu_clear(cpu, cpu_sibling_map[i]);
  648 + for_each_cpu_mask(i, cpu_core_map[cpu])
  649 + cpu_clear(cpu, cpu_core_map[i]);
  650 +
  651 + cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE;
  652 +}
  653 +
  654 +static void
  655 +remove_siblinginfo(int cpu)
  656 +{
  657 + int last = 0;
  658 +
  659 + if (cpu_data(cpu)->threads_per_core == 1 &&
  660 + cpu_data(cpu)->cores_per_socket == 1) {
  661 + cpu_clear(cpu, cpu_core_map[cpu]);
  662 + cpu_clear(cpu, cpu_sibling_map[cpu]);
  663 + return;
  664 + }
  665 +
  666 + last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0);
  667 +
  668 + /* remove it from all sibling map's */
  669 + clear_cpu_sibling_map(cpu);
  670 +
  671 + /* if this cpu is the last in the core group, remove all its info
  672 + * from mt_info structure
  673 + */
  674 + if (last)
  675 + remove_from_mtinfo(cpu);
  676 +}
  677 +
602 678 extern void fixup_irqs(void);
603 679 /* must be called with cpucontrol mutex held */
604 680 int __cpu_disable(void)
... ... @@ -611,6 +687,7 @@
611 687 if (cpu == 0)
612 688 return -EBUSY;
613 689  
  690 + remove_siblinginfo(cpu);
614 691 fixup_irqs();
615 692 local_flush_tlb_all();
616 693 cpu_clear(cpu, cpu_callin_map);
... ... @@ -663,6 +740,23 @@
663 740 (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
664 741 }
665 742  
  743 +static inline void __devinit
  744 +set_cpu_sibling_map(int cpu)
  745 +{
  746 + int i;
  747 +
  748 + for_each_online_cpu(i) {
  749 + if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) {
  750 + cpu_set(i, cpu_core_map[cpu]);
  751 + cpu_set(cpu, cpu_core_map[i]);
  752 + if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) {
  753 + cpu_set(i, cpu_sibling_map[cpu]);
  754 + cpu_set(cpu, cpu_sibling_map[i]);
  755 + }
  756 + }
  757 + }
  758 +}
  759 +
666 760 int __devinit
667 761 __cpu_up (unsigned int cpu)
668 762 {
... ... @@ -685,6 +779,15 @@
685 779 if (ret < 0)
686 780 return ret;
687 781  
  782 + if (cpu_data(cpu)->threads_per_core == 1 &&
  783 + cpu_data(cpu)->cores_per_socket == 1) {
  784 + cpu_set(cpu, cpu_sibling_map[cpu]);
  785 + cpu_set(cpu, cpu_core_map[cpu]);
  786 + return 0;
  787 + }
  788 +
  789 + set_cpu_sibling_map(cpu);
  790 +
688 791 return 0;
689 792 }
690 793  
... ... @@ -710,5 +813,109 @@
710 813 if (sal_ret < 0)
711 814 printk(KERN_ERR "SMP: Can't set SAL AP Boot Rendezvous: %s\n",
712 815 ia64_sal_strerror(sal_ret));
  816 +}
  817 +
  818 +static inline int __devinit
  819 +check_for_mtinfo_index(void)
  820 +{
  821 + int i;
  822 +
  823 + for_each_cpu(i)
  824 + if (!mt_info[i].valid)
  825 + return i;
  826 +
  827 + return -1;
  828 +}
  829 +
  830 +/*
  831 + * Search the mt_info to find out if this socket's cid/tid information is
  832 + * cached or not. If the socket exists, fill in the core_id and thread_id
  833 + * in cpuinfo
  834 + */
  835 +static int __devinit
  836 +check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c)
  837 +{
  838 + int i;
  839 + __u32 sid = c->socket_id;
  840 +
  841 + for_each_cpu(i) {
  842 + if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address
  843 + && mt_info[i].socket_id == sid) {
  844 + c->core_id = mt_info[i].core_id;
  845 + c->thread_id = mt_info[i].thread_id;
  846 + return 1; /* not a new socket */
  847 + }
  848 + }
  849 + return 0;
  850 +}
  851 +
  852 +/*
  853 + * identify_siblings(cpu) gets called from identify_cpu. This populates the
  854 + * information related to logical execution units in per_cpu_data structure.
  855 + */
  856 +void __devinit
  857 +identify_siblings(struct cpuinfo_ia64 *c)
  858 +{
  859 + s64 status;
  860 + u16 pltid;
  861 + u64 proc_fixed_addr;
  862 + int count, i;
  863 + pal_logical_to_physical_t info;
  864 +
  865 + if (smp_num_cpucores == 1 && smp_num_siblings == 1)
  866 + return;
  867 +
  868 + if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) {
  869 + printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
  870 + status);
  871 + return;
  872 + }
  873 + if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) {
  874 + printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status);
  875 + return;
  876 + }
  877 + if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) {
  878 + printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status);
  879 + return;
  880 + }
  881 +
  882 + c->socket_id = (pltid << 8) | info.overview_ppid;
  883 + c->cores_per_socket = info.overview_cpp;
  884 + c->threads_per_core = info.overview_tpc;
  885 + count = c->num_log = info.overview_num_log;
  886 +
  887 + /* If the thread and core id information is already cached, then
  888 + * we will simply update cpu_info and return. Otherwise, we will
  889 + * do the PAL calls and cache core and thread id's of all the siblings.
  890 + */
  891 + if (check_for_new_socket(proc_fixed_addr, c))
  892 + return;
  893 +
  894 + for (i = 0; i < count; i++) {
  895 + int index;
  896 +
  897 + if (i && (status = ia64_pal_logical_to_phys(i, &info))
  898 + != PAL_STATUS_SUCCESS) {
  899 + printk(KERN_ERR "ia64_pal_logical_to_phys failed"
  900 + " with %ld\n", status);
  901 + return;
  902 + }
  903 + if (info.log2_la == proc_fixed_addr) {
  904 + c->core_id = info.log1_cid;
  905 + c->thread_id = info.log1_tid;
  906 + }
  907 +
  908 + index = check_for_mtinfo_index();
  909 + /* We will not do the mt_info caching optimization in this case.
  910 + */
  911 + if (index < 0)
  912 + continue;
  913 +
  914 + mt_info[index].valid = 1;
  915 + mt_info[index].socket_id = c->socket_id;
  916 + mt_info[index].core_id = info.log1_cid;
  917 + mt_info[index].thread_id = info.log1_tid;
  918 + mt_info[index].proc_fixed_addr = info.log2_la;
  919 + }
713 920 }
include/asm-ia64/pal.h
... ... @@ -67,6 +67,7 @@
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 */
... ... @@ -1559,6 +1560,73 @@
1559 1560 return iprv.status;
1560 1561 }
1561 1562  
  1563 +/* data structure for getting information on logical to physical mappings */
  1564 +typedef union pal_log_overview_u {
  1565 + struct {
  1566 + u64 num_log :16, /* Total number of logical
  1567 + * processors on this die
  1568 + */
  1569 + tpc :8, /* Threads per core */
  1570 + reserved3 :8, /* Reserved */
  1571 + cpp :8, /* Cores per processor */
  1572 + reserved2 :8, /* Reserved */
  1573 + ppid :8, /* Physical processor ID */
  1574 + reserved1 :8; /* Reserved */
  1575 + } overview_bits;
  1576 + u64 overview_data;
  1577 +} pal_log_overview_t;
  1578 +
  1579 +typedef union pal_proc_n_log_info1_u{
  1580 + struct {
  1581 + u64 tid :16, /* Thread id */
  1582 + reserved2 :16, /* Reserved */
  1583 + cid :16, /* Core id */
  1584 + reserved1 :16; /* Reserved */
  1585 + } ppli1_bits;
  1586 + u64 ppli1_data;
  1587 +} pal_proc_n_log_info1_t;
  1588 +
  1589 +typedef union pal_proc_n_log_info2_u {
  1590 + struct {
  1591 + u64 la :16, /* Logical address */
  1592 + reserved :48; /* Reserved */
  1593 + } ppli2_bits;
  1594 + u64 ppli2_data;
  1595 +} pal_proc_n_log_info2_t;
  1596 +
  1597 +typedef struct pal_logical_to_physical_s
  1598 +{
  1599 + pal_log_overview_t overview;
  1600 + pal_proc_n_log_info1_t ppli1;
  1601 + pal_proc_n_log_info2_t ppli2;
  1602 +} pal_logical_to_physical_t;
  1603 +
  1604 +#define overview_num_log overview.overview_bits.num_log
  1605 +#define overview_tpc overview.overview_bits.tpc
  1606 +#define overview_cpp overview.overview_bits.cpp
  1607 +#define overview_ppid overview.overview_bits.ppid
  1608 +#define log1_tid ppli1.ppli1_bits.tid
  1609 +#define log1_cid ppli1.ppli1_bits.cid
  1610 +#define log2_la ppli2.ppli2_bits.la
  1611 +
  1612 +/* Get information on logical to physical processor mappings. */
  1613 +static inline s64
  1614 +ia64_pal_logical_to_phys(u64 proc_number, pal_logical_to_physical_t *mapping)
  1615 +{
  1616 + struct ia64_pal_retval iprv;
  1617 +
  1618 + PAL_CALL(iprv, PAL_LOGICAL_TO_PHYSICAL, proc_number, 0, 0);
  1619 +
  1620 + if (iprv.status == PAL_STATUS_SUCCESS)
  1621 + {
  1622 + if (proc_number == 0)
  1623 + mapping->overview.overview_data = iprv.v0;
  1624 + mapping->ppli1.ppli1_data = iprv.v1;
  1625 + mapping->ppli2.ppli2_data = iprv.v2;
  1626 + }
  1627 +
  1628 + return iprv.status;
  1629 +}
1562 1630 #endif /* __ASSEMBLY__ */
1563 1631  
1564 1632 #endif /* _ASM_IA64_PAL_H */
include/asm-ia64/processor.h
... ... @@ -148,6 +148,13 @@
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: */
include/asm-ia64/sal.h
... ... @@ -91,6 +91,7 @@
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  
... ... @@ -812,6 +813,17 @@
812 813 *error_code = isrv.v0;
813 814 if (scratch_buf_size_needed)
814 815 *scratch_buf_size_needed = isrv.v1;
  816 + return isrv.status;
  817 +}
  818 +
  819 +/* Get physical processor die mapping in the platform. */
  820 +static inline s64
  821 +ia64_sal_physical_id_info(u16 *splid)
  822 +{
  823 + struct ia64_sal_retval isrv;
  824 + SAL_CALL(isrv, SAL_PHYSICAL_ID_INFO, 0, 0, 0, 0, 0, 0, 0);
  825 + if (splid)
  826 + *splid = isrv.v0;
815 827 return isrv.status;
816 828 }
817 829  
include/asm-ia64/smp.h
... ... @@ -56,6 +56,10 @@
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  
... ... @@ -124,6 +128,7 @@
124 128 extern void smp_send_reschedule (int cpu);
125 129 extern void lock_ipi_calllock(void);
126 130 extern void unlock_ipi_calllock(void);
  131 +extern void identify_siblings (struct cpuinfo_ia64 *);
127 132  
128 133 #else
129 134