Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e927ecb0 authored by Suresh Siddha's avatar Suresh Siddha Committed by Tony Luck
Browse files

[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: default avatarSuresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: default avatarGordon Jin <gordon.jin@intel.com>
Signed-off-by: default avatarRohit Seth <rohit.seth@intel.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 6118ec84
Loading
Loading
Loading
Loading
+67 −2
Original line number Diff line number Diff line
@@ -4,10 +4,15 @@
 * Copyright (C) 1998-2001, 2003-2004 Hewlett-Packard Co
 *	David Mosberger-Tang <davidm@hpl.hp.com>
 *	Stephane Eranian <eranian@hpl.hp.com>
 * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
 * Copyright (C) 2000, 2004 Intel Corp
 * 	Rohit Seth <rohit.seth@intel.com>
 * 	Suresh Siddha <suresh.b.siddha@intel.com>
 * 	Gordon Jin <gordon.jin@intel.com>
 * Copyright (C) 1999 VA Linux Systems
 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
 *
 * 12/26/04 S.Siddha, G.Jin, R.Seth
 *			Add multi-threading and multi-core detection
 * 11/12/01 D.Mosberger Convert get_cpuinfo() to seq_file based show_cpuinfo().
 * 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map
 * 03/31/00 R.Seth	cpu_initialized and current->processor fixes
@@ -296,6 +301,34 @@ mark_bsp_online (void)
#endif
}

#ifdef CONFIG_SMP
static void
check_for_logical_procs (void)
{
	pal_logical_to_physical_t info;
	s64 status;

	status = ia64_pal_logical_to_phys(0, &info);
	if (status == -1) {
		printk(KERN_INFO "No logical to physical processor mapping "
		       "available\n");
		return;
	}
	if (status) {
		printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
		       status);
		return;
	}
	/*
	 * Total number of siblings that BSP has.  Though not all of them 
	 * may have booted successfully. The correct number of siblings 
	 * booted is in info.overview_num_log.
	 */
	smp_num_siblings = info.overview_tpc;
	smp_num_cpucores = info.overview_cpp;
}
#endif

void __init
setup_arch (char **cmdline_p)
{
@@ -356,6 +389,19 @@ setup_arch (char **cmdline_p)

#ifdef CONFIG_SMP
	cpu_physical_id(0) = hard_smp_processor_id();

	cpu_set(0, cpu_sibling_map[0]);
	cpu_set(0, cpu_core_map[0]);

	check_for_logical_procs();
	if (smp_num_cpucores > 1)
		printk(KERN_INFO
		       "cpu package is Multi-Core capable: number of cores=%d\n",
		       smp_num_cpucores);
	if (smp_num_siblings > 1)
		printk(KERN_INFO
		       "cpu package is Multi-Threading capable: number of siblings=%d\n",
		       smp_num_siblings);
#endif

	cpu_init();	/* initialize the bootstrap CPU */
@@ -459,12 +505,23 @@ show_cpuinfo (struct seq_file *m, void *v)
		   "cpu regs   : %u\n"
		   "cpu MHz    : %lu.%06lu\n"
		   "itc MHz    : %lu.%06lu\n"
		   "BogoMIPS   : %lu.%02lu\n\n",
		   "BogoMIPS   : %lu.%02lu\n",
		   cpunum, c->vendor, family, c->model, c->revision, c->archrev,
		   features, c->ppn, c->number,
		   c->proc_freq / 1000000, c->proc_freq % 1000000,
		   c->itc_freq / 1000000, c->itc_freq % 1000000,
		   lpj*HZ/500000, (lpj*HZ/5000) % 100);
#ifdef CONFIG_SMP
	if (c->threads_per_core > 1 || c->cores_per_socket > 1)
		seq_printf(m,
		   	   "physical id: %u\n"
		   	   "core id    : %u\n"
		   	   "thread id  : %u\n",
		   	   c->socket_id, c->core_id, c->thread_id);
	seq_printf(m, "siblings   : %u\n", c->num_log);
#endif
	seq_printf(m,"\n");

	return 0;
}

@@ -533,6 +590,14 @@ identify_cpu (struct cpuinfo_ia64 *c)
	memcpy(c->vendor, cpuid.field.vendor, 16);
#ifdef CONFIG_SMP
	c->cpu = smp_processor_id();

	/* below default values will be overwritten  by identify_siblings() 
	 * for Multi-Threading/Multi-Core capable cpu's
	 */
	c->threads_per_core = c->cores_per_socket = c->num_log = 1;
	c->socket_id = -1;

	identify_siblings(c);
#endif
	c->ppn = cpuid.field.ppn;
	c->number = cpuid.field.number;
+206 −0
Original line number Diff line number Diff line
@@ -3,6 +3,11 @@
 *
 * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co
 *	David Mosberger-Tang <davidm@hpl.hp.com>
 * Copyright (C) 2001, 2004-2005 Intel Corp
 * 	Rohit Seth <rohit.seth@intel.com>
 * 	Suresh Siddha <suresh.b.siddha@intel.com>
 * 	Gordon Jin <gordon.jin@intel.com>
 *	Ashok Raj  <ashok.raj@intel.com>
 *
 * 01/05/16 Rohit Seth <rohit.seth@intel.com>	Moved SMP booting functions from smp.c to here.
 * 01/04/27 David Mosberger <davidm@hpl.hp.com>	Added ITC synching code.
@@ -10,6 +15,11 @@
 *						smp_boot_cpus()/smp_commence() is replaced by
 *						smp_prepare_cpus()/__cpu_up()/smp_cpus_done().
 * 04/06/21 Ashok Raj		<ashok.raj@intel.com> Added CPU Hotplug Support
 * 04/12/26 Jin Gordon <gordon.jin@intel.com>
 * 04/12/26 Rohit Seth <rohit.seth@intel.com>
 *						Add multi-threading and multi-core detection
 * 05/01/30 Suresh Siddha <suresh.b.siddha@intel.com>
 *						Setup cpu_sibling_map and cpu_core_map
 */
#include <linux/config.h>

@@ -122,6 +132,11 @@ EXPORT_SYMBOL(cpu_online_map);
cpumask_t cpu_possible_map;
EXPORT_SYMBOL(cpu_possible_map);

cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
int smp_num_siblings = 1;
int smp_num_cpucores = 1;

/* which logical CPU number maps to which CPU (physical APIC ID) */
volatile int ia64_cpu_to_sapicid[NR_CPUS];
EXPORT_SYMBOL(ia64_cpu_to_sapicid);
@@ -598,7 +613,68 @@ void __devinit smp_prepare_boot_cpu(void)
	cpu_set(smp_processor_id(), cpu_callin_map);
}

/*
 * mt_info[] is a temporary store for all info returned by
 * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the
 * specific cpu comes.
 */
static struct {
	__u32   socket_id;
	__u16   core_id;
	__u16   thread_id;
	__u16   proc_fixed_addr;
	__u8    valid;
}mt_info[NR_CPUS] __devinit;

#ifdef CONFIG_HOTPLUG_CPU
static inline void
remove_from_mtinfo(int cpu)
{
	int i;

	for_each_cpu(i)
		if (mt_info[i].valid &&  mt_info[i].socket_id ==
		    				cpu_data(cpu)->socket_id)
			mt_info[i].valid = 0;
}

static inline void
clear_cpu_sibling_map(int cpu)
{
	int i;

	for_each_cpu_mask(i, cpu_sibling_map[cpu])
		cpu_clear(cpu, cpu_sibling_map[i]);
	for_each_cpu_mask(i, cpu_core_map[cpu])
		cpu_clear(cpu, cpu_core_map[i]);

	cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE;
}

static void
remove_siblinginfo(int cpu)
{
	int last = 0;

	if (cpu_data(cpu)->threads_per_core == 1 &&
	    cpu_data(cpu)->cores_per_socket == 1) {
		cpu_clear(cpu, cpu_core_map[cpu]);
		cpu_clear(cpu, cpu_sibling_map[cpu]);
		return;
	}

	last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0);

	/* remove it from all sibling map's */
	clear_cpu_sibling_map(cpu);

	/* if this cpu is the last in the core group, remove all its info 
	 * from mt_info structure
	 */
	if (last)
		remove_from_mtinfo(cpu);
}

extern void fixup_irqs(void);
/* must be called with cpucontrol mutex held */
int __cpu_disable(void)
@@ -611,6 +687,7 @@ int __cpu_disable(void)
	if (cpu == 0)
		return -EBUSY;

	remove_siblinginfo(cpu);
	fixup_irqs();
	local_flush_tlb_all();
	cpu_clear(cpu, cpu_callin_map);
@@ -663,6 +740,23 @@ smp_cpus_done (unsigned int dummy)
	       (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
}

static inline void __devinit
set_cpu_sibling_map(int cpu)
{
	int i;

	for_each_online_cpu(i) {
		if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) {
			cpu_set(i, cpu_core_map[cpu]);
			cpu_set(cpu, cpu_core_map[i]);
			if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) {
				cpu_set(i, cpu_sibling_map[cpu]);
				cpu_set(cpu, cpu_sibling_map[i]);
			}
		}
	}
}

int __devinit
__cpu_up (unsigned int cpu)
{
@@ -685,6 +779,15 @@ __cpu_up (unsigned int cpu)
	if (ret < 0)
		return ret;

	if (cpu_data(cpu)->threads_per_core == 1 &&
	    cpu_data(cpu)->cores_per_socket == 1) {
		cpu_set(cpu, cpu_sibling_map[cpu]);
		cpu_set(cpu, cpu_core_map[cpu]);
		return 0;
	}

	set_cpu_sibling_map(cpu);

	return 0;
}

@@ -712,3 +815,106 @@ init_smp_config(void)
		       ia64_sal_strerror(sal_ret));
}

static inline int __devinit
check_for_mtinfo_index(void)
{
	int i;
	
	for_each_cpu(i)
		if (!mt_info[i].valid)
			return i;

	return -1;
}

/*
 * Search the mt_info to find out if this socket's cid/tid information is
 * cached or not. If the socket exists, fill in the core_id and thread_id 
 * in cpuinfo
 */
static int __devinit
check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c)
{
	int i;
	__u32 sid = c->socket_id;

	for_each_cpu(i) {
		if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address
		    && mt_info[i].socket_id == sid) {
			c->core_id = mt_info[i].core_id;
			c->thread_id = mt_info[i].thread_id;
			return 1; /* not a new socket */
		}
	}
	return 0;
}

/*
 * identify_siblings(cpu) gets called from identify_cpu. This populates the 
 * information related to logical execution units in per_cpu_data structure.
 */
void __devinit
identify_siblings(struct cpuinfo_ia64 *c)
{
	s64 status;
	u16 pltid;
	u64 proc_fixed_addr;
	int count, i;
	pal_logical_to_physical_t info;

	if (smp_num_cpucores == 1 && smp_num_siblings == 1)
		return;

	if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) {
		printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n",
		       status);
		return;
	}
	if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) {
		printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status);
		return;
	}
	if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) {
		printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status);
		return;
	}

	c->socket_id =  (pltid << 8) | info.overview_ppid;
	c->cores_per_socket = info.overview_cpp;
	c->threads_per_core = info.overview_tpc;
	count = c->num_log = info.overview_num_log;

	/* If the thread and core id information is already cached, then
	 * we will simply update cpu_info and return. Otherwise, we will
	 * do the PAL calls and cache core and thread id's of all the siblings.
	 */
	if (check_for_new_socket(proc_fixed_addr, c))
		return;

	for (i = 0; i < count; i++) {
		int index;

		if (i && (status = ia64_pal_logical_to_phys(i, &info))
			  != PAL_STATUS_SUCCESS) {
                	printk(KERN_ERR "ia64_pal_logical_to_phys failed"
					" with %ld\n", status);
                	return;
		}
		if (info.log2_la == proc_fixed_addr) {
			c->core_id = info.log1_cid;
			c->thread_id = info.log1_tid;
		}

		index = check_for_mtinfo_index();
		/* We will not do the mt_info caching optimization in this case.
		 */
		if (index < 0)
			continue;

		mt_info[index].valid = 1;
		mt_info[index].socket_id = c->socket_id;
		mt_info[index].core_id = info.log1_cid;
		mt_info[index].thread_id = info.log1_tid;
		mt_info[index].proc_fixed_addr = info.log2_la;
	}
}
+68 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@
#define PAL_REGISTER_INFO	39	/* return AR and CR register information*/
#define PAL_SHUTDOWN		40	/* enter processor shutdown state */
#define PAL_PREFETCH_VISIBILITY	41	/* Make Processor Prefetches Visible */
#define PAL_LOGICAL_TO_PHYSICAL 42	/* returns information on logical to physical processor mapping */

#define PAL_COPY_PAL		256	/* relocate PAL procedures and PAL PMI */
#define PAL_HALT_INFO		257	/* return the low power capabilities of processor */
@@ -1559,6 +1560,73 @@ ia64_pal_prefetch_visibility (s64 trans_type)
	return iprv.status;
}

/* data structure for getting information on logical to physical mappings */
typedef union pal_log_overview_u {
	struct {
		u64	num_log		:16,	/* Total number of logical
						 * processors on this die
						 */
			tpc		:8,	/* Threads per core */
			reserved3	:8,	/* Reserved */
			cpp		:8,	/* Cores per processor */
			reserved2	:8,	/* Reserved */
			ppid		:8,	/* Physical processor ID */
			reserved1	:8;	/* Reserved */
	} overview_bits;
	u64 overview_data;
} pal_log_overview_t;

typedef union pal_proc_n_log_info1_u{
	struct {
		u64	tid		:16,	/* Thread id */
			reserved2	:16,	/* Reserved */
			cid		:16,	/* Core id */
			reserved1	:16;	/* Reserved */
	} ppli1_bits;
	u64	ppli1_data;
} pal_proc_n_log_info1_t;

typedef union pal_proc_n_log_info2_u {
	struct {
		u64	la		:16,	/* Logical address */
			reserved	:48;	/* Reserved */
	} ppli2_bits;
	u64	ppli2_data;
} pal_proc_n_log_info2_t;

typedef struct pal_logical_to_physical_s
{
	pal_log_overview_t overview;
	pal_proc_n_log_info1_t ppli1;
	pal_proc_n_log_info2_t ppli2;
} pal_logical_to_physical_t;

#define overview_num_log	overview.overview_bits.num_log
#define overview_tpc		overview.overview_bits.tpc
#define overview_cpp		overview.overview_bits.cpp
#define overview_ppid		overview.overview_bits.ppid
#define log1_tid		ppli1.ppli1_bits.tid
#define log1_cid		ppli1.ppli1_bits.cid
#define log2_la			ppli2.ppli2_bits.la

/* Get information on logical to physical processor mappings. */
static inline s64
ia64_pal_logical_to_phys(u64 proc_number, pal_logical_to_physical_t *mapping)
{
	struct ia64_pal_retval iprv;

	PAL_CALL(iprv, PAL_LOGICAL_TO_PHYSICAL, proc_number, 0, 0);

	if (iprv.status == PAL_STATUS_SUCCESS)
	{
		if (proc_number == 0)
			mapping->overview.overview_data = iprv.v0;
		mapping->ppli1.ppli1_data = iprv.v1;
		mapping->ppli2.ppli2_data = iprv.v2;
	}

	return iprv.status;
}
#endif /* __ASSEMBLY__ */

#endif /* _ASM_IA64_PAL_H */
+7 −0
Original line number Diff line number Diff line
@@ -148,6 +148,13 @@ struct cpuinfo_ia64 {
#ifdef CONFIG_SMP
	__u64 loops_per_jiffy;
	int cpu;
	__u32 socket_id;	/* physical processor socket id */
	__u16 core_id;		/* core id */
	__u16 thread_id;	/* thread id */
	__u16 num_log;		/* Total number of logical processors on
				 * this socket that were successfully booted */
	__u8  cores_per_socket;	/* Cores per processor socket */
	__u8  threads_per_core;	/* Threads per core */
#endif

	/* CPUID-derived information: */
+12 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ extern spinlock_t sal_lock;
#define SAL_PCI_CONFIG_READ		0x01000010
#define SAL_PCI_CONFIG_WRITE		0x01000011
#define SAL_FREQ_BASE			0x01000012
#define SAL_PHYSICAL_ID_INFO		0x01000013

#define SAL_UPDATE_PAL			0x01000020

@@ -815,6 +816,17 @@ ia64_sal_update_pal (u64 param_buf, u64 scratch_buf, u64 scratch_buf_size,
	return isrv.status;
}

/* Get physical processor die mapping in the platform. */
static inline s64
ia64_sal_physical_id_info(u16 *splid)
{
	struct ia64_sal_retval isrv;
	SAL_CALL(isrv, SAL_PHYSICAL_ID_INFO, 0, 0, 0, 0, 0, 0, 0);
	if (splid)
		*splid = isrv.v0;
	return isrv.status;
}

extern unsigned long sal_platform_features;

extern int (*salinfo_platform_oemdata)(const u8 *, u8 **, u64 *);
Loading