📄 prom.c
字号:
}/* * ibm,pa-features is a per-cpu property that contains a string of * attribute descriptors, each of which has a 2 byte header plus up * to 254 bytes worth of processor attribute bits. First header * byte specifies the number of bytes following the header. * Second header byte is an "attribute-specifier" type, of which * zero is the only currently-defined value. * Implementation: Pass in the byte and bit offset for the feature * that we are interested in. The function will return -1 if the * pa-features property is missing, or a 1/0 to indicate if the feature * is supported/not supported. Note that the bit numbers are * big-endian to match the definition in PAPR. */static struct ibm_pa_feature { unsigned long cpu_features; /* CPU_FTR_xxx bit */ unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */ unsigned char pabyte; /* byte number in ibm,pa-features */ unsigned char pabit; /* bit number (big-endian) */ unsigned char invert; /* if 1, pa bit set => clear feature */} ibm_pa_features[] __initdata = { {0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, {0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, {CPU_FTR_SLB, 0, 0, 2, 0}, {CPU_FTR_CTRL, 0, 0, 3, 0}, {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},};static void __init scan_features(unsigned long node, unsigned char *ftrs, unsigned long tablelen, struct ibm_pa_feature *fp, unsigned long ft_size){ unsigned long i, len, bit; /* find descriptor with type == 0 */ for (;;) { if (tablelen < 3) return; len = 2 + ftrs[0]; if (tablelen < len) return; /* descriptor 0 not found */ if (ftrs[1] == 0) break; tablelen -= len; ftrs += len; } /* loop over bits we know about */ for (i = 0; i < ft_size; ++i, ++fp) { if (fp->pabyte >= ftrs[0]) continue; bit = (ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1; if (bit ^ fp->invert) { cur_cpu_spec->cpu_features |= fp->cpu_features; cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; } else { cur_cpu_spec->cpu_features &= ~fp->cpu_features; cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; } }}static void __init check_cpu_pa_features(unsigned long node){ unsigned char *pa_ftrs; unsigned long tablelen; pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen); if (pa_ftrs == NULL) return; scan_features(node, pa_ftrs, tablelen, ibm_pa_features, ARRAY_SIZE(ibm_pa_features));}static struct feature_property { const char *name; u32 min_value; unsigned long cpu_feature; unsigned long cpu_user_ftr;} feature_properties[] __initdata = {#ifdef CONFIG_ALTIVEC {"altivec", 0, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC}, {"ibm,vmx", 1, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC},#endif /* CONFIG_ALTIVEC */#ifdef CONFIG_PPC64 {"ibm,dfp", 1, 0, PPC_FEATURE_HAS_DFP}, {"ibm,purr", 1, CPU_FTR_PURR, 0}, {"ibm,spurr", 1, CPU_FTR_SPURR, 0},#endif /* CONFIG_PPC64 */};static void __init check_cpu_feature_properties(unsigned long node){ unsigned long i; struct feature_property *fp = feature_properties; const u32 *prop; for (i = 0; i < ARRAY_SIZE(feature_properties); ++i, ++fp) { prop = of_get_flat_dt_prop(node, fp->name, NULL); if (prop && *prop >= fp->min_value) { cur_cpu_spec->cpu_features |= fp->cpu_feature; cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftr; } }}static int __init early_init_dt_scan_cpus(unsigned long node, const char *uname, int depth, void *data){ static int logical_cpuid = 0; char *type = of_get_flat_dt_prop(node, "device_type", NULL); const u32 *prop; const u32 *intserv; int i, nthreads; unsigned long len; int found = 0; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) return 0; /* Get physical cpuid */ intserv = of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", &len); if (intserv) { nthreads = len / sizeof(int); } else { intserv = of_get_flat_dt_prop(node, "reg", NULL); nthreads = 1; } /* * Now see if any of these threads match our boot cpu. * NOTE: This must match the parsing done in smp_setup_cpu_maps. */ for (i = 0; i < nthreads; i++) { /* * version 2 of the kexec param format adds the phys cpuid of * booted proc. */ if (initial_boot_params && initial_boot_params->version >= 2) { if (intserv[i] == initial_boot_params->boot_cpuid_phys) { found = 1; break; } } else { /* * Check if it's the boot-cpu, set it's hw index now, * unfortunately this format did not support booting * off secondary threads. */ if (of_get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { found = 1; break; } }#ifdef CONFIG_SMP /* logical cpu id is always 0 on UP kernels */ logical_cpuid++;#endif } if (found) { DBG("boot cpu: logical %d physical %d\n", logical_cpuid, intserv[i]); boot_cpuid = logical_cpuid; set_hard_smp_processor_id(boot_cpuid, intserv[i]); /* * PAPR defines "logical" PVR values for cpus that * meet various levels of the architecture: * 0x0f000001 Architecture version 2.04 * 0x0f000002 Architecture version 2.05 * If the cpu-version property in the cpu node contains * such a value, we call identify_cpu again with the * logical PVR value in order to use the cpu feature * bits appropriate for the architecture level. * * A POWER6 partition in "POWER6 architected" mode * uses the 0x0f000002 PVR value; in POWER5+ mode * it uses 0x0f000001. */ prop = of_get_flat_dt_prop(node, "cpu-version", NULL); if (prop && (*prop & 0xff000000) == 0x0f000000) identify_cpu(0, *prop);#if defined(CONFIG_44x) && defined(CONFIG_PPC_FPU) /* * Since 440GR(x)/440EP(x) processors have the same pvr, * we check the node path and set bit 28 in the cur_cpu_spec * pvr for EP(x) processor version. This bit is always 0 in * the "real" pvr. Then we call identify_cpu again with * the new logical pvr to enable FPU support. */ if (strstr(uname, "440EP")) { identify_cpu(0, cur_cpu_spec->pvr_value | 0x8); }#endif } check_cpu_feature_properties(node); check_cpu_pa_features(node);#ifdef CONFIG_PPC_PSERIES if (nthreads > 1) cur_cpu_spec->cpu_features |= CPU_FTR_SMT; else cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;#endif return 0;}#ifdef CONFIG_BLK_DEV_INITRDstatic void __init early_init_dt_check_for_initrd(unsigned long node){ unsigned long l; u32 *prop; DBG("Looking for initrd properties... "); prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l); if (prop) { initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4)); prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l); if (prop) { initrd_end = (unsigned long) __va(of_read_ulong(prop, l/4)); initrd_below_start_ok = 1; } else { initrd_start = 0; } } DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end);}#elsestatic inline void early_init_dt_check_for_initrd(unsigned long node){}#endif /* CONFIG_BLK_DEV_INITRD */static int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data){ unsigned long *lprop; unsigned long l; char *p; DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); if (depth != 1 || (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) return 0;#ifdef CONFIG_PPC64 /* check if iommu is forced on or off */ if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) iommu_is_off = 1; if (of_get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL) iommu_force_on = 1;#endif /* mem=x on the command line is the preferred mechanism */ lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL); if (lprop) memory_limit = *lprop;#ifdef CONFIG_PPC64 lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-start", NULL); if (lprop) tce_alloc_start = *lprop; lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-end", NULL); if (lprop) tce_alloc_end = *lprop;#endif#ifdef CONFIG_KEXEC lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL); if (lprop) crashk_res.start = *lprop; lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL); if (lprop) crashk_res.end = crashk_res.start + *lprop - 1;#endif early_init_dt_check_for_initrd(node); /* Retreive command line */ p = of_get_flat_dt_prop(node, "bootargs", &l); if (p != NULL && l > 0) strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));#ifdef CONFIG_CMDLINE if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);#endif /* CONFIG_CMDLINE */ DBG("Command line is: %s\n", cmd_line); /* break now */ return 1;}static int __init early_init_dt_scan_root(unsigned long node, const char *uname, int depth, void *data){ u32 *prop; if (depth != 0) return 0; prop = of_get_flat_dt_prop(node, "#size-cells", NULL); dt_root_size_cells = (prop == NULL) ? 1 : *prop; DBG("dt_root_size_cells = %x\n", dt_root_size_cells); prop = of_get_flat_dt_prop(node, "#address-cells", NULL); dt_root_addr_cells = (prop == NULL) ? 2 : *prop; DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells); /* break now */ return 1;}static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp){ cell_t *p = *cellp; *cellp = p + s; return of_read_ulong(p, s);}#ifdef CONFIG_PPC_PSERIES/* * Interpret the ibm,dynamic-memory property in the * /ibm,dynamic-reconfiguration-memory node. * This contains a list of memory blocks along with NUMA affinity * information. */static int __init early_init_dt_scan_drconf_memory(unsigned long node){ cell_t *dm, *ls; unsigned long l, n; unsigned long base, size, lmb_size, flags; ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l); if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t)) return 0; lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls); dm = (cell_t *)of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l); if (dm == NULL || l < sizeof(cell_t)) return 0; n = *dm++; /* number of entries */ if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t)) return 0; for (; n != 0; --n) { base = dt_mem_next_cell(dt_root_addr_cells, &dm); flags = dm[3]; /* skip DRC index, pad, assoc. list index, flags */ dm += 4; /* skip this block if the reserved bit is set in flags (0x80) or if the block is not assigned to this partition (0x8) */ if ((flags & 0x80) || !(flags & 0x8)) continue; size = lmb_size; if (iommu_is_off) { if (base >= 0x80000000ul) continue; if ((base + size) > 0x80000000ul) size = 0x80000000ul - base; } lmb_add(base, size); } lmb_dump_all(); return 0;}#else#define early_init_dt_scan_drconf_memory(node) 0#endif /* CONFIG_PPC_PSERIES */static int __init early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data){ char *type = of_get_flat_dt_prop(node, "device_type", NULL); cell_t *reg, *endp; unsigned long l; /* Look for the ibm,dynamic-reconfiguration-memory node */ if (depth == 1 && strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) return early_init_dt_scan_drconf_memory(node); /* We are scanning "memory" nodes only */ if (type == NULL) { /* * The longtrail doesn't have a device_type on the * /memory node, so look for the node called /memory@0. */ if (depth != 1 || strcmp(uname, "memory@0") != 0) return 0; } else if (strcmp(type, "memory") != 0) return 0; reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l); if (reg == NULL) reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); if (reg == NULL) return 0; endp = reg + (l / sizeof(cell_t)); DBG("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", uname, l, reg[0], reg[1], reg[2], reg[3]); while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { unsigned long base, size; base = dt_mem_next_cell(dt_root_addr_cells, ®); size = dt_mem_next_cell(dt_root_size_cells, ®); if (size == 0) continue; DBG(" - %lx , %lx\n", base, size);#ifdef CONFIG_PPC64 if (iommu_is_off) { if (base >= 0x80000000ul) continue; if ((base + size) > 0x80000000ul) size = 0x80000000ul - base; }#endif lmb_add(base, size); } return 0;}static void __init early_reserve_mem(void){ u64 base, size; u64 *reserve_map; unsigned long self_base; unsigned long self_size; reserve_map = (u64 *)(((unsigned long)initial_boot_params) + initial_boot_params->off_mem_rsvmap); /* before we do anything, lets reserve the dt blob */ self_base = __pa((unsigned long)initial_boot_params); self_size = initial_boot_params->totalsize; lmb_reserve(self_base, self_size);#ifdef CONFIG_BLK_DEV_INITRD /* then reserve the initrd, if any */ if (initrd_start && (initrd_end > initrd_start)) lmb_reserve(__pa(initrd_start), initrd_end - initrd_start);#endif /* CONFIG_BLK_DEV_INITRD */#ifdef CONFIG_PPC32 /* * Handle the case where we might be booting from an old kexec * image that setup the mem_rsvmap as pairs of 32-bit values */ if (*reserve_map > 0xffffffffull) { u32 base_32, size_32; u32 *reserve_map_32 = (u32 *)reserve_map; while (1) { base_32 = *(reserve_map_32++); size_32 = *(reserve_map_32++); if (size_32 == 0) break; /* skip if the reservation is for the blob */ if (base_32 == self_base && size_32 == self_size) continue; DBG("reserving: %x -> %x\n", base_32, size_32); lmb_reserve(base_32, size_32); } return; }#endif while (1) { base = *(reserve_map++); size = *(reserve_map++); if (size == 0) break; DBG("reserving: %llx -> %llx\n", base, size); lmb_reserve(base, size); }#if 0 DBG("memory reserved, lmbs :\n"); lmb_dump_all();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -