patch-2.4.25 linux-2.4.25/arch/ppc64/kernel/prom.c
Next file: linux-2.4.25/arch/ppc64/kernel/ptrace.c
Previous file: linux-2.4.25/arch/ppc64/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 428
- Date:
2004-02-18 05:36:30.000000000 -0800
- Orig file:
linux-2.4.24/arch/ppc64/kernel/prom.c
- Orig date:
2003-08-25 04:44:40.000000000 -0700
diff -urN linux-2.4.24/arch/ppc64/kernel/prom.c linux-2.4.25/arch/ppc64/kernel/prom.c
@@ -168,7 +168,6 @@
extern struct rtas_t rtas;
extern unsigned long klimit;
-extern unsigned long embedded_sysmap_end;
extern struct lmb lmb;
#ifdef CONFIG_MSCHUNKS
extern struct msChunks msChunks;
@@ -180,12 +179,9 @@
char *bootpath = 0;
char *bootdevice = 0;
-struct device_node *allnodes = 0;
+#define MAX_CPU_THREADS 2
-#define UNDEFINED_IRQ 0xffff
-unsigned short real_irq_to_virt_map[NR_HW_IRQS];
-unsigned short virt_irq_to_real_map[NR_IRQS];
-int last_virt_irq = 2; /* index of last virt_irq. Skip through IPI */
+struct device_node *allnodes = 0;
static unsigned long call_prom(const char *service, int nargs, int nret, ...);
static void prom_exit(void);
@@ -941,7 +937,7 @@
* By doing this, we avoid the pitfalls of trying to DMA to
* MMIO space and the DMA alias hole.
*/
- minsize = 4UL << 20;
+ minsize = 8UL << 20;
/* Align to the greater of the align or size */
align = (minalign < minsize) ? minsize : minalign;
@@ -1054,6 +1050,9 @@
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;
@@ -1117,18 +1116,12 @@
call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
®, sizeof(reg));
- /* Only need to start secondary procs, not ourself. */
- if ( reg == _prom->cpu )
- continue;
-
path = (char *) mem;
memset(path, 0, 256);
if ((long) call_prom(RELOC("package-to-path"), 3, 1,
node, path, 255) < 0)
continue;
- cpuid++;
-
#ifdef DEBUG_PROM
prom_print_nl();
prom_print(RELOC("cpuid = 0x"));
@@ -1140,56 +1133,80 @@
#endif
_xPaca[cpuid].xHwProcNum = reg;
- prom_print(RELOC("starting cpu "));
- prom_print(path);
-
/* Init the acknowledge var which will be reset by
* the secondary cpu when it awakens from its OF
* spinloop.
*/
*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);
- prom_print_nl();
- prom_print(RELOC(" 3) cpuid = 0x"));
- prom_print_hex(cpuid);
- prom_print_nl();
-#endif
- call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, cpuid);
- prom_print(RELOC("..."));
- 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();
+ 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();
+ cpu_threads = 1; /* ToDo: panic? */
+ }
}
-#endif
- if (*acknowledge == cpuid) {
- prom_print(RELOC("ok\n"));
- /* Set the number of active processors. */
- _systemcfg->processorCount++;
+
+ 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++ );
+
+ if (*acknowledge == cpuid) {
+ prom_print(RELOC("ok\n"));
+ /* Set the number of active processors. */
+ _systemcfg->processorCount++;
+ _xPaca[cpuid].active = 1;
+ _xPaca[cpuid].available = 1;
+ } else {
+ prom_print(RELOC("failed: "));
+ prom_print_hex(*acknowledge);
+ prom_print_nl();
+ /* prom_panic(RELOC("cpu failed to start")); */
+ }
} else {
- prom_print(RELOC("failed: "));
- prom_print_hex(*acknowledge);
+ prom_print_hex(cpuid);
+ prom_print(RELOC(" : booting cpu "));
+ prom_print(path);
prom_print_nl();
}
+
+ /* 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) {
+ _xPaca[cpuid].available = 1;
+ 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. */
@@ -1236,6 +1253,104 @@
#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;
+}
+
#ifdef CONFIG_PPCDBG
extern char *trace_names[]; /* defined in udbg.c -- need a better interface */
@@ -1359,7 +1474,6 @@
char *p, *d;
unsigned long phys;
u32 getprop_rval;
- struct naca_struct *_naca = RELOC(naca);
struct systemcfg *_systemcfg = RELOC(systemcfg);
struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
struct prom_t *_prom = PTRRELOC(&prom);
@@ -1367,9 +1481,6 @@
/* Default machine type. */
_systemcfg->platform = PLATFORM_PSERIES;
- /* Reset klimit to take into account the embedded system map */
- if (RELOC(embedded_sysmap_end))
- RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end)));
/* Get a handle to the prom entry point before anything else */
_prom->entry = pp;
@@ -1532,12 +1643,13 @@
/* 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);
+ prom_hold_cpus(mem);
#ifdef DEBUG_PROM
prom_print(RELOC("copying OF device tree...\n"));
@@ -1697,46 +1809,6 @@
return DOUBLEWORD_ALIGN(mem);
}
-void
-virt_irq_init(void)
-{
- int i;
- for (i = 0; i < NR_IRQS; i++)
- virt_irq_to_real_map[i] = UNDEFINED_IRQ;
- for (i = 0; i < NR_HW_IRQS; i++)
- real_irq_to_virt_map[i] = UNDEFINED_IRQ;
-}
-
-/* Create a mapping for a real_irq if it doesn't already exist.
- * Return the virtual irq as a convenience.
- */
-unsigned long
-virt_irq_create_mapping(unsigned long real_irq)
-{
- unsigned long virq;
- if (naca->interrupt_controller == IC_OPEN_PIC)
- return real_irq; /* no mapping for openpic (for now) */
- virq = real_irq_to_virt(real_irq);
- if (virq == UNDEFINED_IRQ) {
- /* Assign a virtual IRQ number */
- if (real_irq < NR_IRQS && virt_irq_to_real(real_irq) == UNDEFINED_IRQ) {
- /* A 1-1 mapping will work. */
- virq = real_irq;
- } else {
- while (last_virt_irq < NR_IRQS &&
- virt_irq_to_real(++last_virt_irq) != UNDEFINED_IRQ)
- /* skip irq's in use */;
- if (last_virt_irq >= NR_IRQS)
- panic("Too many IRQs are required on this system. NR_IRQS=%d\n", NR_IRQS);
- virq = last_virt_irq;
- }
- virt_irq_to_real_map[virq] = real_irq;
- real_irq_to_virt_map[real_irq] = virq;
- }
- return virq;
-}
-
-
static int __init
prom_next_node(phandle *nodep)
{
@@ -1833,6 +1905,23 @@
*prev_propp = PTRUNRELOC(pp);
prev_propp = &pp->next;
}
+
+ /* Add a "linux_phandle" value */
+ if (np->node != NULL) {
+ u32 ibm_phandle = 0;
+ int len;
+
+ /* First see if "ibm,phandle" exists and use its value */
+ len = (int) call_prom(RELOC("getprop"), 4, 1, node,
+ RELOC("ibm,phandle"),
+ &ibm_phandle, sizeof(ibm_phandle));
+ if (len < 0) {
+ np->linux_phandle = np->node;
+ } else {
+ np->linux_phandle = ibm_phandle;
+ }
+ }
+
*prev_propp = 0;
/* get the node's full name */
@@ -1866,8 +1955,6 @@
{
unsigned long mem = klimit;
- virt_irq_init();
-
mem = finish_node(allnodes, mem, NULL, 0, 0);
dev_tree_size = mem - (unsigned long) allnodes;
@@ -1972,7 +2059,7 @@
np->n_intrs = ipsize / isize;
mem_start += np->n_intrs * sizeof(struct interrupt_info);
for (i = 0; i < np->n_intrs; ++i) {
- np->intrs[i].line = openpic_to_irq(virt_irq_create_mapping(*interrupts++));
+ np->intrs[i].line = irq_offset_up(*interrupts++);
np->intrs[i].sense = 1;
if (isize > 1)
np->intrs[i].sense = *interrupts++;
@@ -2334,7 +2421,7 @@
struct device_node *np;
for (np = allnodes; np != 0; np = np->allnext)
- if (np->node == ph)
+ if (np->linux_phandle == ph)
return np;
return NULL;
}
@@ -2425,7 +2512,7 @@
void __init
-abort()
+abort(void)
{
#ifdef CONFIG_XMON
xmon(NULL);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)