prom.c
字号:
DBG("Command line is: %s\n", cmd_line); DBG(" <- unflatten_device_tree()\n");}static int __init early_init_dt_scan_cpus(unsigned long node, const char *uname, int depth, void *data){ char *type = get_flat_dt_prop(node, "device_type", NULL); u32 *prop; unsigned long size; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) return 0; /* On LPAR, look for the first ibm,pft-size property for the hash table size */ if (systemcfg->platform == PLATFORM_PSERIES_LPAR && ppc64_pft_size == 0) { u32 *pft_size; pft_size = (u32 *)get_flat_dt_prop(node, "ibm,pft-size", NULL); if (pft_size != NULL) { /* pft_size[0] is the NUMA CEC cookie */ ppc64_pft_size = pft_size[1]; } } if (initial_boot_params && initial_boot_params->version >= 2) { /* version 2 of the kexec param format adds the phys cpuid * of booted proc. */ boot_cpuid_phys = initial_boot_params->boot_cpuid_phys; boot_cpuid = 0; } else { /* Check if it's the boot-cpu, set it's hw index in paca now */ if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { u32 *prop = get_flat_dt_prop(node, "reg", NULL); set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop); boot_cpuid_phys = get_hard_smp_processor_id(0); } }#ifdef CONFIG_ALTIVEC /* Check if we have a VMX and eventually update CPU features */ prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", NULL); if (prop && (*prop) > 0) { cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; } /* Same goes for Apple's "altivec" property */ prop = (u32 *)get_flat_dt_prop(node, "altivec", NULL); if (prop) { cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; }#endif /* CONFIG_ALTIVEC */ /* * Check for an SMT capable CPU and set the CPU feature. We do * this by looking at the size of the ibm,ppc-interrupt-server#s * property */ prop = (u32 *)get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", &size); cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT; if (prop && ((size / sizeof(u32)) > 1)) cur_cpu_spec->cpu_features |= CPU_FTR_SMT; return 0;}static int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data){ u32 *prop; u64 *prop64; extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); if (depth != 1 || strcmp(uname, "chosen") != 0) return 0; /* get platform type */ prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL); if (prop == NULL) return 0; systemcfg->platform = *prop; /* check if iommu is forced on or off */ if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) iommu_is_off = 1; if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL) iommu_force_on = 1; prop64 = (u64*)get_flat_dt_prop(node, "linux,memory-limit", NULL); if (prop64) memory_limit = *prop64; prop64 = (u64*)get_flat_dt_prop(node, "linux,tce-alloc-start", NULL); if (prop64) tce_alloc_start = *prop64; prop64 = (u64*)get_flat_dt_prop(node, "linux,tce-alloc-end", NULL); if (prop64) tce_alloc_end = *prop64;#ifdef CONFIG_PPC_RTAS /* To help early debugging via the front panel, we retreive a minimal * set of RTAS infos now if available */ { u64 *basep, *entryp; basep = (u64*)get_flat_dt_prop(node, "linux,rtas-base", NULL); entryp = (u64*)get_flat_dt_prop(node, "linux,rtas-entry", NULL); prop = (u32*)get_flat_dt_prop(node, "linux,rtas-size", NULL); if (basep && entryp && prop) { rtas.base = *basep; rtas.entry = *entryp; rtas.size = *prop; } }#endif /* CONFIG_PPC_RTAS */ /* 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 = (u32 *)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 = (u32 *)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; unsigned long r = 0; /* Ignore more than 2 cells */ while (s > 2) { p++; s--; } while (s) { r <<= 32; r |= *(p++); s--; } *cellp = p; return r;}static int __init early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data){ char *type = get_flat_dt_prop(node, "device_type", NULL); cell_t *reg, *endp; unsigned long l; /* We are scanning "memory" nodes only */ if (type == NULL || strcmp(type, "memory") != 0) return 0; reg = (cell_t *)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); if (iommu_is_off) { if (base >= 0x80000000ul) continue; if ((base + size) > 0x80000000ul) size = 0x80000000ul - base; } lmb_add(base, size); } return 0;}static void __init early_reserve_mem(void){ u64 base, size; u64 *reserve_map = (u64 *)(((unsigned long)initial_boot_params) + initial_boot_params->off_mem_rsvmap); while (1) { base = *(reserve_map++); size = *(reserve_map++); if (size == 0) break; DBG("reserving: %lx -> %lx\n", base, size); lmb_reserve(base, size); }#if 0 DBG("memory reserved, lmbs :\n"); lmb_dump_all();#endif}void __init early_init_devtree(void *params){ DBG(" -> early_init_devtree()\n"); /* Setup flat device-tree pointer */ initial_boot_params = params; /* By default, hash size is not set */ ppc64_pft_size = 0; /* Retreive various informations from the /chosen node of the * device-tree, including the platform type, initrd location and * size, TCE reserve, and more ... */ scan_flat_dt(early_init_dt_scan_chosen, NULL); /* Scan memory nodes and rebuild LMBs */ lmb_init(); scan_flat_dt(early_init_dt_scan_root, NULL); scan_flat_dt(early_init_dt_scan_memory, NULL); lmb_enforce_memory_limit(); lmb_analyze(); systemcfg->physicalMemorySize = lmb_phys_mem_size(); lmb_reserve(0, __pa(klimit)); DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize); /* Reserve LMB regions used by kernel, initrd, dt, etc... */ early_reserve_mem(); DBG("Scanning CPUs ...\n"); /* Retreive hash table size from flattened tree plus other * CPU related informations (altivec support, boot CPU ID, ...) */ scan_flat_dt(early_init_dt_scan_cpus, NULL); /* If hash size wasn't obtained above, we calculate it now based on * the total RAM size */ if (ppc64_pft_size == 0) { unsigned long rnd_mem_size, pteg_count; /* round mem_size up to next power of 2 */ rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); if (rnd_mem_size < systemcfg->physicalMemorySize) rnd_mem_size <<= 1; /* # pages / 2 */ pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11); ppc64_pft_size = __ilog2(pteg_count << 7); } DBG("Hash pftSize: %x\n", (int)ppc64_pft_size); DBG(" <- early_init_devtree()\n");}#undef printkintprom_n_addr_cells(struct device_node* np){ int* ip; do { if (np->parent) np = np->parent; ip = (int *) get_property(np, "#address-cells", NULL); if (ip != NULL) return *ip; } while (np->parent); /* No #address-cells property for the root node, default to 1 */ return 1;}intprom_n_size_cells(struct device_node* np){ int* ip; do { if (np->parent) np = np->parent; ip = (int *) get_property(np, "#size-cells", NULL); if (ip != NULL) return *ip; } while (np->parent); /* No #size-cells property for the root node, default to 1 */ return 1;}/** * Work out the sense (active-low level / active-high edge) * of each interrupt from the device tree. */void __init prom_get_irq_senses(unsigned char *senses, int off, int max){ struct device_node *np; int i, j; /* default to level-triggered */ memset(senses, 1, max - off); for (np = allnodes; np != 0; np = np->allnext) { for (j = 0; j < np->n_intrs; j++) { i = np->intrs[j].line; if (i >= off && i < max) senses[i-off] = np->intrs[j].sense ? IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE : IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE; } }}/** * Construct and return a list of the device_nodes with a given name. */struct device_node *find_devices(const char *name){ struct device_node *head, **prevp, *np; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { if (np->name != 0 && strcasecmp(np->name, name) == 0) { *prevp = np; prevp = &np->next; } } *prevp = NULL; return head;}EXPORT_SYMBOL(find_devices);/** * Construct and return a list of the device_nodes with a given type. */struct device_node *find_type_devices(const char *type){ struct device_node *head, **prevp, *np; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { if (np->type != 0 && strcasecmp(np->type, type) == 0) { *prevp = np; prevp = &np->next; } } *prevp = NULL; return head;}EXPORT_SYMBOL(find_type_devices);/** * Returns all nodes linked together */struct device_node *find_all_nodes(void){ struct device_node *head, **prevp, *np; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { *prevp = np; prevp = &np->next; } *prevp = NULL; return head;}EXPORT_SYMBOL(find_all_nodes);/** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */intdevice_is_compatible(struct device_node *device, const char *compat){ const char* cp; int cplen, l; cp = (char *) get_property(device, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { if (strncasecmp(cp, compat, strlen(compat)) == 0) return 1; l = strlen(cp) + 1; cp += l; cplen -= l; } return 0;}EXPORT_SYMBOL(device_is_compatible);/** * Indicates whether the root node has a given value in its * compatible property. */intmachine_is_compatible(const char *compat){ struct device_node *root; int rc = 0; root = of_find_node_by_path("/"); if (root) { rc = device_is_compatible(root, compat); of_node_put(root); } return rc;}EXPORT_SYMBOL(machine_is_compatible);/** * Construct and return a list of the device_nodes with a given type * and compatible property. */struct device_node *find_compatible_devices(const char *type, const char *compat){ struct device_node *head, **prevp, *np; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { if (type != NULL && !(np->type != 0 && strcasecmp(np->type, type) == 0)) continue; if (device_is_compatible(np, compat)) { *prevp = np; prevp = &np->next; } } *prevp = NULL; return head;}EXPORT_SYMBOL(find_compatible_devices);/** * Find the device_node with a given full_name. */struct device_node *find_path_device(const char *path){ struct device_node *np; for (np = allnodes; np != 0; np = np->allnext) if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) return np; return NULL;}EXPORT_SYMBOL(find_path_device);/******* * * New implementation of the OF "find" APIs, return a refcounted * object, call of_node_put() when done. The device tree and list * are protected by a rw_lock. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -