prom.c
字号:
} return mem_start;}static unsigned long __init finish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc, int naddrc, int nsizec, int measure_only){ struct device_node *child; int *ip; /* get the device addresses and interrupts */ if (ifunc != NULL) mem_start = ifunc(np, mem_start, naddrc, nsizec, measure_only); mem_start = finish_node_interrupts(np, mem_start, measure_only); /* Look for #address-cells and #size-cells properties. */ ip = (int *) get_property(np, "#address-cells", NULL); if (ip != NULL) naddrc = *ip; ip = (int *) get_property(np, "#size-cells", NULL); if (ip != NULL) nsizec = *ip; /* the f50 sets the name to 'display' and 'compatible' to what we * expect for the name -- Cort */ if (!strcmp(np->name, "display")) np->name = get_property(np, "compatible", NULL); if (!strcmp(np->name, "device-tree") || np->parent == NULL) ifunc = interpret_root_props; else if (np->type == 0) ifunc = NULL; else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) ifunc = interpret_pci_props; else if (!strcmp(np->type, "dbdma")) ifunc = interpret_dbdma_props; else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props) ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3")) ifunc = interpret_root_props; else if (!((ifunc == interpret_dbdma_props || ifunc == interpret_macio_props) && (!strcmp(np->type, "escc") || !strcmp(np->type, "media-bay")))) ifunc = NULL; for (child = np->child; child != NULL; child = child->sibling) mem_start = finish_node(child, mem_start, ifunc, naddrc, nsizec, measure_only); return mem_start;}/** * finish_device_tree is called once things are running normally * (i.e. with text and data mapped to the address they were linked at). * It traverses the device tree and fills in some of the additional, * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt * mapping is also initialized at this point. */void __init finish_device_tree(void){ unsigned long mem, size; DBG(" -> finish_device_tree\n"); if (naca->interrupt_controller == IC_INVALID) { DBG("failed to configure interrupt controller type\n"); panic("failed to configure interrupt controller type\n"); } /* Initialize virtual IRQ map */ virt_irq_init(); /* Finish device-tree (pre-parsing some properties etc...) */ size = finish_node(allnodes, 0, NULL, 0, 0, 1); mem = (unsigned long)abs_to_virt(lmb_alloc(size, 128)); if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + size) BUG(); DBG(" <- finish_device_tree\n");}#ifdef DEBUG#define printk udbg_printf#endifstatic inline char *find_flat_dt_string(u32 offset){ return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings + offset;}/** * This function is used to scan the flattened device-tree, it is * used to extract the memory informations at boot before we can * unflatten the tree */static int __init scan_flat_dt(int (*it)(unsigned long node, const char *full_path, void *data), void *data){ unsigned long p = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; int rc = 0; do { u32 tag = *((u32 *)p); char *pathp; p += 4; if (tag == OF_DT_END_NODE) continue; if (tag == OF_DT_END) break; if (tag == OF_DT_PROP) { u32 sz = *((u32 *)p); p += 8; p = _ALIGN(p, sz >= 8 ? 8 : 4); p += sz; p = _ALIGN(p, 4); continue; } if (tag != OF_DT_BEGIN_NODE) { printk(KERN_WARNING "Invalid tag %x scanning flattened" " device tree !\n", tag); return -EINVAL; } pathp = (char *)p; p = _ALIGN(p + strlen(pathp) + 1, 4); rc = it(p, pathp, data); if (rc != 0) break; } while(1); return rc;}/** * This function can be used within scan_flattened_dt callback to get * access to properties */static void* __init get_flat_dt_prop(unsigned long node, const char *name, unsigned long *size){ unsigned long p = node; do { u32 tag = *((u32 *)p); u32 sz, noff; const char *nstr; p += 4; if (tag != OF_DT_PROP) return NULL; sz = *((u32 *)p); noff = *((u32 *)(p + 4)); p += 8; p = _ALIGN(p, sz >= 8 ? 8 : 4); nstr = find_flat_dt_string(noff); if (nstr == NULL) { printk(KERN_WARNING "Can't find property index name !\n"); return NULL; } if (strcmp(name, nstr) == 0) { if (size) *size = sz; return (void *)p; } p += sz; p = _ALIGN(p, 4); } while(1);}static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align){ void *res; *mem = _ALIGN(*mem, align); res = (void *)*mem; *mem += size; return res;}static unsigned long __init unflatten_dt_node(unsigned long mem, unsigned long *p, struct device_node *dad, struct device_node ***allnextpp){ struct device_node *np; struct property *pp, **prev_pp = NULL; char *pathp; u32 tag; unsigned int l; tag = *((u32 *)(*p)); if (tag != OF_DT_BEGIN_NODE) { printk("Weird tag at start of node: %x\n", tag); return mem; } *p += 4; pathp = (char *)*p; l = strlen(pathp) + 1; *p = _ALIGN(*p + l, 4); np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, __alignof__(struct device_node)); if (allnextpp) { memset(np, 0, sizeof(*np)); np->full_name = ((char*)np) + sizeof(struct device_node); memcpy(np->full_name, pathp, l); prev_pp = &np->properties; **allnextpp = np; *allnextpp = &np->allnext; if (dad != NULL) { np->parent = dad; /* we temporarily use the `next' field as `last_child'. */ if (dad->next == 0) dad->child = np; else dad->next->sibling = np; dad->next = np; } } while(1) { u32 sz, noff; char *pname; tag = *((u32 *)(*p)); if (tag != OF_DT_PROP) break; *p += 4; sz = *((u32 *)(*p)); noff = *((u32 *)((*p) + 4)); *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); pname = find_flat_dt_string(noff); if (pname == NULL) { printk("Can't find property name in list !\n"); break; } l = strlen(pname) + 1; pp = unflatten_dt_alloc(&mem, sizeof(struct property), __alignof__(struct property)); if (allnextpp) { if (strcmp(pname, "linux,phandle") == 0) { np->node = *((u32 *)*p); if (np->linux_phandle == 0) np->linux_phandle = np->node; } if (strcmp(pname, "ibm,phandle") == 0) np->linux_phandle = *((u32 *)*p); pp->name = pname; pp->length = sz; pp->value = (void *)*p; *prev_pp = pp; prev_pp = &pp->next; } *p = _ALIGN((*p) + sz, 4); } if (allnextpp) { *prev_pp = NULL; np->name = get_property(np, "name", NULL); np->type = get_property(np, "device_type", NULL); if (!np->name) np->name = "<NULL>"; if (!np->type) np->type = "<NULL>"; } while (tag == OF_DT_BEGIN_NODE) { mem = unflatten_dt_node(mem, p, np, allnextpp); tag = *((u32 *)(*p)); } if (tag != OF_DT_END_NODE) { printk("Weird tag at start of node: %x\n", tag); return mem; } *p += 4; return mem;}/** * unflattens the device-tree passed by the firmware, creating the * tree of struct device_node. It also fills the "name" and "type" * pointers of the nodes so the normal device-tree walking functions * can be used (this used to be done by finish_device_tree) */void __init unflatten_device_tree(void){ unsigned long start, mem, size; struct device_node **allnextp = &allnodes; char *p; int l = 0; DBG(" -> unflatten_device_tree()\n"); /* First pass, scan for size */ start = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; size = unflatten_dt_node(0, &start, NULL, NULL); DBG(" size is %lx, allocating...\n", size); /* Allocate memory for the expanded device tree */ mem = (unsigned long)abs_to_virt(lmb_alloc(size, __alignof__(struct device_node))); DBG(" unflattening...\n", mem); /* Second pass, do actual unflattening */ start = ((unsigned long)initial_boot_params) + initial_boot_params->off_dt_struct; unflatten_dt_node(mem, &start, NULL, &allnextp); if (*((u32 *)start) != OF_DT_END) printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); *allnextp = NULL; /* Get pointer to OF "/chosen" node for use everywhere */ of_chosen = of_find_node_by_path("/chosen"); /* Retreive command line */ if (of_chosen != NULL) { p = (char *)get_property(of_chosen, "bootargs", &l); if (p != NULL && l > 0) strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE)); }#ifdef CONFIG_CMDLINE if (l == 0) /* dbl check */ strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);#endif /* CONFIG_CMDLINE */ 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 *full_path, void *data){ char *type = get_flat_dt_prop(node, "device_type", NULL); /* 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 && naca->pftSize == 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 */ naca->pftSize = pft_size[1]; } } /* 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); paca[0].hw_cpu_id = prop == NULL ? 0 : *prop; } return 0;}static int __init early_init_dt_scan_chosen(unsigned long node, const char *full_path, void *data){ u32 *prop; if (strcmp(full_path, "/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;#ifdef CONFIG_PPC_PSERIES /* 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_PSERIES */ /* break now */ return 1;}static int __init early_init_dt_scan_root(unsigned long node, const char *full_path, void *data){ u32 *prop; if (strcmp(full_path, "/") != 0) return 0; prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); dt_root_size_cells = (prop == NULL) ? 1 : *prop; prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); dt_root_addr_cells = (prop == NULL) ? 2 : *prop; /* 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 *full_path, 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 ...\n", full_path); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -