diff options
| -rw-r--r-- | Documentation/ABI/testing/sysfs-firmware-ofw | 28 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/dlpar.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/reconfig.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/sysdev/msi_bitmap.c | 2 | ||||
| -rw-r--r-- | drivers/of/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/of/base.c | 231 | ||||
| -rw-r--r-- | drivers/of/fdt.c | 2 | ||||
| -rw-r--r-- | drivers/of/pdt.c | 3 | ||||
| -rw-r--r-- | drivers/of/selftest.c | 62 | ||||
| -rw-r--r-- | drivers/of/testcase-data/tests-phandle.dtsi | 3 | ||||
| -rw-r--r-- | fs/proc/Makefile | 1 | ||||
| -rw-r--r-- | fs/proc/internal.h | 7 | ||||
| -rw-r--r-- | fs/proc/proc_devtree.c | 241 | ||||
| -rw-r--r-- | fs/proc/root.c | 3 | ||||
| -rw-r--r-- | include/linux/of.h | 39 |
15 files changed, 300 insertions, 334 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-ofw b/Documentation/ABI/testing/sysfs-firmware-ofw new file mode 100644 index 000000000000..f562b188e71d --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-ofw | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | What: /sys/firmware/devicetree/* | ||
| 2 | Date: November 2013 | ||
| 3 | Contact: Grant Likely <grant.likely@linaro.org> | ||
| 4 | Description: | ||
| 5 | When using OpenFirmware or a Flattened Device Tree to enumerate | ||
| 6 | hardware, the device tree structure will be exposed in this | ||
| 7 | directory. | ||
| 8 | |||
| 9 | It is possible for multiple device-tree directories to exist. | ||
| 10 | Some device drivers use a separate detached device tree which | ||
| 11 | have no attachment to the system tree and will appear in a | ||
| 12 | different subdirectory under /sys/firmware/devicetree. | ||
| 13 | |||
| 14 | Userspace must not use the /sys/firmware/devicetree/base | ||
| 15 | path directly, but instead should follow /proc/device-tree | ||
| 16 | symlink. It is possible that the absolute path will change | ||
| 17 | in the future, but the symlink is the stable ABI. | ||
| 18 | |||
| 19 | The /proc/device-tree symlink replaces the devicetree /proc | ||
| 20 | filesystem support, and has largely the same semantics and | ||
| 21 | should be compatible with existing userspace. | ||
| 22 | |||
| 23 | The contents of /sys/firmware/devicetree/ is a | ||
| 24 | hierarchy of directories, one per device tree node. The | ||
| 25 | directory name is the resolved path component name (node | ||
| 26 | name plus address). Properties are represented as files | ||
| 27 | in the directory. The contents of each file is the exact | ||
| 28 | binary data from the device tree. | ||
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index a8fe5aa3d34f..022b38e6a80b 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/kref.h> | ||
| 15 | #include <linux/notifier.h> | 14 | #include <linux/notifier.h> |
| 16 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
| 17 | #include <linux/cpu.h> | 16 | #include <linux/cpu.h> |
| @@ -87,7 +86,6 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa, | |||
| 87 | } | 86 | } |
| 88 | 87 | ||
| 89 | of_node_set_flag(dn, OF_DYNAMIC); | 88 | of_node_set_flag(dn, OF_DYNAMIC); |
| 90 | kref_init(&dn->kref); | ||
| 91 | 89 | ||
| 92 | return dn; | 90 | return dn; |
| 93 | } | 91 | } |
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index f93cdf55628c..0435bb65d0aa 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 15 | #include <linux/kref.h> | ||
| 16 | #include <linux/notifier.h> | 15 | #include <linux/notifier.h> |
| 17 | #include <linux/proc_fs.h> | 16 | #include <linux/proc_fs.h> |
| 18 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| @@ -70,7 +69,6 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist | |||
| 70 | 69 | ||
| 71 | np->properties = proplist; | 70 | np->properties = proplist; |
| 72 | of_node_set_flag(np, OF_DYNAMIC); | 71 | of_node_set_flag(np, OF_DYNAMIC); |
| 73 | kref_init(&np->kref); | ||
| 74 | 72 | ||
| 75 | np->parent = derive_parent(path); | 73 | np->parent = derive_parent(path); |
| 76 | if (IS_ERR(np->parent)) { | 74 | if (IS_ERR(np->parent)) { |
diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c index 0968b66b4cf9..8ba60424be95 100644 --- a/arch/powerpc/sysdev/msi_bitmap.c +++ b/arch/powerpc/sysdev/msi_bitmap.c | |||
| @@ -202,7 +202,7 @@ void __init test_of_node(void) | |||
| 202 | 202 | ||
| 203 | /* There should really be a struct device_node allocator */ | 203 | /* There should really be a struct device_node allocator */ |
| 204 | memset(&of_node, 0, sizeof(of_node)); | 204 | memset(&of_node, 0, sizeof(of_node)); |
| 205 | kref_init(&of_node.kref); | 205 | kref_init(&of_node.kobj.kref); |
| 206 | of_node.full_name = node_name; | 206 | of_node.full_name = node_name; |
| 207 | 207 | ||
| 208 | check(0 == msi_bitmap_alloc(&bmp, size, &of_node)); | 208 | check(0 == msi_bitmap_alloc(&bmp, size, &of_node)); |
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index c144b8f990ff..889005fa4d04 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig | |||
| @@ -7,14 +7,6 @@ config OF | |||
| 7 | menu "Device Tree and Open Firmware support" | 7 | menu "Device Tree and Open Firmware support" |
| 8 | depends on OF | 8 | depends on OF |
| 9 | 9 | ||
| 10 | config PROC_DEVICETREE | ||
| 11 | bool "Support for device tree in /proc" | ||
| 12 | depends on PROC_FS && !SPARC | ||
| 13 | help | ||
| 14 | This option adds a device-tree directory under /proc which contains | ||
| 15 | an image of the device tree that the kernel copies from Open | ||
| 16 | Firmware or other boot firmware. If unsure, say Y here. | ||
| 17 | |||
| 18 | config OF_SELFTEST | 10 | config OF_SELFTEST |
| 19 | bool "Device Tree Runtime self tests" | 11 | bool "Device Tree Runtime self tests" |
| 20 | depends on OF_IRQ | 12 | depends on OF_IRQ |
diff --git a/drivers/of/base.c b/drivers/of/base.c index 48594f334151..418a4ff9d97c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/of.h> | 23 | #include <linux/of.h> |
| 24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/string.h> | ||
| 26 | #include <linux/proc_fs.h> | 27 | #include <linux/proc_fs.h> |
| 27 | 28 | ||
| 28 | #include "of_private.h" | 29 | #include "of_private.h" |
| @@ -35,6 +36,12 @@ struct device_node *of_chosen; | |||
| 35 | struct device_node *of_aliases; | 36 | struct device_node *of_aliases; |
| 36 | static struct device_node *of_stdout; | 37 | static struct device_node *of_stdout; |
| 37 | 38 | ||
| 39 | static struct kset *of_kset; | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Used to protect the of_aliases; but also overloaded to hold off addition of | ||
| 43 | * nodes to sysfs | ||
| 44 | */ | ||
| 38 | DEFINE_MUTEX(of_aliases_mutex); | 45 | DEFINE_MUTEX(of_aliases_mutex); |
| 39 | 46 | ||
| 40 | /* use when traversing tree through the allnext, child, sibling, | 47 | /* use when traversing tree through the allnext, child, sibling, |
| @@ -92,14 +99,14 @@ int __weak of_node_to_nid(struct device_node *np) | |||
| 92 | struct device_node *of_node_get(struct device_node *node) | 99 | struct device_node *of_node_get(struct device_node *node) |
| 93 | { | 100 | { |
| 94 | if (node) | 101 | if (node) |
| 95 | kref_get(&node->kref); | 102 | kobject_get(&node->kobj); |
| 96 | return node; | 103 | return node; |
| 97 | } | 104 | } |
| 98 | EXPORT_SYMBOL(of_node_get); | 105 | EXPORT_SYMBOL(of_node_get); |
| 99 | 106 | ||
| 100 | static inline struct device_node *kref_to_device_node(struct kref *kref) | 107 | static inline struct device_node *kobj_to_device_node(struct kobject *kobj) |
| 101 | { | 108 | { |
| 102 | return container_of(kref, struct device_node, kref); | 109 | return container_of(kobj, struct device_node, kobj); |
| 103 | } | 110 | } |
| 104 | 111 | ||
| 105 | /** | 112 | /** |
| @@ -109,16 +116,15 @@ static inline struct device_node *kref_to_device_node(struct kref *kref) | |||
| 109 | * In of_node_put() this function is passed to kref_put() | 116 | * In of_node_put() this function is passed to kref_put() |
| 110 | * as the destructor. | 117 | * as the destructor. |
| 111 | */ | 118 | */ |
| 112 | static void of_node_release(struct kref *kref) | 119 | static void of_node_release(struct kobject *kobj) |
| 113 | { | 120 | { |
| 114 | struct device_node *node = kref_to_device_node(kref); | 121 | struct device_node *node = kobj_to_device_node(kobj); |
| 115 | struct property *prop = node->properties; | 122 | struct property *prop = node->properties; |
| 116 | 123 | ||
| 117 | /* We should never be releasing nodes that haven't been detached. */ | 124 | /* We should never be releasing nodes that haven't been detached. */ |
| 118 | if (!of_node_check_flag(node, OF_DETACHED)) { | 125 | if (!of_node_check_flag(node, OF_DETACHED)) { |
| 119 | pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); | 126 | pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); |
| 120 | dump_stack(); | 127 | dump_stack(); |
| 121 | kref_init(&node->kref); | ||
| 122 | return; | 128 | return; |
| 123 | } | 129 | } |
| 124 | 130 | ||
| @@ -151,11 +157,154 @@ static void of_node_release(struct kref *kref) | |||
| 151 | void of_node_put(struct device_node *node) | 157 | void of_node_put(struct device_node *node) |
| 152 | { | 158 | { |
| 153 | if (node) | 159 | if (node) |
| 154 | kref_put(&node->kref, of_node_release); | 160 | kobject_put(&node->kobj); |
| 155 | } | 161 | } |
| 156 | EXPORT_SYMBOL(of_node_put); | 162 | EXPORT_SYMBOL(of_node_put); |
| 163 | #else | ||
| 164 | static void of_node_release(struct kobject *kobj) | ||
| 165 | { | ||
| 166 | /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ | ||
| 167 | } | ||
| 157 | #endif /* CONFIG_OF_DYNAMIC */ | 168 | #endif /* CONFIG_OF_DYNAMIC */ |
| 158 | 169 | ||
| 170 | struct kobj_type of_node_ktype = { | ||
| 171 | .release = of_node_release, | ||
| 172 | }; | ||
| 173 | |||
| 174 | static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, | ||
| 175 | struct bin_attribute *bin_attr, char *buf, | ||
| 176 | loff_t offset, size_t count) | ||
| 177 | { | ||
| 178 | struct property *pp = container_of(bin_attr, struct property, attr); | ||
| 179 | return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); | ||
| 180 | } | ||
| 181 | |||
| 182 | static const char *safe_name(struct kobject *kobj, const char *orig_name) | ||
| 183 | { | ||
| 184 | const char *name = orig_name; | ||
| 185 | struct kernfs_node *kn; | ||
| 186 | int i = 0; | ||
| 187 | |||
| 188 | /* don't be a hero. After 16 tries give up */ | ||
| 189 | while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) { | ||
| 190 | sysfs_put(kn); | ||
| 191 | if (name != orig_name) | ||
| 192 | kfree(name); | ||
| 193 | name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); | ||
| 194 | } | ||
| 195 | |||
| 196 | if (name != orig_name) | ||
| 197 | pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n", | ||
| 198 | kobject_name(kobj), name); | ||
| 199 | return name; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int __of_add_property_sysfs(struct device_node *np, struct property *pp) | ||
| 203 | { | ||
| 204 | int rc; | ||
| 205 | |||
| 206 | /* Important: Don't leak passwords */ | ||
| 207 | bool secure = strncmp(pp->name, "security-", 9) == 0; | ||
| 208 | |||
| 209 | sysfs_bin_attr_init(&pp->attr); | ||
| 210 | pp->attr.attr.name = safe_name(&np->kobj, pp->name); | ||
| 211 | pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; | ||
| 212 | pp->attr.size = secure ? 0 : pp->length; | ||
| 213 | pp->attr.read = of_node_property_read; | ||
| 214 | |||
| 215 | rc = sysfs_create_bin_file(&np->kobj, &pp->attr); | ||
| 216 | WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name); | ||
| 217 | return rc; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int __of_node_add(struct device_node *np) | ||
| 221 | { | ||
| 222 | const char *name; | ||
| 223 | struct property *pp; | ||
| 224 | int rc; | ||
| 225 | |||
| 226 | np->kobj.kset = of_kset; | ||
| 227 | if (!np->parent) { | ||
| 228 | /* Nodes without parents are new top level trees */ | ||
| 229 | rc = kobject_add(&np->kobj, NULL, safe_name(&of_kset->kobj, "base")); | ||
| 230 | } else { | ||
| 231 | name = safe_name(&np->parent->kobj, kbasename(np->full_name)); | ||
| 232 | if (!name || !name[0]) | ||
| 233 | return -EINVAL; | ||
| 234 | |||
| 235 | rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name); | ||
| 236 | } | ||
| 237 | if (rc) | ||
| 238 | return rc; | ||
| 239 | |||
| 240 | for_each_property_of_node(np, pp) | ||
| 241 | __of_add_property_sysfs(np, pp); | ||
| 242 | |||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | int of_node_add(struct device_node *np) | ||
| 247 | { | ||
| 248 | int rc = 0; | ||
| 249 | |||
| 250 | BUG_ON(!of_node_is_initialized(np)); | ||
| 251 | |||
| 252 | /* | ||
| 253 | * Grab the mutex here so that in a race condition between of_init() and | ||
| 254 | * of_node_add(), node addition will still be consistent. | ||
| 255 | */ | ||
| 256 | mutex_lock(&of_aliases_mutex); | ||
| 257 | if (of_kset) | ||
| 258 | rc = __of_node_add(np); | ||
| 259 | else | ||
| 260 | /* This scenario may be perfectly valid, but report it anyway */ | ||
| 261 | pr_info("of_node_add(%s) before of_init()\n", np->full_name); | ||
| 262 | mutex_unlock(&of_aliases_mutex); | ||
| 263 | return rc; | ||
| 264 | } | ||
| 265 | |||
| 266 | #if defined(CONFIG_OF_DYNAMIC) | ||
| 267 | static void of_node_remove(struct device_node *np) | ||
| 268 | { | ||
| 269 | struct property *pp; | ||
| 270 | |||
| 271 | BUG_ON(!of_node_is_initialized(np)); | ||
| 272 | |||
| 273 | /* only remove properties if on sysfs */ | ||
| 274 | if (of_node_is_attached(np)) { | ||
| 275 | for_each_property_of_node(np, pp) | ||
| 276 | sysfs_remove_bin_file(&np->kobj, &pp->attr); | ||
| 277 | kobject_del(&np->kobj); | ||
| 278 | } | ||
| 279 | |||
| 280 | /* finally remove the kobj_init ref */ | ||
| 281 | of_node_put(np); | ||
| 282 | } | ||
| 283 | #endif | ||
| 284 | |||
| 285 | static int __init of_init(void) | ||
| 286 | { | ||
| 287 | struct device_node *np; | ||
| 288 | |||
| 289 | /* Create the kset, and register existing nodes */ | ||
| 290 | mutex_lock(&of_aliases_mutex); | ||
| 291 | of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); | ||
| 292 | if (!of_kset) { | ||
| 293 | mutex_unlock(&of_aliases_mutex); | ||
| 294 | return -ENOMEM; | ||
| 295 | } | ||
| 296 | for_each_of_allnodes(np) | ||
| 297 | __of_node_add(np); | ||
| 298 | mutex_unlock(&of_aliases_mutex); | ||
| 299 | |||
| 300 | /* Symlink in /proc as required by userspace ABI */ | ||
| 301 | if (of_allnodes) | ||
| 302 | proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); | ||
| 303 | |||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | core_initcall(of_init); | ||
| 307 | |||
| 159 | static struct property *__of_find_property(const struct device_node *np, | 308 | static struct property *__of_find_property(const struct device_node *np, |
| 160 | const char *name, int *lenp) | 309 | const char *name, int *lenp) |
| 161 | { | 310 | { |
| @@ -1498,6 +1647,10 @@ static int of_property_notify(int action, struct device_node *np, | |||
| 1498 | { | 1647 | { |
| 1499 | struct of_prop_reconfig pr; | 1648 | struct of_prop_reconfig pr; |
| 1500 | 1649 | ||
| 1650 | /* only call notifiers if the node is attached */ | ||
| 1651 | if (!of_node_is_attached(np)) | ||
| 1652 | return 0; | ||
| 1653 | |||
| 1501 | pr.dn = np; | 1654 | pr.dn = np; |
| 1502 | pr.prop = prop; | 1655 | pr.prop = prop; |
| 1503 | return of_reconfig_notify(action, &pr); | 1656 | return of_reconfig_notify(action, &pr); |
| @@ -1546,12 +1699,11 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
| 1546 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1699 | raw_spin_lock_irqsave(&devtree_lock, flags); |
| 1547 | rc = __of_add_property(np, prop); | 1700 | rc = __of_add_property(np, prop); |
| 1548 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1701 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 1702 | if (rc) | ||
| 1703 | return rc; | ||
| 1549 | 1704 | ||
| 1550 | #ifdef CONFIG_PROC_DEVICETREE | 1705 | if (of_node_is_attached(np)) |
| 1551 | /* try to add to proc as well if it was initialized */ | 1706 | __of_add_property_sysfs(np, prop); |
| 1552 | if (!rc && np->pde) | ||
| 1553 | proc_device_tree_add_prop(np->pde, prop); | ||
| 1554 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
| 1555 | 1707 | ||
| 1556 | return rc; | 1708 | return rc; |
| 1557 | } | 1709 | } |
| @@ -1593,11 +1745,11 @@ int of_remove_property(struct device_node *np, struct property *prop) | |||
| 1593 | if (!found) | 1745 | if (!found) |
| 1594 | return -ENODEV; | 1746 | return -ENODEV; |
| 1595 | 1747 | ||
| 1596 | #ifdef CONFIG_PROC_DEVICETREE | 1748 | /* at early boot, bail hear and defer setup to of_init() */ |
| 1597 | /* try to remove the proc node as well */ | 1749 | if (!of_kset) |
| 1598 | if (np->pde) | 1750 | return 0; |
| 1599 | proc_device_tree_remove_prop(np->pde, prop); | 1751 | |
| 1600 | #endif /* CONFIG_PROC_DEVICETREE */ | 1752 | sysfs_remove_bin_file(&np->kobj, &prop->attr); |
| 1601 | 1753 | ||
| 1602 | return 0; | 1754 | return 0; |
| 1603 | } | 1755 | } |
| @@ -1643,16 +1795,17 @@ int of_update_property(struct device_node *np, struct property *newprop) | |||
| 1643 | next = &(*next)->next; | 1795 | next = &(*next)->next; |
| 1644 | } | 1796 | } |
| 1645 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1797 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 1798 | if (rc) | ||
| 1799 | return rc; | ||
| 1800 | |||
| 1801 | /* Update the sysfs attribute */ | ||
| 1802 | if (oldprop) | ||
| 1803 | sysfs_remove_bin_file(&np->kobj, &oldprop->attr); | ||
| 1804 | __of_add_property_sysfs(np, newprop); | ||
| 1646 | 1805 | ||
| 1647 | if (!found) | 1806 | if (!found) |
| 1648 | return -ENODEV; | 1807 | return -ENODEV; |
| 1649 | 1808 | ||
| 1650 | #ifdef CONFIG_PROC_DEVICETREE | ||
| 1651 | /* try to add to proc as well if it was initialized */ | ||
| 1652 | if (!rc && np->pde) | ||
| 1653 | proc_device_tree_update_prop(np->pde, newprop, oldprop); | ||
| 1654 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
| 1655 | |||
| 1656 | return 0; | 1809 | return 0; |
| 1657 | } | 1810 | } |
| 1658 | 1811 | ||
| @@ -1687,22 +1840,6 @@ int of_reconfig_notify(unsigned long action, void *p) | |||
| 1687 | return notifier_to_errno(rc); | 1840 | return notifier_to_errno(rc); |
| 1688 | } | 1841 | } |
| 1689 | 1842 | ||
| 1690 | #ifdef CONFIG_PROC_DEVICETREE | ||
| 1691 | static void of_add_proc_dt_entry(struct device_node *dn) | ||
| 1692 | { | ||
| 1693 | struct proc_dir_entry *ent; | ||
| 1694 | |||
| 1695 | ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); | ||
| 1696 | if (ent) | ||
| 1697 | proc_device_tree_add_node(dn, ent); | ||
| 1698 | } | ||
| 1699 | #else | ||
| 1700 | static void of_add_proc_dt_entry(struct device_node *dn) | ||
| 1701 | { | ||
| 1702 | return; | ||
| 1703 | } | ||
| 1704 | #endif | ||
| 1705 | |||
| 1706 | /** | 1843 | /** |
| 1707 | * of_attach_node - Plug a device node into the tree and global list. | 1844 | * of_attach_node - Plug a device node into the tree and global list. |
| 1708 | */ | 1845 | */ |
| @@ -1723,22 +1860,10 @@ int of_attach_node(struct device_node *np) | |||
| 1723 | of_node_clear_flag(np, OF_DETACHED); | 1860 | of_node_clear_flag(np, OF_DETACHED); |
| 1724 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1861 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 1725 | 1862 | ||
| 1726 | of_add_proc_dt_entry(np); | 1863 | of_node_add(np); |
| 1727 | return 0; | 1864 | return 0; |
| 1728 | } | 1865 | } |
| 1729 | 1866 | ||
| 1730 | #ifdef CONFIG_PROC_DEVICETREE | ||
| 1731 | static void of_remove_proc_dt_entry(struct device_node *dn) | ||
| 1732 | { | ||
| 1733 | proc_remove(dn->pde); | ||
| 1734 | } | ||
| 1735 | #else | ||
| 1736 | static void of_remove_proc_dt_entry(struct device_node *dn) | ||
| 1737 | { | ||
| 1738 | return; | ||
| 1739 | } | ||
| 1740 | #endif | ||
| 1741 | |||
| 1742 | /** | 1867 | /** |
| 1743 | * of_detach_node - "Unplug" a node from the device tree. | 1868 | * of_detach_node - "Unplug" a node from the device tree. |
| 1744 | * | 1869 | * |
| @@ -1794,7 +1919,7 @@ int of_detach_node(struct device_node *np) | |||
| 1794 | of_node_set_flag(np, OF_DETACHED); | 1919 | of_node_set_flag(np, OF_DETACHED); |
| 1795 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1920 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 1796 | 1921 | ||
| 1797 | of_remove_proc_dt_entry(np); | 1922 | of_node_remove(np); |
| 1798 | return rc; | 1923 | return rc; |
| 1799 | } | 1924 | } |
| 1800 | #endif /* defined(CONFIG_OF_DYNAMIC) */ | 1925 | #endif /* defined(CONFIG_OF_DYNAMIC) */ |
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 501bc83f8cdf..fa16a912a927 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c | |||
| @@ -204,6 +204,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob, | |||
| 204 | __alignof__(struct device_node)); | 204 | __alignof__(struct device_node)); |
| 205 | if (allnextpp) { | 205 | if (allnextpp) { |
| 206 | char *fn; | 206 | char *fn; |
| 207 | of_node_init(np); | ||
| 207 | np->full_name = fn = ((char *)np) + sizeof(*np); | 208 | np->full_name = fn = ((char *)np) + sizeof(*np); |
| 208 | if (new_format) { | 209 | if (new_format) { |
| 209 | /* rebuild full path for new format */ | 210 | /* rebuild full path for new format */ |
| @@ -234,7 +235,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob, | |||
| 234 | dad->next->sibling = np; | 235 | dad->next->sibling = np; |
| 235 | dad->next = np; | 236 | dad->next = np; |
| 236 | } | 237 | } |
| 237 | kref_init(&np->kref); | ||
| 238 | } | 238 | } |
| 239 | /* process properties */ | 239 | /* process properties */ |
| 240 | while (1) { | 240 | while (1) { |
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index 7b666736c168..36b4035881b0 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c | |||
| @@ -176,11 +176,10 @@ static struct device_node * __init of_pdt_create_node(phandle node, | |||
| 176 | return NULL; | 176 | return NULL; |
| 177 | 177 | ||
| 178 | dp = prom_early_alloc(sizeof(*dp)); | 178 | dp = prom_early_alloc(sizeof(*dp)); |
| 179 | of_node_init(dp); | ||
| 179 | of_pdt_incr_unique_id(dp); | 180 | of_pdt_incr_unique_id(dp); |
| 180 | dp->parent = parent; | 181 | dp->parent = parent; |
| 181 | 182 | ||
| 182 | kref_init(&dp->kref); | ||
| 183 | |||
| 184 | dp->name = of_pdt_get_one_property(node, "name"); | 183 | dp->name = of_pdt_get_one_property(node, "name"); |
| 185 | dp->type = of_pdt_get_one_property(node, "device_type"); | 184 | dp->type = of_pdt_get_one_property(node, "device_type"); |
| 186 | dp->phandle = node; | 185 | dp->phandle = node; |
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 6643d1920985..ae4450070503 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c | |||
| @@ -30,6 +30,67 @@ static struct selftest_results { | |||
| 30 | } \ | 30 | } \ |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | static void __init of_selftest_dynamic(void) | ||
| 34 | { | ||
| 35 | struct device_node *np; | ||
| 36 | struct property *prop; | ||
| 37 | |||
| 38 | np = of_find_node_by_path("/testcase-data"); | ||
| 39 | if (!np) { | ||
| 40 | pr_err("missing testcase data\n"); | ||
| 41 | return; | ||
| 42 | } | ||
| 43 | |||
| 44 | /* Array of 4 properties for the purpose of testing */ | ||
| 45 | prop = kzalloc(sizeof(*prop) * 4, GFP_KERNEL); | ||
| 46 | if (!prop) { | ||
| 47 | selftest(0, "kzalloc() failed\n"); | ||
| 48 | return; | ||
| 49 | } | ||
| 50 | |||
| 51 | /* Add a new property - should pass*/ | ||
| 52 | prop->name = "new-property"; | ||
| 53 | prop->value = "new-property-data"; | ||
| 54 | prop->length = strlen(prop->value); | ||
| 55 | selftest(of_add_property(np, prop) == 0, "Adding a new property failed\n"); | ||
| 56 | |||
| 57 | /* Try to add an existing property - should fail */ | ||
| 58 | prop++; | ||
| 59 | prop->name = "new-property"; | ||
| 60 | prop->value = "new-property-data-should-fail"; | ||
| 61 | prop->length = strlen(prop->value); | ||
| 62 | selftest(of_add_property(np, prop) != 0, | ||
| 63 | "Adding an existing property should have failed\n"); | ||
| 64 | |||
| 65 | /* Try to modify an existing property - should pass */ | ||
| 66 | prop->value = "modify-property-data-should-pass"; | ||
| 67 | prop->length = strlen(prop->value); | ||
| 68 | selftest(of_update_property(np, prop) == 0, | ||
| 69 | "Updating an existing property should have passed\n"); | ||
| 70 | |||
| 71 | /* Try to modify non-existent property - should pass*/ | ||
| 72 | prop++; | ||
| 73 | prop->name = "modify-property"; | ||
| 74 | prop->value = "modify-missing-property-data-should-pass"; | ||
| 75 | prop->length = strlen(prop->value); | ||
| 76 | selftest(of_update_property(np, prop) == 0, | ||
| 77 | "Updating a missing property should have passed\n"); | ||
| 78 | |||
| 79 | /* Remove property - should pass */ | ||
| 80 | selftest(of_remove_property(np, prop) == 0, | ||
| 81 | "Removing a property should have passed\n"); | ||
| 82 | |||
| 83 | /* Adding very large property - should pass */ | ||
| 84 | prop++; | ||
| 85 | prop->name = "large-property-PAGE_SIZEx8"; | ||
| 86 | prop->length = PAGE_SIZE * 8; | ||
| 87 | prop->value = kzalloc(prop->length, GFP_KERNEL); | ||
| 88 | selftest(prop->value != NULL, "Unable to allocate large buffer\n"); | ||
| 89 | if (prop->value) | ||
| 90 | selftest(of_add_property(np, prop) == 0, | ||
| 91 | "Adding a large property should have passed\n"); | ||
| 92 | } | ||
| 93 | |||
| 33 | static void __init of_selftest_parse_phandle_with_args(void) | 94 | static void __init of_selftest_parse_phandle_with_args(void) |
| 34 | { | 95 | { |
| 35 | struct device_node *np; | 96 | struct device_node *np; |
| @@ -378,6 +439,7 @@ static int __init of_selftest(void) | |||
| 378 | of_node_put(np); | 439 | of_node_put(np); |
| 379 | 440 | ||
| 380 | pr_info("start of selftest - you will see error messages\n"); | 441 | pr_info("start of selftest - you will see error messages\n"); |
| 442 | of_selftest_dynamic(); | ||
| 381 | of_selftest_parse_phandle_with_args(); | 443 | of_selftest_parse_phandle_with_args(); |
| 382 | of_selftest_property_match_string(); | 444 | of_selftest_property_match_string(); |
| 383 | of_selftest_parse_interrupts(); | 445 | of_selftest_parse_interrupts(); |
diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi index 0007d3cd7dc2..788a4c24b8f5 100644 --- a/drivers/of/testcase-data/tests-phandle.dtsi +++ b/drivers/of/testcase-data/tests-phandle.dtsi | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | 1 | ||
| 2 | / { | 2 | / { |
| 3 | testcase-data { | 3 | testcase-data { |
| 4 | security-password = "password"; | ||
| 5 | duplicate-name = "duplicate"; | ||
| 6 | duplicate-name { }; | ||
| 4 | phandle-tests { | 7 | phandle-tests { |
| 5 | provider0: provider0 { | 8 | provider0: provider0 { |
| 6 | #phandle-cells = <0>; | 9 | #phandle-cells = <0>; |
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index ab30716584f5..239493ec718e 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
| @@ -27,6 +27,5 @@ proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o | |||
| 27 | proc-$(CONFIG_NET) += proc_net.o | 27 | proc-$(CONFIG_NET) += proc_net.o |
| 28 | proc-$(CONFIG_PROC_KCORE) += kcore.o | 28 | proc-$(CONFIG_PROC_KCORE) += kcore.o |
| 29 | proc-$(CONFIG_PROC_VMCORE) += vmcore.o | 29 | proc-$(CONFIG_PROC_VMCORE) += vmcore.o |
| 30 | proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o | ||
| 31 | proc-$(CONFIG_PRINTK) += kmsg.o | 30 | proc-$(CONFIG_PRINTK) += kmsg.o |
| 32 | proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o | 31 | proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 651d09a11dde..3ab6d14e71c5 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
| @@ -211,13 +211,6 @@ extern int proc_fill_super(struct super_block *); | |||
| 211 | extern void proc_entry_rundown(struct proc_dir_entry *); | 211 | extern void proc_entry_rundown(struct proc_dir_entry *); |
| 212 | 212 | ||
| 213 | /* | 213 | /* |
| 214 | * proc_devtree.c | ||
| 215 | */ | ||
| 216 | #ifdef CONFIG_PROC_DEVICETREE | ||
| 217 | extern void proc_device_tree_init(void); | ||
| 218 | #endif | ||
| 219 | |||
| 220 | /* | ||
| 221 | * proc_namespaces.c | 214 | * proc_namespaces.c |
| 222 | */ | 215 | */ |
| 223 | extern const struct inode_operations proc_ns_dir_inode_operations; | 216 | extern const struct inode_operations proc_ns_dir_inode_operations; |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c deleted file mode 100644 index c82dd5147845..000000000000 --- a/fs/proc/proc_devtree.c +++ /dev/null | |||
| @@ -1,241 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * proc_devtree.c - handles /proc/device-tree | ||
| 3 | * | ||
| 4 | * Copyright 1997 Paul Mackerras | ||
| 5 | */ | ||
| 6 | #include <linux/errno.h> | ||
| 7 | #include <linux/init.h> | ||
| 8 | #include <linux/time.h> | ||
| 9 | #include <linux/proc_fs.h> | ||
| 10 | #include <linux/seq_file.h> | ||
| 11 | #include <linux/printk.h> | ||
| 12 | #include <linux/stat.h> | ||
| 13 | #include <linux/string.h> | ||
| 14 | #include <linux/of.h> | ||
| 15 | #include <linux/export.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <asm/uaccess.h> | ||
| 18 | #include "internal.h" | ||
| 19 | |||
| 20 | static inline void set_node_proc_entry(struct device_node *np, | ||
| 21 | struct proc_dir_entry *de) | ||
| 22 | { | ||
| 23 | np->pde = de; | ||
| 24 | } | ||
| 25 | |||
| 26 | static struct proc_dir_entry *proc_device_tree; | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Supply data on a read from /proc/device-tree/node/property. | ||
| 30 | */ | ||
| 31 | static int property_proc_show(struct seq_file *m, void *v) | ||
| 32 | { | ||
| 33 | struct property *pp = m->private; | ||
| 34 | |||
| 35 | seq_write(m, pp->value, pp->length); | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | static int property_proc_open(struct inode *inode, struct file *file) | ||
| 40 | { | ||
| 41 | return single_open(file, property_proc_show, __PDE_DATA(inode)); | ||
| 42 | } | ||
| 43 | |||
| 44 | static const struct file_operations property_proc_fops = { | ||
| 45 | .owner = THIS_MODULE, | ||
| 46 | .open = property_proc_open, | ||
| 47 | .read = seq_read, | ||
| 48 | .llseek = seq_lseek, | ||
| 49 | .release = single_release, | ||
| 50 | }; | ||
| 51 | |||
| 52 | /* | ||
| 53 | * For a node with a name like "gc@10", we make symlinks called "gc" | ||
| 54 | * and "@10" to it. | ||
| 55 | */ | ||
| 56 | |||
| 57 | /* | ||
| 58 | * Add a property to a node | ||
| 59 | */ | ||
| 60 | static struct proc_dir_entry * | ||
| 61 | __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp, | ||
| 62 | const char *name) | ||
| 63 | { | ||
| 64 | struct proc_dir_entry *ent; | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Unfortunately proc_register puts each new entry | ||
| 68 | * at the beginning of the list. So we rearrange them. | ||
| 69 | */ | ||
| 70 | ent = proc_create_data(name, | ||
| 71 | strncmp(name, "security-", 9) ? S_IRUGO : S_IRUSR, | ||
| 72 | de, &property_proc_fops, pp); | ||
| 73 | if (ent == NULL) | ||
| 74 | return NULL; | ||
| 75 | |||
| 76 | if (!strncmp(name, "security-", 9)) | ||
| 77 | proc_set_size(ent, 0); /* don't leak number of password chars */ | ||
| 78 | else | ||
| 79 | proc_set_size(ent, pp->length); | ||
| 80 | |||
| 81 | return ent; | ||
| 82 | } | ||
| 83 | |||
| 84 | |||
| 85 | void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) | ||
| 86 | { | ||
| 87 | __proc_device_tree_add_prop(pde, prop, prop->name); | ||
| 88 | } | ||
| 89 | |||
| 90 | void proc_device_tree_remove_prop(struct proc_dir_entry *pde, | ||
| 91 | struct property *prop) | ||
| 92 | { | ||
| 93 | remove_proc_entry(prop->name, pde); | ||
| 94 | } | ||
| 95 | |||
| 96 | void proc_device_tree_update_prop(struct proc_dir_entry *pde, | ||
| 97 | struct property *newprop, | ||
| 98 | struct property *oldprop) | ||
| 99 | { | ||
| 100 | struct proc_dir_entry *ent; | ||
| 101 | |||
| 102 | if (!oldprop) { | ||
| 103 | proc_device_tree_add_prop(pde, newprop); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | |||
| 107 | for (ent = pde->subdir; ent != NULL; ent = ent->next) | ||
| 108 | if (ent->data == oldprop) | ||
| 109 | break; | ||
| 110 | if (ent == NULL) { | ||
| 111 | pr_warn("device-tree: property \"%s\" does not exist\n", | ||
| 112 | oldprop->name); | ||
| 113 | } else { | ||
| 114 | ent->data = newprop; | ||
| 115 | ent->size = newprop->length; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Various dodgy firmware might give us nodes and/or properties with | ||
| 121 | * conflicting names. That's generally ok, except for exporting via /proc, | ||
| 122 | * so munge names here to ensure they're unique. | ||
| 123 | */ | ||
| 124 | |||
| 125 | static int duplicate_name(struct proc_dir_entry *de, const char *name) | ||
| 126 | { | ||
| 127 | struct proc_dir_entry *ent; | ||
| 128 | int found = 0; | ||
| 129 | |||
| 130 | spin_lock(&proc_subdir_lock); | ||
| 131 | |||
| 132 | for (ent = de->subdir; ent != NULL; ent = ent->next) { | ||
| 133 | if (strcmp(ent->name, name) == 0) { | ||
| 134 | found = 1; | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | spin_unlock(&proc_subdir_lock); | ||
| 140 | |||
| 141 | return found; | ||
| 142 | } | ||
| 143 | |||
| 144 | static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de, | ||
| 145 | const char *name) | ||
| 146 | { | ||
| 147 | char *fixed_name; | ||
| 148 | int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */ | ||
| 149 | int i = 1, size; | ||
| 150 | |||
| 151 | realloc: | ||
| 152 | fixed_name = kmalloc(fixup_len, GFP_KERNEL); | ||
| 153 | if (fixed_name == NULL) { | ||
| 154 | pr_err("device-tree: Out of memory trying to fixup " | ||
| 155 | "name \"%s\"\n", name); | ||
| 156 | return name; | ||
| 157 | } | ||
| 158 | |||
| 159 | retry: | ||
| 160 | size = snprintf(fixed_name, fixup_len, "%s#%d", name, i); | ||
| 161 | size++; /* account for NULL */ | ||
| 162 | |||
| 163 | if (size > fixup_len) { | ||
| 164 | /* We ran out of space, free and reallocate. */ | ||
| 165 | kfree(fixed_name); | ||
| 166 | fixup_len = size; | ||
| 167 | goto realloc; | ||
| 168 | } | ||
| 169 | |||
| 170 | if (duplicate_name(de, fixed_name)) { | ||
| 171 | /* Multiple duplicates. Retry with a different offset. */ | ||
| 172 | i++; | ||
| 173 | goto retry; | ||
| 174 | } | ||
| 175 | |||
| 176 | pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n", | ||
| 177 | np->full_name, fixed_name); | ||
| 178 | |||
| 179 | return fixed_name; | ||
| 180 | } | ||
| 181 | |||
| 182 | /* | ||
| 183 | * Process a node, adding entries for its children and its properties. | ||
| 184 | */ | ||
| 185 | void proc_device_tree_add_node(struct device_node *np, | ||
| 186 | struct proc_dir_entry *de) | ||
| 187 | { | ||
| 188 | struct property *pp; | ||
| 189 | struct proc_dir_entry *ent; | ||
| 190 | struct device_node *child; | ||
| 191 | const char *p; | ||
| 192 | |||
| 193 | set_node_proc_entry(np, de); | ||
| 194 | for (child = NULL; (child = of_get_next_child(np, child));) { | ||
| 195 | /* Use everything after the last slash, or the full name */ | ||
| 196 | p = kbasename(child->full_name); | ||
| 197 | |||
| 198 | if (duplicate_name(de, p)) | ||
| 199 | p = fixup_name(np, de, p); | ||
| 200 | |||
| 201 | ent = proc_mkdir(p, de); | ||
| 202 | if (ent == NULL) | ||
| 203 | break; | ||
| 204 | proc_device_tree_add_node(child, ent); | ||
| 205 | } | ||
| 206 | of_node_put(child); | ||
| 207 | |||
| 208 | for (pp = np->properties; pp != NULL; pp = pp->next) { | ||
| 209 | p = pp->name; | ||
| 210 | |||
| 211 | if (strchr(p, '/')) | ||
| 212 | continue; | ||
| 213 | |||
| 214 | if (duplicate_name(de, p)) | ||
| 215 | p = fixup_name(np, de, p); | ||
| 216 | |||
| 217 | ent = __proc_device_tree_add_prop(de, pp, p); | ||
| 218 | if (ent == NULL) | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | /* | ||
| 224 | * Called on initialization to set up the /proc/device-tree subtree | ||
| 225 | */ | ||
| 226 | void __init proc_device_tree_init(void) | ||
| 227 | { | ||
| 228 | struct device_node *root; | ||
| 229 | |||
| 230 | proc_device_tree = proc_mkdir("device-tree", NULL); | ||
| 231 | if (proc_device_tree == NULL) | ||
| 232 | return; | ||
| 233 | root = of_find_node_by_path("/"); | ||
| 234 | if (root == NULL) { | ||
| 235 | remove_proc_entry("device-tree", NULL); | ||
| 236 | pr_debug("/proc/device-tree: can't find root\n"); | ||
| 237 | return; | ||
| 238 | } | ||
| 239 | proc_device_tree_add_node(root, proc_device_tree); | ||
| 240 | of_node_put(root); | ||
| 241 | } | ||
diff --git a/fs/proc/root.c b/fs/proc/root.c index 87dbcbef7fe4..7bbeb5257af1 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
| @@ -183,9 +183,6 @@ void __init proc_root_init(void) | |||
| 183 | proc_mkdir("openprom", NULL); | 183 | proc_mkdir("openprom", NULL); |
| 184 | #endif | 184 | #endif |
| 185 | proc_tty_init(); | 185 | proc_tty_init(); |
| 186 | #ifdef CONFIG_PROC_DEVICETREE | ||
| 187 | proc_device_tree_init(); | ||
| 188 | #endif | ||
| 189 | proc_mkdir("bus", NULL); | 186 | proc_mkdir("bus", NULL); |
| 190 | proc_sys_init(); | 187 | proc_sys_init(); |
| 191 | } | 188 | } |
diff --git a/include/linux/of.h b/include/linux/of.h index b3d0f6d86e3b..a8b9dad90c64 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 19 | #include <linux/bitops.h> | 19 | #include <linux/bitops.h> |
| 20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
| 21 | #include <linux/kref.h> | 21 | #include <linux/kobject.h> |
| 22 | #include <linux/mod_devicetable.h> | 22 | #include <linux/mod_devicetable.h> |
| 23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
| 24 | #include <linux/topology.h> | 24 | #include <linux/topology.h> |
| @@ -37,6 +37,7 @@ struct property { | |||
| 37 | struct property *next; | 37 | struct property *next; |
| 38 | unsigned long _flags; | 38 | unsigned long _flags; |
| 39 | unsigned int unique_id; | 39 | unsigned int unique_id; |
| 40 | struct bin_attribute attr; | ||
| 40 | }; | 41 | }; |
| 41 | 42 | ||
| 42 | #if defined(CONFIG_SPARC) | 43 | #if defined(CONFIG_SPARC) |
| @@ -56,8 +57,7 @@ struct device_node { | |||
| 56 | struct device_node *sibling; | 57 | struct device_node *sibling; |
| 57 | struct device_node *next; /* next device of same type */ | 58 | struct device_node *next; /* next device of same type */ |
| 58 | struct device_node *allnext; /* next in list of all nodes */ | 59 | struct device_node *allnext; /* next in list of all nodes */ |
| 59 | struct proc_dir_entry *pde; /* this node's proc directory */ | 60 | struct kobject kobj; |
| 60 | struct kref kref; | ||
| 61 | unsigned long _flags; | 61 | unsigned long _flags; |
| 62 | void *data; | 62 | void *data; |
| 63 | #if defined(CONFIG_SPARC) | 63 | #if defined(CONFIG_SPARC) |
| @@ -74,6 +74,27 @@ struct of_phandle_args { | |||
| 74 | uint32_t args[MAX_PHANDLE_ARGS]; | 74 | uint32_t args[MAX_PHANDLE_ARGS]; |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | extern int of_node_add(struct device_node *node); | ||
| 78 | |||
| 79 | /* initialize a node */ | ||
| 80 | extern struct kobj_type of_node_ktype; | ||
| 81 | static inline void of_node_init(struct device_node *node) | ||
| 82 | { | ||
| 83 | kobject_init(&node->kobj, &of_node_ktype); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* true when node is initialized */ | ||
| 87 | static inline int of_node_is_initialized(struct device_node *node) | ||
| 88 | { | ||
| 89 | return node && node->kobj.state_initialized; | ||
| 90 | } | ||
| 91 | |||
| 92 | /* true when node is attached (i.e. present on sysfs) */ | ||
| 93 | static inline int of_node_is_attached(struct device_node *node) | ||
| 94 | { | ||
| 95 | return node && node->kobj.state_in_sysfs; | ||
| 96 | } | ||
| 97 | |||
| 77 | #ifdef CONFIG_OF_DYNAMIC | 98 | #ifdef CONFIG_OF_DYNAMIC |
| 78 | extern struct device_node *of_node_get(struct device_node *node); | 99 | extern struct device_node *of_node_get(struct device_node *node); |
| 79 | extern void of_node_put(struct device_node *node); | 100 | extern void of_node_put(struct device_node *node); |
| @@ -187,6 +208,8 @@ static inline const char *of_node_full_name(const struct device_node *np) | |||
| 187 | return np ? np->full_name : "<no-node>"; | 208 | return np ? np->full_name : "<no-node>"; |
| 188 | } | 209 | } |
| 189 | 210 | ||
| 211 | #define for_each_of_allnodes(dn) \ | ||
| 212 | for (dn = of_allnodes; dn; dn = dn->allnext) | ||
| 190 | extern struct device_node *of_find_node_by_name(struct device_node *from, | 213 | extern struct device_node *of_find_node_by_name(struct device_node *from, |
| 191 | const char *name); | 214 | const char *name); |
| 192 | extern struct device_node *of_find_node_by_type(struct device_node *from, | 215 | extern struct device_node *of_find_node_by_type(struct device_node *from, |
| @@ -653,14 +676,4 @@ static inline int of_get_available_child_count(const struct device_node *np) | |||
| 653 | return num; | 676 | return num; |
| 654 | } | 677 | } |
| 655 | 678 | ||
| 656 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE) | ||
| 657 | extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *); | ||
| 658 | extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop); | ||
| 659 | extern void proc_device_tree_remove_prop(struct proc_dir_entry *pde, | ||
| 660 | struct property *prop); | ||
| 661 | extern void proc_device_tree_update_prop(struct proc_dir_entry *pde, | ||
| 662 | struct property *newprop, | ||
| 663 | struct property *oldprop); | ||
| 664 | #endif | ||
| 665 | |||
| 666 | #endif /* _LINUX_OF_H */ | 679 | #endif /* _LINUX_OF_H */ |
