Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /* pdt.c: OF PROM device tree support code.
0003  *
0004  * Paul Mackerras   August 1996.
0005  * Copyright (C) 1996-2005 Paul Mackerras.
0006  *
0007  *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
0008  *    {engebret|bergner}@us.ibm.com
0009  *
0010  *  Adapted for sparc by David S. Miller davem@davemloft.net
0011  *  Adapted for multiple architectures by Andres Salomon <dilinger@queued.net>
0012  */
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/errno.h>
0017 #include <linux/mutex.h>
0018 #include <linux/slab.h>
0019 #include <linux/of.h>
0020 #include <linux/of_pdt.h>
0021 
0022 static struct of_pdt_ops *of_pdt_prom_ops __initdata;
0023 
0024 #if defined(CONFIG_SPARC)
0025 unsigned int of_pdt_unique_id __initdata;
0026 
0027 #define of_pdt_incr_unique_id(p) do { \
0028     (p)->unique_id = of_pdt_unique_id++; \
0029 } while (0)
0030 
0031 static char * __init of_pdt_build_full_name(struct device_node *dp)
0032 {
0033     return build_path_component(dp);
0034 }
0035 
0036 #else /* CONFIG_SPARC */
0037 
0038 static inline void of_pdt_incr_unique_id(void *p) { }
0039 static inline void irq_trans_init(struct device_node *dp) { }
0040 
0041 static char * __init of_pdt_build_full_name(struct device_node *dp)
0042 {
0043     static int failsafe_id = 0; /* for generating unique names on failure */
0044     const char *name;
0045     char path[256];
0046     char *buf;
0047     int len;
0048 
0049     if (!of_pdt_prom_ops->pkg2path(dp->phandle, path, sizeof(path), &len)) {
0050         name = kbasename(path);
0051         buf = prom_early_alloc(strlen(name) + 1);
0052         strcpy(buf, name);
0053         return buf;
0054     }
0055 
0056     name = of_get_property(dp, "name", &len);
0057     buf = prom_early_alloc(len + 16);
0058     sprintf(buf, "%s@unknown%i", name, failsafe_id++);
0059     pr_err("%s: pkg2path failed; assigning %s\n", __func__, buf);
0060     return buf;
0061 }
0062 
0063 #endif /* !CONFIG_SPARC */
0064 
0065 static struct property * __init of_pdt_build_one_prop(phandle node, char *prev,
0066                            char *special_name,
0067                            void *special_val,
0068                            int special_len)
0069 {
0070     static struct property *tmp = NULL;
0071     struct property *p;
0072     int err;
0073 
0074     if (tmp) {
0075         p = tmp;
0076         memset(p, 0, sizeof(*p) + 32);
0077         tmp = NULL;
0078     } else {
0079         p = prom_early_alloc(sizeof(struct property) + 32);
0080         of_pdt_incr_unique_id(p);
0081     }
0082 
0083     p->name = (char *) (p + 1);
0084     if (special_name) {
0085         strcpy(p->name, special_name);
0086         p->length = special_len;
0087         p->value = prom_early_alloc(special_len);
0088         memcpy(p->value, special_val, special_len);
0089     } else {
0090         err = of_pdt_prom_ops->nextprop(node, prev, p->name);
0091         if (err) {
0092             tmp = p;
0093             return NULL;
0094         }
0095         p->length = of_pdt_prom_ops->getproplen(node, p->name);
0096         if (p->length <= 0) {
0097             p->length = 0;
0098         } else {
0099             int len;
0100 
0101             p->value = prom_early_alloc(p->length + 1);
0102             len = of_pdt_prom_ops->getproperty(node, p->name,
0103                     p->value, p->length);
0104             if (len <= 0)
0105                 p->length = 0;
0106             ((unsigned char *)p->value)[p->length] = '\0';
0107         }
0108     }
0109     return p;
0110 }
0111 
0112 static struct property * __init of_pdt_build_prop_list(phandle node)
0113 {
0114     struct property *head, *tail;
0115 
0116     head = tail = of_pdt_build_one_prop(node, NULL,
0117                      ".node", &node, sizeof(node));
0118 
0119     tail->next = of_pdt_build_one_prop(node, NULL, NULL, NULL, 0);
0120     tail = tail->next;
0121     while(tail) {
0122         tail->next = of_pdt_build_one_prop(node, tail->name,
0123                         NULL, NULL, 0);
0124         tail = tail->next;
0125     }
0126 
0127     return head;
0128 }
0129 
0130 static char * __init of_pdt_get_one_property(phandle node, const char *name)
0131 {
0132     char *buf = "<NULL>";
0133     int len;
0134 
0135     len = of_pdt_prom_ops->getproplen(node, name);
0136     if (len > 0) {
0137         buf = prom_early_alloc(len);
0138         len = of_pdt_prom_ops->getproperty(node, name, buf, len);
0139     }
0140 
0141     return buf;
0142 }
0143 
0144 static struct device_node * __init of_pdt_create_node(phandle node,
0145                             struct device_node *parent)
0146 {
0147     struct device_node *dp;
0148 
0149     if (!node)
0150         return NULL;
0151 
0152     dp = prom_early_alloc(sizeof(*dp));
0153     of_node_init(dp);
0154     of_pdt_incr_unique_id(dp);
0155     dp->parent = parent;
0156 
0157     dp->name = of_pdt_get_one_property(node, "name");
0158     dp->phandle = node;
0159 
0160     dp->properties = of_pdt_build_prop_list(node);
0161 
0162     dp->full_name = of_pdt_build_full_name(dp);
0163 
0164     irq_trans_init(dp);
0165 
0166     return dp;
0167 }
0168 
0169 static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
0170                            phandle node)
0171 {
0172     struct device_node *ret = NULL, *prev_sibling = NULL;
0173     struct device_node *dp;
0174 
0175     while (1) {
0176         dp = of_pdt_create_node(node, parent);
0177         if (!dp)
0178             break;
0179 
0180         if (prev_sibling)
0181             prev_sibling->sibling = dp;
0182 
0183         if (!ret)
0184             ret = dp;
0185         prev_sibling = dp;
0186 
0187         dp->child = of_pdt_build_tree(dp, of_pdt_prom_ops->getchild(node));
0188 
0189         node = of_pdt_prom_ops->getsibling(node);
0190     }
0191 
0192     return ret;
0193 }
0194 
0195 static void * __init kernel_tree_alloc(u64 size, u64 align)
0196 {
0197     return prom_early_alloc(size);
0198 }
0199 
0200 void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
0201 {
0202     BUG_ON(!ops);
0203     of_pdt_prom_ops = ops;
0204 
0205     of_root = of_pdt_create_node(root_node, NULL);
0206     of_root->full_name = "/";
0207 
0208     of_root->child = of_pdt_build_tree(of_root,
0209                 of_pdt_prom_ops->getchild(of_root->phandle));
0210 
0211     /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
0212     of_alias_scan(kernel_tree_alloc);
0213 }