diff options
-rw-r--r-- | arch/powerpc/kernel/prom.c | 90 | ||||
-rw-r--r-- | include/asm-powerpc/prom.h | 5 |
2 files changed, 93 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 02e2115323e4..70057b63de21 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -1627,6 +1627,11 @@ static void of_node_release(struct kref *kref) | |||
1627 | kfree(prop->value); | 1627 | kfree(prop->value); |
1628 | kfree(prop); | 1628 | kfree(prop); |
1629 | prop = next; | 1629 | prop = next; |
1630 | |||
1631 | if (!prop) { | ||
1632 | prop = node->deadprops; | ||
1633 | node->deadprops = NULL; | ||
1634 | } | ||
1630 | } | 1635 | } |
1631 | kfree(node->intrs); | 1636 | kfree(node->intrs); |
1632 | kfree(node->full_name); | 1637 | kfree(node->full_name); |
@@ -1783,13 +1788,16 @@ unsigned char *get_property(struct device_node *np, const char *name, | |||
1783 | { | 1788 | { |
1784 | struct property *pp; | 1789 | struct property *pp; |
1785 | 1790 | ||
1791 | read_lock(&devtree_lock); | ||
1786 | for (pp = np->properties; pp != 0; pp = pp->next) | 1792 | for (pp = np->properties; pp != 0; pp = pp->next) |
1787 | if (strcmp(pp->name, name) == 0) { | 1793 | if (strcmp(pp->name, name) == 0) { |
1788 | if (lenp != 0) | 1794 | if (lenp != 0) |
1789 | *lenp = pp->length; | 1795 | *lenp = pp->length; |
1790 | return pp->value; | 1796 | break; |
1791 | } | 1797 | } |
1792 | return NULL; | 1798 | read_unlock(&devtree_lock); |
1799 | |||
1800 | return pp ? pp->value : NULL; | ||
1793 | } | 1801 | } |
1794 | EXPORT_SYMBOL(get_property); | 1802 | EXPORT_SYMBOL(get_property); |
1795 | 1803 | ||
@@ -1823,4 +1831,82 @@ int prom_add_property(struct device_node* np, struct property* prop) | |||
1823 | return 0; | 1831 | return 0; |
1824 | } | 1832 | } |
1825 | 1833 | ||
1834 | /* | ||
1835 | * Remove a property from a node. Note that we don't actually | ||
1836 | * remove it, since we have given out who-knows-how-many pointers | ||
1837 | * to the data using get-property. Instead we just move the property | ||
1838 | * to the "dead properties" list, so it won't be found any more. | ||
1839 | */ | ||
1840 | int prom_remove_property(struct device_node *np, struct property *prop) | ||
1841 | { | ||
1842 | struct property **next; | ||
1843 | int found = 0; | ||
1844 | |||
1845 | write_lock(&devtree_lock); | ||
1846 | next = &np->properties; | ||
1847 | while (*next) { | ||
1848 | if (*next == prop) { | ||
1849 | /* found the node */ | ||
1850 | *next = prop->next; | ||
1851 | prop->next = np->deadprops; | ||
1852 | np->deadprops = prop; | ||
1853 | found = 1; | ||
1854 | break; | ||
1855 | } | ||
1856 | next = &(*next)->next; | ||
1857 | } | ||
1858 | write_unlock(&devtree_lock); | ||
1859 | |||
1860 | if (!found) | ||
1861 | return -ENODEV; | ||
1862 | |||
1863 | #ifdef CONFIG_PROC_DEVICETREE | ||
1864 | /* try to remove the proc node as well */ | ||
1865 | if (np->pde) | ||
1866 | proc_device_tree_remove_prop(np->pde, prop); | ||
1867 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
1868 | |||
1869 | return 0; | ||
1870 | } | ||
1871 | |||
1872 | /* | ||
1873 | * Update a property in a node. Note that we don't actually | ||
1874 | * remove it, since we have given out who-knows-how-many pointers | ||
1875 | * to the data using get-property. Instead we just move the property | ||
1876 | * to the "dead properties" list, and add the new property to the | ||
1877 | * property list | ||
1878 | */ | ||
1879 | int prom_update_property(struct device_node *np, | ||
1880 | struct property *newprop, | ||
1881 | struct property *oldprop) | ||
1882 | { | ||
1883 | struct property **next; | ||
1884 | int found = 0; | ||
1885 | |||
1886 | write_lock(&devtree_lock); | ||
1887 | next = &np->properties; | ||
1888 | while (*next) { | ||
1889 | if (*next == oldprop) { | ||
1890 | /* found the node */ | ||
1891 | newprop->next = oldprop->next; | ||
1892 | *next = newprop; | ||
1893 | oldprop->next = np->deadprops; | ||
1894 | np->deadprops = oldprop; | ||
1895 | found = 1; | ||
1896 | break; | ||
1897 | } | ||
1898 | next = &(*next)->next; | ||
1899 | } | ||
1900 | write_unlock(&devtree_lock); | ||
1901 | |||
1902 | if (!found) | ||
1903 | return -ENODEV; | ||
1826 | 1904 | ||
1905 | #ifdef CONFIG_PROC_DEVICETREE | ||
1906 | /* try to add to proc as well if it was initialized */ | ||
1907 | if (np->pde) | ||
1908 | proc_device_tree_update_prop(np->pde, newprop, oldprop); | ||
1909 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
1910 | |||
1911 | return 0; | ||
1912 | } | ||
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 329e9bf62260..25d8d5974d19 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h | |||
@@ -87,6 +87,7 @@ struct device_node { | |||
87 | char *full_name; | 87 | char *full_name; |
88 | 88 | ||
89 | struct property *properties; | 89 | struct property *properties; |
90 | struct property *deadprops; /* removed properties */ | ||
90 | struct device_node *parent; | 91 | struct device_node *parent; |
91 | struct device_node *child; | 92 | struct device_node *child; |
92 | struct device_node *sibling; | 93 | struct device_node *sibling; |
@@ -164,6 +165,10 @@ extern int prom_n_size_cells(struct device_node* np); | |||
164 | extern int prom_n_intr_cells(struct device_node* np); | 165 | extern int prom_n_intr_cells(struct device_node* np); |
165 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); | 166 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); |
166 | extern int prom_add_property(struct device_node* np, struct property* prop); | 167 | extern int prom_add_property(struct device_node* np, struct property* prop); |
168 | extern int prom_remove_property(struct device_node *np, struct property *prop); | ||
169 | extern int prom_update_property(struct device_node *np, | ||
170 | struct property *newprop, | ||
171 | struct property *oldprop); | ||
167 | 172 | ||
168 | #ifdef CONFIG_PPC32 | 173 | #ifdef CONFIG_PPC32 |
169 | /* | 174 | /* |