📄 prom.c
字号:
/* Carve out storage for the TCE table. */ base = lmb_alloc(minsize, align); if ( !base ) { prom_print(RELOC("ERROR, cannot find space for TCE table.\n")); prom_exit(); } vbase = absolute_to_virt(base); /* Save away the TCE table attributes for later use. */ prom_tce_table[table].node = node; prom_tce_table[table].base = vbase; prom_tce_table[table].size = minsize;#ifdef DEBUG_PROM prom_print(RELOC("TCE table: 0x")); prom_print_hex(table); prom_print_nl(); prom_print(RELOC("\tnode = 0x")); prom_print_hex(node); prom_print_nl(); prom_print(RELOC("\tbase = 0x")); prom_print_hex(vbase); prom_print_nl(); prom_print(RELOC("\tsize = 0x")); prom_print_hex(minsize); prom_print_nl();#endif /* Initialize the table to have a one-to-one mapping * over the allocated size. */ tce_entryp = (unsigned long *)base; for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { tce_entry = (i << PAGE_SHIFT); tce_entry |= 0x3; *tce_entryp = tce_entry; } /* Call OF to setup the TCE hardware */ if (call_prom(RELOC("package-to-path"), 3, 1, node, path, 255) <= 0) { prom_print(RELOC("package-to-path failed\n")); } else { prom_print(RELOC("opened ")); prom_print(path); prom_print_nl(); } phb_node = (ihandle)call_prom(RELOC("open"), 1, 1, path); if ( (long)phb_node <= 0) { prom_print(RELOC("open failed\n")); } else { prom_print(RELOC("open success\n")); } call_prom(RELOC("call-method"), 6, 0, RELOC("set-64-bit-addressing"), phb_node, -1, minsize, base & 0xffffffff, (base >> 32) & 0xffffffff); call_prom(RELOC("close"), 1, 0, phb_node); table++; } /* Flag the first invalid entry */ prom_tce_table[table].node = 0;#ifdef DEBUG_PROM prom_print(RELOC("ending prom_initialize_tce_table\n"));#endif}/* * With CHRP SMP we need to use the OF to start the other * processors so we can't wait until smp_boot_cpus (the OF is * trashed by then) so we have to put the processors into * a holding pattern controlled by the kernel (not OF) before * we destroy the OF. * * This uses a chunk of low memory, puts some holding pattern * code there and sends the other processors off to there until * smp_boot_cpus tells them to do something. The holding pattern * checks that address until its cpu # is there, when it is that * cpu jumps to __secondary_start(). smp_boot_cpus() takes care * of setting those values. * * We also use physical address 0x4 here to tell when a cpu * is in its holding pattern code. * * Fixup comment... DRENG / PPPBBB - Peter * * -- Cort */static voidprom_hold_cpus(unsigned long mem){ unsigned long i; 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); /* Initially, we must have one active CPU. */ _systemcfg->processorCount = 1;#ifdef DEBUG_PROM prom_print(RELOC("prom_hold_cpus: start...\n")); prom_print(RELOC(" 1) spinloop = 0x")); prom_print_hex(spinloop); prom_print_nl(); prom_print(RELOC(" 1) *spinloop = 0x")); prom_print_hex(*spinloop); prom_print_nl(); prom_print(RELOC(" 1) acknowledge = 0x")); prom_print_hex(acknowledge); prom_print_nl(); prom_print(RELOC(" 1) *acknowledge = 0x")); prom_print_hex(*acknowledge); prom_print_nl(); prom_print(RELOC(" 1) secondary_hold = 0x")); prom_print_hex(secondary_hold); prom_print_nl();#endif /* Set the common spinloop variable, so all of the secondary cpus * will block when they are awakened from their OF spinloop. * This must occur for both SMP and non SMP kernels, since OF will * be trashed when we move the kernel. */ *spinloop = 0;#ifdef CONFIG_HMT for (i=0; i < NR_CPUS; i++) { RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; }#endif /* look for cpus */ for (node = 0; prom_next_node(&node); ) { type[0] = 0; call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), type, sizeof(type)); if (strcmp(type, RELOC("cpu")) != 0) continue; /* Skip non-configured cpus. */ call_prom(RELOC("getprop"), 4, 1, node, RELOC("status"), type, sizeof(type)); if (strcmp(type, RELOC("okay")) != 0) continue; reg = -1; call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), ®, sizeof(reg)); path = (char *) mem; memset(path, 0, 256); if ((long) call_prom(RELOC("package-to-path"), 3, 1, node, path, 255) < 0) continue;#ifdef DEBUG_PROM prom_print_nl(); 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 _xPaca[cpuid].xHwProcNum = reg; /* Init the acknowledge var which will be reset by * the secondary cpu when it awakens from its OF * spinloop. */ *acknowledge = (unsigned long)-1; 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? */ } } 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_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. */ if (__is_processor(PV_PULSAR) || __is_processor(PV_ICESTAR) || __is_processor(PV_SSTAR)) { prom_print(RELOC(" starting secondary threads\n")); for (i=0; i < _systemcfg->processorCount ;i++) { unsigned long threadid = _systemcfg->processorCount*2-1-i; if (i == 0) { unsigned long pir = _get_PIR(); if (__is_processor(PV_PULSAR)) { RELOC(hmt_thread_data)[i].pir = pir & 0x1f; } else { RELOC(hmt_thread_data)[i].pir = pir & 0x3ff; } } RELOC(hmt_thread_data)[i].threadid = threadid;#ifdef DEBUG_PROM prom_print(RELOC(" cpuid 0x")); prom_print_hex(i); prom_print(RELOC(" maps to threadid 0x")); prom_print_hex(threadid); prom_print_nl(); prom_print(RELOC(" pir 0x")); prom_print_hex(RELOC(hmt_thread_data)[i].pir); prom_print_nl();#endif _xPaca[threadid].xHwProcNum = _xPaca[i].xHwProcNum+1; } _systemcfg->processorCount *= 2; } else { prom_print(RELOC("Processor is not HMT capable\n")); }#endif #ifdef DEBUG_PROM prom_print(RELOC("prom_hold_cpus: end...\n"));#endif}static voidsmt_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_PPCDBGextern char *trace_names[]; /* defined in udbg.c -- need a better interface */void parse_ppcdbg_optionlist(const char *cmd, const char *cmdend){ unsigned long offset = reloc_offset(); char **_trace_names = PTRRELOC(&trace_names[0]); const char *all = RELOC("all"); struct naca_struct *_naca = RELOC(naca); const char *p, *pend; int onoff, i, cmdidx; unsigned long mask; char cmdbuf[30]; for (p = cmd, pend = strchr(p, ','); p < cmdend; pend = strchr(p, ',')) { if (pend == NULL || pend > cmdend) pend = cmdend; onoff = 1; /* default */ if (*p == '+' || *p == '-') { /* explicit on or off */ onoff = (*p == '+'); p++; } /* parse out p..pend here */ if (pend - p < sizeof(cmdbuf)) { strncpy(cmdbuf, p, pend - p); cmdbuf[pend - p] = '\0'; for (cmdidx = -1, i = 0; i < PPCDBG_NUM_FLAGS; i++) { if (_trace_names[i] && (strcmp(PTRRELOC(_trace_names[i]), cmdbuf) == 0)) { cmdidx = i; break; } } mask = 0; if (cmdidx >= 0) { mask = (1 << cmdidx); } else if (strcmp(cmdbuf, all) == 0) { mask = PPCDBG_ALL; } else { prom_print(RELOC("ppcdbg: unknown debug: ")); prom_print(cmdbuf); prom_print_nl(); } if (mask) { if (onoff) _naca->debug_switch |= mask; else _naca->debug_switch &= ~mask; } } p = pend+1; }}/* * Parse ppcdbg= cmdline option. * * Option names are listed in <asm/ppcdebug.h> in the trace_names * table. Multiple names may be listed separated by commas (no whitespace),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -