*/
#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 */
/* 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 */
/* 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 */
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
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)
{
#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);
{
check_arg_timer(timer);
openpic_write(&OpenPIC->Global.Timer[timer].Destination,
- cpumask & cpus_coerce(cpu_online_map));
+ physmask(cpumask & cpus_coerce(cpu_online_map)));
}
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
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,
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);
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;
+ ®, sizeof(reg));
path = (char *) mem;
memset(path, 0, 256);
#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
*/
*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. */
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 =
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 {
#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
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"));
/* 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
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;
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;
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);
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) {