📄 prom.c
字号:
#endif}void __init early_init_devtree(void *params){ DBG(" -> early_init_devtree(%p)\n", params); /* Setup flat device-tree pointer */ initial_boot_params = params;#ifdef CONFIG_PPC_RTAS /* Some machines might need RTAS info for debugging, grab it now. */ of_scan_flat_dt(early_init_dt_scan_rtas, NULL);#endif /* Retrieve various informations from the /chosen node of the * device-tree, including the platform type, initrd location and * size, TCE reserve, and more ... */ of_scan_flat_dt(early_init_dt_scan_chosen, NULL); /* Scan memory nodes and rebuild LMBs */ lmb_init(); of_scan_flat_dt(early_init_dt_scan_root, NULL); of_scan_flat_dt(early_init_dt_scan_memory, NULL); /* Save command line for /proc/cmdline and then parse parameters */ strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); parse_early_param(); /* Reserve LMB regions used by kernel, initrd, dt, etc... */ lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); reserve_kdump_trampoline(); reserve_crashkernel(); early_reserve_mem(); lmb_enforce_memory_limit(memory_limit); lmb_analyze(); DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); /* We may need to relocate the flat tree, do it now. * FIXME .. and the initrd too? */ move_device_tree(); DBG("Scanning CPUs ...\n"); /* Retreive CPU related informations from the flat tree * (altivec support, boot CPU ID, ...) */ of_scan_flat_dt(early_init_dt_scan_cpus, NULL); DBG(" <- early_init_devtree()\n");}/** * Indicates whether the root node has a given value in its * compatible property. */int machine_is_compatible(const char *compat){ struct device_node *root; int rc = 0; root = of_find_node_by_path("/"); if (root) { rc = of_device_is_compatible(root, compat); of_node_put(root); } return rc;}EXPORT_SYMBOL(machine_is_compatible);/******* * * 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. * * Note that property management will need some locking as well, * this isn't dealt with yet. * *******//** * of_find_node_by_phandle - Find a node given a phandle * @handle: phandle of the node to find * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_node_by_phandle(phandle handle){ struct device_node *np; read_lock(&devtree_lock); for (np = allnodes; np != 0; np = np->allnext) if (np->linux_phandle == handle) break; of_node_get(np); read_unlock(&devtree_lock); return np;}EXPORT_SYMBOL(of_find_node_by_phandle);/** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration * of_node_put() will be called on it * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */struct device_node *of_find_all_nodes(struct device_node *prev){ struct device_node *np; read_lock(&devtree_lock); np = prev ? prev->allnext : allnodes; for (; np != 0; np = np->allnext) if (of_node_get(np)) break; of_node_put(prev); read_unlock(&devtree_lock); return np;}EXPORT_SYMBOL(of_find_all_nodes);/** * of_node_get - Increment refcount of a node * @node: Node to inc refcount, NULL is supported to * simplify writing of callers * * Returns node. */struct device_node *of_node_get(struct device_node *node){ if (node) kref_get(&node->kref); return node;}EXPORT_SYMBOL(of_node_get);static inline struct device_node * kref_to_device_node(struct kref *kref){ return container_of(kref, struct device_node, kref);}/** * of_node_release - release a dynamically allocated node * @kref: kref element of the node to be released * * In of_node_put() this function is passed to kref_put() * as the destructor. */static void of_node_release(struct kref *kref){ struct device_node *node = kref_to_device_node(kref); struct property *prop = node->properties; /* We should never be releasing nodes that haven't been detached. */ if (!of_node_check_flag(node, OF_DETACHED)) { printk("WARNING: Bad of_node_put() on %s\n", node->full_name); dump_stack(); kref_init(&node->kref); return; } if (!of_node_check_flag(node, OF_DYNAMIC)) return; while (prop) { struct property *next = prop->next; kfree(prop->name); kfree(prop->value); kfree(prop); prop = next; if (!prop) { prop = node->deadprops; node->deadprops = NULL; } } kfree(node->full_name); kfree(node->data); kfree(node);}/** * of_node_put - Decrement refcount of a node * @node: Node to dec refcount, NULL is supported to * simplify writing of callers * */void of_node_put(struct device_node *node){ if (node) kref_put(&node->kref, of_node_release);}EXPORT_SYMBOL(of_node_put);/* * Plug a device node into the tree and global list. */void of_attach_node(struct device_node *np){ write_lock(&devtree_lock); np->sibling = np->parent->child; np->allnext = allnodes; np->parent->child = np; allnodes = np; write_unlock(&devtree_lock);}/* * "Unplug" a node from the device tree. The caller must hold * a reference to the node. The memory associated with the node * is not freed until its refcount goes to zero. */void of_detach_node(struct device_node *np){ struct device_node *parent; write_lock(&devtree_lock); parent = np->parent; if (!parent) goto out_unlock; if (allnodes == np) allnodes = np->allnext; else { struct device_node *prev; for (prev = allnodes; prev->allnext != np; prev = prev->allnext) ; prev->allnext = np->allnext; } if (parent->child == np) parent->child = np->sibling; else { struct device_node *prevsib; for (prevsib = np->parent->child; prevsib->sibling != np; prevsib = prevsib->sibling) ; prevsib->sibling = np->sibling; } of_node_set_flag(np, OF_DETACHED);out_unlock: write_unlock(&devtree_lock);}#ifdef CONFIG_PPC_PSERIES/* * Fix up the uninitialized fields in a new device node: * name, type and pci-specific fields */static int of_finish_dynamic_node(struct device_node *node){ struct device_node *parent = of_get_parent(node); int err = 0; const phandle *ibm_phandle; node->name = of_get_property(node, "name", NULL); node->type = of_get_property(node, "device_type", NULL); if (!node->name) node->name = "<NULL>"; if (!node->type) node->type = "<NULL>"; if (!parent) { err = -ENODEV; goto out; } /* We don't support that function on PowerMac, at least * not yet */ if (machine_is(powermac)) return -ENODEV; /* fix up new node's linux_phandle field */ if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL))) node->linux_phandle = *ibm_phandle;out: of_node_put(parent); return err;}static int prom_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node){ int err; switch (action) { case PSERIES_RECONFIG_ADD: err = of_finish_dynamic_node(node); if (err < 0) { printk(KERN_ERR "finish_node returned %d\n", err); err = NOTIFY_BAD; } break; default: err = NOTIFY_DONE; break; } return err;}static struct notifier_block prom_reconfig_nb = { .notifier_call = prom_reconfig_notifier, .priority = 10, /* This one needs to run first */};static int __init prom_reconfig_setup(void){ return pSeries_reconfig_notifier_register(&prom_reconfig_nb);}__initcall(prom_reconfig_setup);#endif/* * Add a property to a node */int prom_add_property(struct device_node* np, struct property* prop){ struct property **next; prop->next = NULL; write_lock(&devtree_lock); next = &np->properties; while (*next) { if (strcmp(prop->name, (*next)->name) == 0) { /* duplicate ! don't insert it */ write_unlock(&devtree_lock); return -1; } next = &(*next)->next; } *next = prop; write_unlock(&devtree_lock);#ifdef CONFIG_PROC_DEVICETREE /* try to add to proc as well if it was initialized */ if (np->pde) proc_device_tree_add_prop(np->pde, prop);#endif /* CONFIG_PROC_DEVICETREE */ return 0;}/* * Remove a property from a node. Note that we don't actually * remove it, since we have given out who-knows-how-many pointers * to the data using get-property. Instead we just move the property * to the "dead properties" list, so it won't be found any more. */int prom_remove_property(struct device_node *np, struct property *prop){ struct property **next; int found = 0; write_lock(&devtree_lock); next = &np->properties; while (*next) { if (*next == prop) { /* found the node */ *next = prop->next; prop->next = np->deadprops; np->deadprops = prop; found = 1; break; } next = &(*next)->next; } write_unlock(&devtree_lock); if (!found) return -ENODEV;#ifdef CONFIG_PROC_DEVICETREE /* try to remove the proc node as well */ if (np->pde) proc_device_tree_remove_prop(np->pde, prop);#endif /* CONFIG_PROC_DEVICETREE */ return 0;}/* * Update a property in a node. Note that we don't actually * remove it, since we have given out who-knows-how-many pointers * to the data using get-property. Instead we just move the property * to the "dead properties" list, and add the new property to the * property list */int prom_update_property(struct device_node *np, struct property *newprop, struct property *oldprop){ struct property **next; int found = 0; write_lock(&devtree_lock); next = &np->properties; while (*next) { if (*next == oldprop) { /* found the node */ newprop->next = oldprop->next; *next = newprop; oldprop->next = np->deadprops; np->deadprops = oldprop; found = 1; break; } next = &(*next)->next; } write_unlock(&devtree_lock); if (!found) return -ENODEV;#ifdef CONFIG_PROC_DEVICETREE /* try to add to proc as well if it was initialized */ if (np->pde) proc_device_tree_update_prop(np->pde, newprop, oldprop);#endif /* CONFIG_PROC_DEVICETREE */ return 0;}/* Find the device node for a given logical cpu number, also returns the cpu * local thread number (index in ibm,interrupt-server#s) if relevant and * asked for (non NULL) */struct device_node *of_get_cpu_node(int cpu, unsigned int *thread){ int hardid; struct device_node *np; hardid = get_hard_smp_processor_id(cpu); for_each_node_by_type(np, "cpu") { const u32 *intserv; unsigned int plen, t; /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist * fallback to "reg" property and assume no threads */ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &plen); if (intserv == NULL) { const u32 *reg = of_get_property(np, "reg", NULL); if (reg == NULL) continue; if (*reg == hardid) { if (thread) *thread = 0; return np; } } else { plen /= sizeof(u32); for (t = 0; t < plen; t++) { if (hardid == intserv[t]) { if (thread) *thread = t; return np; } } } } return NULL;}EXPORT_SYMBOL(of_get_cpu_node);#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)static struct debugfs_blob_wrapper flat_dt_blob;static int __init export_flat_device_tree(void){ struct dentry *d; flat_dt_blob.data = initial_boot_params; flat_dt_blob.size = initial_boot_params->totalsize; d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, powerpc_debugfs_root, &flat_dt_blob); if (!d) return 1; return 0;}__initcall(export_flat_device_tree);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -