Commit 09a0a191 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ppc64: SMT processor support and logical cpu numbering, from Dave Engebretsen

From: Anton Blanchard <anton@samba.org>

And SMT processor support & move back to a logical cpu numbering
in support of DLPAR work.
parent b015de48
......@@ -85,10 +85,10 @@ unsigned int openpic_vec_spurious;
*/
#ifdef CONFIG_SMP
#define THIS_CPU Processor[cpu]
#define DECL_THIS_CPU int cpu = smp_processor_id()
#define DECL_THIS_CPU int cpu = hard_smp_processor_id()
#define CHECK_THIS_CPU check_arg_cpu(cpu)
#else
#define THIS_CPU Processor[smp_processor_id()]
#define THIS_CPU Processor[hard_smp_processor_id()]
#define DECL_THIS_CPU
#define CHECK_THIS_CPU
#endif /* CONFIG_SMP */
......@@ -355,7 +355,7 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
/* SIOint (8259 cascade) is special */
if (offset) {
openpic_initirq(0, 8, offset, 1, 1);
openpic_mapirq(0, 1 << boot_cpuid);
openpic_mapirq(0, 1 << get_hard_smp_processor_id(boot_cpuid));
}
/* Init all external sources */
......@@ -373,7 +373,7 @@ void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
/* Enabled, Priority 8 or 9 */
openpic_initirq(i, pri, i+offset, !sense, sense);
/* Processor 0 */
openpic_mapirq(i, 1 << boot_cpuid);
openpic_mapirq(i, 1 << get_hard_smp_processor_id(boot_cpuid));
}
/* Init descriptors */
......@@ -514,10 +514,23 @@ static void openpic_set_spurious(u_int vec)
vec);
}
/*
* Convert a cpu mask from logical to physical cpu numbers.
*/
static inline u32 physmask(u32 cpumask)
{
int i;
u32 mask = 0;
for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
return mask;
}
void openpic_init_processor(u_int cpumask)
{
openpic_write(&OpenPIC->Global.Processor_Initialization,
cpumask & cpus_coerce(cpu_online_map));
physmask(cpumask & cpus_coerce(cpu_online_map)));
}
#ifdef CONFIG_SMP
......@@ -551,7 +564,7 @@ void openpic_cause_IPI(u_int ipi, u_int cpumask)
CHECK_THIS_CPU;
check_arg_ipi(ipi);
openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
cpumask & cpus_coerce(cpu_online_map));
physmask(cpumask & cpus_coerce(cpu_online_map)));
}
void openpic_request_IPIs(void)
......@@ -592,7 +605,7 @@ void __devinit do_openpic_setup_cpu(void)
{
#ifdef CONFIG_IRQ_ALL_CPUS
int i;
u32 msk = 1 << smp_processor_id();
u32 msk = 1 << hard_smp_processor_id();
#endif
spin_lock(&openpic_setup_lock);
......@@ -637,7 +650,7 @@ static void __init openpic_maptimer(u_int timer, u_int cpumask)
{
check_arg_timer(timer);
openpic_write(&OpenPIC->Global.Timer[timer].Destination,
cpumask & cpus_coerce(cpu_online_map));
physmask(cpumask & cpus_coerce(cpu_online_map)));
}
......@@ -763,7 +776,7 @@ static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask)
cpumask_t tmp;
cpus_and(tmp, cpumask, cpu_online_map);
openpic_mapirq(irq_nr - open_pic_irq_offset, cpus_coerce(tmp));
openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpus_coerce(tmp)));
}
#ifdef CONFIG_SMP
......
......@@ -149,6 +149,7 @@ char *bootpath = 0;
char *bootdevice = 0;
int boot_cpuid = 0;
#define MAX_CPU_THREADS 2
struct device_node *allnodes = 0;
/* use when traversing tree through the allnext, child, sibling,
......@@ -898,16 +899,21 @@ static void
prom_hold_cpus(unsigned long mem)
{
unsigned long i;
unsigned int cpuid;
unsigned int reg;
phandle node;
unsigned long offset = reloc_offset();
char type[64], *path;
int cpuid = 0;
unsigned int interrupt_server[MAX_CPU_THREADS];
unsigned int cpu_threads, hw_cpu_num;
int propsize;
extern void __secondary_hold(void);
extern unsigned long __secondary_hold_spinloop;
extern unsigned long __secondary_hold_acknowledge;
unsigned long *spinloop = __v2a(&__secondary_hold_spinloop);
unsigned long *acknowledge = __v2a(&__secondary_hold_acknowledge);
unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
struct naca_struct *_naca = RELOC(naca);
struct systemcfg *_systemcfg = RELOC(systemcfg);
struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
struct prom_t *_prom = PTRRELOC(&prom);
......@@ -960,13 +966,9 @@ prom_hold_cpus(unsigned long mem)
if (strcmp(type, RELOC("okay")) != 0)
continue;
cpuid = -1;
reg = -1;
call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
&cpuid, sizeof(cpuid));
/* Only need to start secondary procs, not ourself. */
if ( cpuid == _prom->cpu )
continue;
&reg, sizeof(reg));
path = (char *) mem;
memset(path, 0, 256);
......@@ -976,12 +978,14 @@ prom_hold_cpus(unsigned long mem)
#ifdef DEBUG_PROM
prom_print_nl();
prom_print(RELOC("cpu hw idx = 0x"));
prom_print(RELOC("cpuid = 0x"));
prom_print_hex(cpuid);
prom_print_nl();
prom_print(RELOC("cpu hw idx = 0x"));
prom_print_hex(reg);
prom_print_nl();
#endif
prom_print(RELOC("starting cpu "));
prom_print(path);
_xPaca[cpuid].xHwProcNum = reg;
/* Init the acknowledge var which will be reset by
* the secondary cpu when it awakens from its OF
......@@ -989,45 +993,80 @@ prom_hold_cpus(unsigned long mem)
*/
*acknowledge = (unsigned long)-1;
#ifdef DEBUG_PROM
prom_print(RELOC(" 3) spinloop = 0x"));
prom_print_hex(spinloop);
prom_print_nl();
prom_print(RELOC(" 3) *spinloop = 0x"));
prom_print_hex(*spinloop);
prom_print_nl();
prom_print(RELOC(" 3) acknowledge = 0x"));
prom_print_hex(acknowledge);
prom_print_nl();
prom_print(RELOC(" 3) *acknowledge = 0x"));
prom_print_hex(*acknowledge);
prom_print_nl();
prom_print(RELOC(" 3) secondary_hold = 0x"));
prom_print_hex(secondary_hold);
propsize = call_prom(RELOC("getprop"), 4, 1, node,
RELOC("ibm,ppc-interrupt-server#s"),
&interrupt_server,
sizeof(interrupt_server));
if (propsize < 0) {
/* no property. old hardware has no SMT */
cpu_threads = 1;
interrupt_server[0] = reg; /* fake it with phys id */
} else {
/* We have a threaded processor */
cpu_threads = propsize / sizeof(u32);
if (cpu_threads > MAX_CPU_THREADS) {
prom_print(RELOC("SMT: too many threads!\nSMT: found "));
prom_print_hex(cpu_threads);
prom_print(RELOC(", max is "));
prom_print_hex(MAX_CPU_THREADS);
prom_print_nl();
#endif
call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, cpuid);
cpu_threads = 1; /* ToDo: panic? */
}
}
hw_cpu_num = interrupt_server[0];
if (hw_cpu_num != _prom->cpu) {
/* Primary Thread of non-boot cpu */
prom_print_hex(cpuid);
prom_print(RELOC(" : starting cpu "));
prom_print(path);
prom_print(RELOC("..."));
call_prom(RELOC("start-cpu"), 3, 0, node,
secondary_hold, cpuid);
for ( i = 0 ; (i < 100000000) &&
(*acknowledge == ((unsigned long)-1)); i++ ) ;
#ifdef DEBUG_PROM
{
unsigned long *p = 0x0;
prom_print(RELOC(" 4) 0x0 = 0x"));
prom_print_hex(*p);
prom_print_nl();
}
#endif
if (*acknowledge == cpuid) {
prom_print(RELOC("ok\n"));
/* Set the number of active processors. */
_systemcfg->processorCount++;
_xPaca[cpuid].active = 1;
cpu_set(cpuid, RELOC(cpu_available_map));
cpu_set(cpuid, RELOC(cpu_possible_map));
cpu_set(cpuid, RELOC(cpu_present_at_boot));
} else {
prom_print(RELOC("failed: "));
prom_print_hex(*acknowledge);
prom_print_nl();
/* prom_panic(RELOC("cpu failed to start")); */
}
} else {
prom_print_hex(cpuid);
prom_print(RELOC(" : booting cpu "));
prom_print(path);
prom_print_nl();
cpu_set(cpuid, RELOC(cpu_available_map));
cpu_set(cpuid, RELOC(cpu_possible_map));
cpu_set(cpuid, RELOC(cpu_online_map));
cpu_set(cpuid, RELOC(cpu_present_at_boot));
}
/* Init paca for secondary threads. They start later. */
for (i=1; i < cpu_threads; i++) {
cpuid++;
_xPaca[cpuid].xHwProcNum = interrupt_server[i];
prom_print_hex(interrupt_server[i]);
prom_print(RELOC(" : preparing thread ... "));
if (_naca->smt_state) {
cpu_set(cpuid, RELOC(cpu_available_map));
cpu_set(cpuid, RELOC(cpu_present_at_boot));
prom_print(RELOC("available"));
} else {
prom_print(RELOC("not available"));
}
prom_print_nl();
}
cpuid++;
}
#ifdef CONFIG_HMT
/* Only enable HMT on processors that provide support. */
......@@ -1037,10 +1076,10 @@ prom_hold_cpus(unsigned long mem)
prom_print(RELOC(" starting secondary threads\n"));
for (i = 0; i < NR_CPUS; i += 2) {
if (!_xPaca[i].active)
if (!cpu_online(i))
continue;
if (i == boot_cpuid) {
if (i == 0) {
unsigned long pir = _get_PIR();
if (__is_processor(PV_PULSAR)) {
RELOC(hmt_thread_data)[i].pir =
......@@ -1050,7 +1089,8 @@ prom_hold_cpus(unsigned long mem)
pir & 0x3ff;
}
}
_xPaca[i+1].active = 1;
/* cpu_set(i+1, cpu_online_map); */
cpu_set(i+1, RELOC(cpu_possible_map));
}
_systemcfg->processorCount *= 2;
} else {
......@@ -1063,6 +1103,105 @@ prom_hold_cpus(unsigned long mem)
#endif
}
static void
smt_setup(void)
{
char *p, *q;
char my_smt_enabled = SMT_DYNAMIC;
unsigned long my_smt_snooze_delay;
ihandle prom_options = NULL;
char option[9];
unsigned long offset = reloc_offset();
struct naca_struct *_naca = RELOC(naca);
char found = 0;
if (strstr(RELOC(cmd_line), RELOC("smt-enabled="))) {
for (q = RELOC(cmd_line); (p = strstr(q, RELOC("smt-enabled="))) != 0; ) {
q = p + 12;
if (p > RELOC(cmd_line) && p[-1] != ' ')
continue;
found = 1;
if (q[0] == 'o' && q[1] == 'f' &&
q[2] == 'f' && (q[3] == ' ' || q[3] == '\0')) {
my_smt_enabled = SMT_OFF;
} else if (q[0]=='o' && q[1] == 'n' &&
(q[2] == ' ' || q[2] == '\0')) {
my_smt_enabled = SMT_ON;
} else {
my_smt_enabled = SMT_DYNAMIC;
}
}
}
if (!found) {
prom_options = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/options"));
if (prom_options != (ihandle) -1) {
call_prom(RELOC("getprop"),
4, 1, prom_options,
RELOC("ibm,smt-enabled"),
option,
sizeof(option));
if (option[0] != 0) {
found = 1;
if (!strcmp(option, "off"))
my_smt_enabled = SMT_OFF;
else if (!strcmp(option, "on"))
my_smt_enabled = SMT_ON;
else
my_smt_enabled = SMT_DYNAMIC;
}
}
}
if (!found )
my_smt_enabled = SMT_DYNAMIC; /* default to on */
found = 0;
if (my_smt_enabled) {
if (strstr(RELOC(cmd_line), RELOC("smt-snooze-delay="))) {
for (q = RELOC(cmd_line); (p = strstr(q, RELOC("smt-snooze-delay="))) != 0; ) {
q = p + 17;
if (p > RELOC(cmd_line) && p[-1] != ' ')
continue;
found = 1;
/* Don't use simple_strtoul() because _ctype & others aren't RELOC'd */
my_smt_snooze_delay = 0;
while (*q >= '0' && *q <= '9') {
my_smt_snooze_delay = my_smt_snooze_delay * 10 + *q - '0';
q++;
}
}
}
if (!found) {
prom_options = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/options"));
if (prom_options != (ihandle) -1) {
call_prom(RELOC("getprop"),
4, 1, prom_options,
RELOC("ibm,smt-snooze-delay"),
option,
sizeof(option));
if (option[0] != 0) {
found = 1;
/* Don't use simple_strtoul() because _ctype & others aren't RELOC'd */
my_smt_snooze_delay = 0;
q = option;
while (*q >= '0' && *q <= '9') {
my_smt_snooze_delay = my_smt_snooze_delay * 10 + *q - '0';
q++;
}
}
}
}
if (!found) {
my_smt_snooze_delay = 30000; /* default value */
}
} else {
my_smt_snooze_delay = 0; /* default value */
}
_naca->smt_snooze_delay = my_smt_snooze_delay;
_naca->smt_state = my_smt_enabled;
}
/*
* We enter here early on, when the Open Firmware prom is still
......@@ -1145,11 +1284,9 @@ prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
cpu_pkg, RELOC("reg"),
&getprop_rval, sizeof(getprop_rval));
_prom->cpu = (int)(unsigned long)getprop_rval;
_xPaca[_prom->cpu].active = 1;
#ifdef CONFIG_SMP
cpu_set(_prom->cpu, RELOC(cpu_online_map));
#endif
RELOC(boot_cpuid) = _prom->cpu;
_xPaca[0].xHwProcNum = _prom->cpu;
RELOC(boot_cpuid) = 0;
#ifdef DEBUG_PROM
prom_print(RELOC("Booting CPU hw index = 0x"));
......@@ -1183,11 +1320,12 @@ prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
/* Initialize some system info into the Naca early... */
mem = prom_initialize_naca(mem);
smt_setup();
/* If we are on an SMP machine, then we *MUST* do the
* following, regardless of whether we have an SMP
* kernel or not.
*/
if (_systemcfg->processorCount > 1)
prom_hold_cpus(mem);
#ifdef DEBUG_PROM
......
......@@ -58,6 +58,8 @@ extern void iSeries_init_early( void );
extern void pSeries_init_early( void );
extern void pSeriesLP_init_early(void);
extern void mm_init_ppc64( void );
extern void pseries_secondary_smp_init(unsigned long);
extern int idle_setup(void);
extern void vpa_init(int cpu);
unsigned long decr_overclock = 1;
......@@ -144,6 +146,8 @@ void __init disable_early_printk(void)
void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
unsigned int ret, i;
#ifdef CONFIG_XMON_DEFAULT
debugger = xmon;
debugger_bpt = xmon_bpt;
......@@ -187,6 +191,21 @@ void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
if (systemcfg->platform & PLATFORM_PSERIES) {
early_console_initialized = 1;
register_console(&udbg_console);
finish_device_tree();
chrp_init(r3, r4, r5, r6, r7);
/* Start secondary threads on SMT systems */
for (i = 0; i < NR_CPUS; i++) {
if(cpu_available(i) && !cpu_possible(i)) {
printk("%16.16x : starting thread\n", i);
rtas_call(rtas_token("start-cpu"), 3, 1,
(void *)&ret,
get_hard_smp_processor_id(i),
*((unsigned long *)pseries_secondary_smp_init), i);
cpu_set(i, cpu_possible_map);
systemcfg->processorCount++;
}
}
}
printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
......@@ -205,11 +224,6 @@ void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
printk("htab_data.num_ptegs = 0x%lx\n", htab_data.htab_num_ptegs);
printk("-----------------------------------------------------\n");
if (systemcfg->platform & PLATFORM_PSERIES) {
finish_device_tree();
chrp_init(r3, r4, r5, r6, r7);
}
mm_init_ppc64();
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
......
......@@ -53,8 +53,11 @@
int smp_threads_ready;
unsigned long cache_decay_ticks;
/* initialised so it doesn't end up in bss */
/* Initialised so it doesn't end up in bss */
cpumask_t cpu_possible_map = CPU_MASK_NONE;
cpumask_t cpu_online_map = CPU_MASK_NONE;
cpumask_t cpu_available_map = CPU_MASK_NONE;
cpumask_t cpu_present_at_boot = CPU_MASK_NONE;
EXPORT_SYMBOL(cpu_online_map);
......@@ -67,6 +70,8 @@ extern unsigned char stab_array[];
extern int cpu_idle(void *unused);
void smp_call_function_interrupt(void);
void smp_message_pass(int target, int msg, unsigned long data, int wait);
extern long register_vpa(unsigned long flags, unsigned long proc,
unsigned long vpa);
#define smp_message_pass(t,m,d,w) smp_ops->message_pass((t),(m),(d),(w))
......
......@@ -202,7 +202,7 @@ static void pSeriesLP_qirr_info(int n_cpu , u8 value)
{
unsigned long lpar_rc;
lpar_rc = plpar_ipi(n_cpu, value);
lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value);
if (lpar_rc != H_Success)
panic("bad return code qirr - rc = %lx\n", lpar_rc);
}
......@@ -441,7 +441,7 @@ void xics_init_IRQ(void)
np;
np = of_find_node_by_type(np, "cpu")) {
ireg = (uint *)get_property(np, "reg", &ilen);
if (ireg && ireg[0] == smp_processor_id()) {
if (ireg && ireg[0] == hard_smp_processor_id()) {
ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
i = ilen / sizeof(int);
if (ireg && i > 0) {
......@@ -478,8 +478,8 @@ void xics_init_IRQ(void)
for (i = 0; i < NR_CPUS; ++i) {
if (!cpu_possible(i))
continue;
xics_per_cpu[i] = __ioremap((ulong)inodes[i].addr,
(ulong)inodes[i].size,
xics_per_cpu[i] = __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr,
(ulong)inodes[get_hard_smp_processor_id(i)].size,
_PAGE_NO_CACHE);
}
#else
......@@ -570,7 +570,7 @@ void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
cpus_and(tmp, cpu_online_map, cpumask);
if (cpus_empty(tmp))
goto out;
newmask = first_cpu(cpumask);
newmask = get_hard_smp_processor_id(first_cpu(cpumask));
}
status = rtas_call(ibm_set_xive, 3, 1, NULL,
......
......@@ -61,7 +61,7 @@ struct paca_struct {
struct ItLpRegSave *xLpRegSavePtr; /* Pointer to LpRegSave for PLIC 0x08 */
u64 xCurrent; /* Pointer to current 0x10 */
u16 xPacaIndex; /* Logical processor number 0x18 */
u16 active; /* Is this cpu active? 0x1a */
u16 xHwProcNum; /* Physical processor number 0x1A */
u32 default_decr; /* Default decrementer value 0x1c */
u64 unused1;
u64 xKsave; /* Saved Kernel stack addr or zero 0x28 */
......
......@@ -371,6 +371,7 @@
#define PV_ICESTAR 0x0036
#define PV_SSTAR 0x0037
#define PV_POWER4p 0x0038
#define PV_POWER5 0x003A
#define PV_630 0x0040
#define PV_630p 0x0041
......
......@@ -34,9 +34,28 @@ extern void smp_send_xmon_break(int cpu);
struct pt_regs;
extern void smp_message_recv(int, struct pt_regs *);
#define cpu_possible(cpu) paca[cpu].active
#define smp_processor_id() (get_paca()->xPacaIndex)
#define hard_smp_processor_id() (get_paca()->xHwProcNum)
/*
* Retrieve the state of a CPU:
* online: CPU is in a normal run state
* possible: CPU is a candidate to be made online
* available: CPU is candidate for the 'possible' pool
* Used to get SMT threads started at boot time.
* present_at_boot: CPU was available at boot time. Used in DLPAR
* code to handle special cases for processor start up.
*/
extern cpumask_t cpu_present_at_boot;
extern cpumask_t cpu_online_map;
extern cpumask_t cpu_possible_map;
extern cpumask_t cpu_available_map;
#define cpu_present_at_boot(cpu) cpu_isset(cpu, cpu_present_at_boot)
#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
#define cpu_possible(cpu) cpu_isset(cpu, cpu_possible_map)
#define cpu_available(cpu) cpu_isset(cpu, cpu_available_map)
/* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
*
......@@ -52,5 +71,7 @@ void smp_init_pSeries(void);
#endif /* __ASSEMBLY__ */
#endif /* !(CONFIG_SMP) */
#define get_hard_smp_processor_id(CPU) (paca[(CPU)].xHwProcNum)
#define set_hard_smp_processor_id(CPU, VAL) do { (paca[(CPU)].xHwProcNum = VAL); } while (0)
#endif /* !(_PPC64_SMP_H) */
#endif /* __KERNEL__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment