prom.c
字号:
pteg_count = (rnd_mem_size >> (12 + 1)); _naca->pftSize = __ilog2(pteg_count << 7); } if (_naca->pftSize == 0) { prom_printf("prom: failed to compute pftSize!\n"); PROM_BUG(); } /* Add an eye catcher and the systemcfg layout version number */ strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64")); _systemcfg->version.major = SYSTEMCFG_MAJOR; _systemcfg->version.minor = SYSTEMCFG_MINOR; _systemcfg->processor = _get_PVR(); prom_debug("systemcfg->processorCount = 0x%x\n", _systemcfg->processorCount); prom_debug("systemcfg->physicalMemorySize = 0x%x\n", _systemcfg->physicalMemorySize); prom_debug("naca->pftSize = 0x%x\n", _naca->pftSize); prom_debug("systemcfg->dCacheL1LineSize = 0x%x\n", _systemcfg->dCacheL1LineSize); prom_debug("systemcfg->iCacheL1LineSize = 0x%x\n", _systemcfg->iCacheL1LineSize); prom_debug("naca->serialPortAddr = 0x%x\n", _naca->serialPortAddr); prom_debug("naca->interrupt_controller = 0x%x\n", _naca->interrupt_controller); prom_debug("systemcfg->platform = 0x%x\n", _systemcfg->platform); prom_debug("prom_initialize_naca: end...\n");}static void __init early_cmdline_parse(void){ unsigned long offset = reloc_offset(); char *opt;#ifndef CONFIG_PMAC_DART struct systemcfg *_systemcfg = RELOC(systemcfg);#endif opt = strstr(RELOC(cmd_line), RELOC("iommu=")); if (opt) { prom_printf("opt is:%s\n", opt); opt += 6; while (*opt && *opt == ' ') opt++; if (!strncmp(opt, RELOC("off"), 3)) RELOC(ppc64_iommu_off) = 1; else if (!strncmp(opt, RELOC("force"), 5)) RELOC(iommu_force_on) = 1; }#ifndef CONFIG_PMAC_DART if (_systemcfg->platform == PLATFORM_POWERMAC) { RELOC(ppc64_iommu_off) = 1; prom_printf("DART disabled on PowerMac !\n"); }#endif}#ifdef DEBUG_PROMvoid prom_dump_lmb(void){ unsigned long i; unsigned long offset = reloc_offset(); struct lmb *_lmb = PTRRELOC(&lmb); prom_printf("\nprom_dump_lmb:\n"); prom_printf(" memory.cnt = 0x%x\n", _lmb->memory.cnt); prom_printf(" memory.size = 0x%x\n", _lmb->memory.size); for (i=0; i < _lmb->memory.cnt ;i++) { prom_printf(" memory.region[0x%x].base = 0x%x\n", i, _lmb->memory.region[i].base); prom_printf(" .physbase = 0x%x\n", _lmb->memory.region[i].physbase); prom_printf(" .size = 0x%x\n", _lmb->memory.region[i].size); } prom_printf("\n reserved.cnt = 0x%x\n", _lmb->reserved.cnt); prom_printf(" reserved.size = 0x%x\n", _lmb->reserved.size); for (i=0; i < _lmb->reserved.cnt ;i++) { prom_printf(" reserved.region[0x%x\n].base = 0x%x\n", i, _lmb->reserved.region[i].base); prom_printf(" .physbase = 0x%x\n", _lmb->reserved.region[i].physbase); prom_printf(" .size = 0x%x\n", _lmb->reserved.region[i].size); }}#endif /* DEBUG_PROM */static void __init prom_initialize_lmb(void){ phandle node; char type[64]; unsigned long i, offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); struct systemcfg *_systemcfg = RELOC(systemcfg); union lmb_reg_property reg; unsigned long lmb_base, lmb_size; unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8; lmb_init(); /* XXX Quick HACK. Proper fix is to drop those structures and properly use * #address-cells. PowerMac has #size-cell set to 1 and #address-cells to 2 */ if (_systemcfg->platform == PLATFORM_POWERMAC) bytes_per_reg = 12; for (node = 0; prom_next_node(&node); ) { type[0] = 0; prom_getprop(node, "device_type", type, sizeof(type)); if (strcmp(type, RELOC("memory"))) continue; num_regs = prom_getprop(node, "reg", ®, sizeof(reg)) / bytes_per_reg; for (i=0; i < num_regs ;i++) { if (_systemcfg->platform == PLATFORM_POWERMAC) { lmb_base = ((unsigned long)reg.addrPM[i].address_hi) << 32; lmb_base |= (unsigned long)reg.addrPM[i].address_lo; lmb_size = reg.addrPM[i].size; } else if (_prom->encode_phys_size == 32) { lmb_base = reg.addr32[i].address; lmb_size = reg.addr32[i].size; } else { lmb_base = reg.addr64[i].address; lmb_size = reg.addr64[i].size; } /* We limit memory to 2GB if the IOMMU is off */ if (RELOC(ppc64_iommu_off)) { if (lmb_base >= 0x80000000UL) continue; if ((lmb_base + lmb_size) > 0x80000000UL) lmb_size = 0x80000000UL - lmb_base; } if (lmb_add(lmb_base, lmb_size) < 0) prom_printf("Too many LMB's, discarding this one...\n"); } } lmb_analyze();#ifdef DEBUG_PROM prom_dump_lmb();#endif /* DEBUG_PROM */}static void __initprom_instantiate_rtas(void){ unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); struct rtas_t *_rtas = PTRRELOC(&rtas); struct systemcfg *_systemcfg = RELOC(systemcfg); ihandle prom_rtas; u32 getprop_rval; char hypertas_funcs[4]; prom_debug("prom_instantiate_rtas: start...\n"); prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); if (prom_rtas != (ihandle) -1) { unsigned long x; x = prom_getprop(prom_rtas, "ibm,hypertas-functions", hypertas_funcs, sizeof(hypertas_funcs)); if (x != PROM_ERROR) { prom_printf("Hypertas detected, assuming LPAR !\n"); _systemcfg->platform = PLATFORM_PSERIES_LPAR; } prom_getprop(prom_rtas, "rtas-size", &getprop_rval, sizeof(getprop_rval)); _rtas->size = getprop_rval; prom_printf("instantiating rtas"); if (_rtas->size != 0) { unsigned long rtas_region = RTAS_INSTANTIATE_MAX; /* Grab some space within the first RTAS_INSTANTIATE_MAX bytes * of physical memory (or within the RMO region) because RTAS * runs in 32-bit mode and relocate off. */ if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) { struct lmb *_lmb = PTRRELOC(&lmb); rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX); } _rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region); prom_printf(" at 0x%x", _rtas->base); prom_rtas = call_prom("open", 1, 1, ADDR("/rtas")); prom_printf("..."); if (call_prom("call-method", 3, 2, ADDR("instantiate-rtas"), prom_rtas, _rtas->base) != PROM_ERROR) { _rtas->entry = (long)_prom->args.rets[1]; } RELOC(rtas_rmo_buf) = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); } if (_rtas->entry <= 0) { prom_printf(" failed\n"); } else { prom_printf(" done\n"); } prom_debug("rtas->base = 0x%x\n", _rtas->base); prom_debug("rtas->entry = 0x%x\n", _rtas->entry); prom_debug("rtas->size = 0x%x\n", _rtas->size); } prom_debug("prom_instantiate_rtas: end...\n");}#ifdef CONFIG_PMAC_DARTstatic void __init prom_initialize_dart_table(void){ unsigned long offset = reloc_offset(); extern unsigned long dart_tablebase; extern unsigned long dart_tablesize; /* Only reserve DART space if machine has more than 2GB of RAM * or if requested with iommu=on on cmdline. */ if (lmb_end_of_DRAM() <= 0x80000000ull && !RELOC(iommu_force_on)) return; /* 512 pages (2MB) is max DART tablesize. */ RELOC(dart_tablesize) = 1UL << 21; /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we * will blow up an entire large page anyway in the kernel mapping */ RELOC(dart_tablebase) = (unsigned long) abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); prom_printf("Dart at: %x\n", RELOC(dart_tablebase));}#endif /* CONFIG_PMAC_DART */static void __init prom_initialize_tce_table(void){ phandle node; ihandle phb_node; unsigned long offset = reloc_offset(); char compatible[64], path[64], type[64], model[64]; unsigned long i, table = 0; unsigned long base, vbase, align; unsigned int minalign, minsize; struct of_tce_table *prom_tce_table = RELOC(of_tce_table); unsigned long tce_entry, *tce_entryp; if (RELOC(ppc64_iommu_off)) return; prom_debug("starting prom_initialize_tce_table\n"); /* Search all nodes looking for PHBs. */ for (node = 0; prom_next_node(&node); ) { if (table == MAX_PHB) { prom_printf("WARNING: PCI host bridge ignored, " "need to increase MAX_PHB\n"); continue; } compatible[0] = 0; type[0] = 0; model[0] = 0; prom_getprop(node, "compatible", compatible, sizeof(compatible)); prom_getprop(node, "device_type", type, sizeof(type)); prom_getprop(node, "model", model, sizeof(model)); /* Keep the old logic in tack to avoid regression. */ if (compatible[0] != 0) { if ((strstr(compatible, RELOC("python")) == NULL) && (strstr(compatible, RELOC("Speedwagon")) == NULL) && (strstr(compatible, RELOC("Winnipeg")) == NULL)) continue; } else if (model[0] != 0) { if ((strstr(model, RELOC("ython")) == NULL) && (strstr(model, RELOC("peedwagon")) == NULL) && (strstr(model, RELOC("innipeg")) == NULL)) continue; } if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) { continue; } if (prom_getprop(node, "tce-table-minalign", &minalign, sizeof(minalign)) == PROM_ERROR) { minalign = 0; } if (prom_getprop(node, "tce-table-minsize", &minsize, sizeof(minsize)) == PROM_ERROR) { minsize = 4UL << 20; } /* * Even though we read what OF wants, we just set the table * size to 4 MB. This is enough to map 2GB of PCI DMA space. * By doing this, we avoid the pitfalls of trying to DMA to * MMIO space and the DMA alias hole. * * On POWER4, firmware sets the TCE region by assuming * each TCE table is 8MB. Using this memory for anything * else will impact performance, so we always allocate 8MB. * Anton */ if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) minsize = 8UL << 20; else minsize = 4UL << 20; /* Align to the greater of the align or size */ align = max(minalign, minsize); /* Carve out storage for the TCE table. */ base = lmb_alloc(minsize, align); if ( !base ) { prom_panic("ERROR, cannot find space for TCE table.\n"); } vbase = (unsigned long)abs_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; prom_debug("TCE table: 0x%x\n", table); prom_debug("\tnode = 0x%x\n", node); prom_debug("\tbase = 0x%x\n", vbase); prom_debug("\tsize = 0x%x\n", minsize); /* 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; } /* It seems OF doesn't null-terminate the path :-( */ memset(path, 0, sizeof(path)); /* Call OF to setup the TCE hardware */ if (call_prom("package-to-path", 3, 1, node, path, sizeof(path)-1) == PROM_ERROR) { prom_printf("package-to-path failed\n"); } else { prom_printf("opening PHB %s", path); } phb_node = call_prom("open", 1, 1, path); if ( (long)phb_node <= 0) { prom_printf("... failed\n"); } else { prom_printf("... done\n"); } call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), phb_node, -1, minsize, (u32) base, (u32) (base >> 32)); call_prom("close", 1, 0, phb_node); table++; } /* Flag the first invalid entry */ prom_tce_table[table].node = 0; prom_debug("ending prom_initialize_tce_table\n");}/* * 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 void __init prom_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 = (void *)virt_to_abs(&__secondary_hold_spinloop); unsigned long *acknowledge = (void *)virt_to_abs(&__secondary_hold_acknowledge); unsigned long secondary_hold = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold)); struct systemcfg *_systemcfg = RELOC(systemcfg); struct paca_struct *lpaca = PTRRELOC(&paca[0]); struct prom_t *_prom = PTRRELOC(&prom);#ifdef CONFIG_SMP struct naca_struct *_naca = RELOC(naca);#endif /* On pmac, we just fill out the various global bitmasks and * arrays indicating our CPUs are here, they are actually started * later on from pmac_smp */ if (_systemcfg->platform == PLATFORM_POWERMAC) { for (node = 0; prom_next_node(&node); ) { type[0] = 0; prom_getprop(node, "device_type", type, sizeof(type)); if (strcmp(type, RELOC("cpu")) != 0) continue; reg = -1; prom_getprop(node, "reg", ®, sizeof(reg)); lpaca[cpuid].hw_cpu_id = reg;#ifdef CONFIG_SMP cpu_set(cpuid, RELOC(cpu_available_map)); cpu_set(cpuid, RELOC(cpu_possible_map)); cpu_set(cpuid, RELOC(cpu_present_at_boot)); if (reg == 0) cpu_set(cpuid, RELOC(cpu_online_map));#endif /* CONFIG_SMP */ cpuid++; } return; } /* Initially, we must have one active CPU. */ _systemcfg->processorCount = 1; prom_debug("prom_hold_cpus: start...\n"); prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); prom_debug(" 1) acknowledge = 0x%x\n", (unsigned long)acknowledge); prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -