diff options
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r-- | drivers/of/base.c | 74 |
1 files changed, 69 insertions, 5 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index bbd073f53c9f..87b63850e8dc 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -1028,6 +1028,24 @@ int of_parse_phandle_with_args(struct device_node *np, const char *list_name, | |||
1028 | } | 1028 | } |
1029 | EXPORT_SYMBOL(of_parse_phandle_with_args); | 1029 | EXPORT_SYMBOL(of_parse_phandle_with_args); |
1030 | 1030 | ||
1031 | #if defined(CONFIG_OF_DYNAMIC) | ||
1032 | static int of_property_notify(int action, struct device_node *np, | ||
1033 | struct property *prop) | ||
1034 | { | ||
1035 | struct of_prop_reconfig pr; | ||
1036 | |||
1037 | pr.dn = np; | ||
1038 | pr.prop = prop; | ||
1039 | return of_reconfig_notify(action, &pr); | ||
1040 | } | ||
1041 | #else | ||
1042 | static int of_property_notify(int action, struct device_node *np, | ||
1043 | struct property *prop) | ||
1044 | { | ||
1045 | return 0; | ||
1046 | } | ||
1047 | #endif | ||
1048 | |||
1031 | /** | 1049 | /** |
1032 | * prom_add_property - Add a property to a node | 1050 | * prom_add_property - Add a property to a node |
1033 | */ | 1051 | */ |
@@ -1035,6 +1053,11 @@ int prom_add_property(struct device_node *np, struct property *prop) | |||
1035 | { | 1053 | { |
1036 | struct property **next; | 1054 | struct property **next; |
1037 | unsigned long flags; | 1055 | unsigned long flags; |
1056 | int rc; | ||
1057 | |||
1058 | rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop); | ||
1059 | if (rc) | ||
1060 | return rc; | ||
1038 | 1061 | ||
1039 | prop->next = NULL; | 1062 | prop->next = NULL; |
1040 | write_lock_irqsave(&devtree_lock, flags); | 1063 | write_lock_irqsave(&devtree_lock, flags); |
@@ -1072,6 +1095,11 @@ int prom_remove_property(struct device_node *np, struct property *prop) | |||
1072 | struct property **next; | 1095 | struct property **next; |
1073 | unsigned long flags; | 1096 | unsigned long flags; |
1074 | int found = 0; | 1097 | int found = 0; |
1098 | int rc; | ||
1099 | |||
1100 | rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); | ||
1101 | if (rc) | ||
1102 | return rc; | ||
1075 | 1103 | ||
1076 | write_lock_irqsave(&devtree_lock, flags); | 1104 | write_lock_irqsave(&devtree_lock, flags); |
1077 | next = &np->properties; | 1105 | next = &np->properties; |
@@ -1114,7 +1142,11 @@ int prom_update_property(struct device_node *np, | |||
1114 | { | 1142 | { |
1115 | struct property **next, *oldprop; | 1143 | struct property **next, *oldprop; |
1116 | unsigned long flags; | 1144 | unsigned long flags; |
1117 | int found = 0; | 1145 | int rc, found = 0; |
1146 | |||
1147 | rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); | ||
1148 | if (rc) | ||
1149 | return rc; | ||
1118 | 1150 | ||
1119 | if (!newprop->name) | 1151 | if (!newprop->name) |
1120 | return -EINVAL; | 1152 | return -EINVAL; |
@@ -1160,6 +1192,26 @@ int prom_update_property(struct device_node *np, | |||
1160 | * device tree nodes. | 1192 | * device tree nodes. |
1161 | */ | 1193 | */ |
1162 | 1194 | ||
1195 | static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); | ||
1196 | |||
1197 | int of_reconfig_notifier_register(struct notifier_block *nb) | ||
1198 | { | ||
1199 | return blocking_notifier_chain_register(&of_reconfig_chain, nb); | ||
1200 | } | ||
1201 | |||
1202 | int of_reconfig_notifier_unregister(struct notifier_block *nb) | ||
1203 | { | ||
1204 | return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); | ||
1205 | } | ||
1206 | |||
1207 | int of_reconfig_notify(unsigned long action, void *p) | ||
1208 | { | ||
1209 | int rc; | ||
1210 | |||
1211 | rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); | ||
1212 | return notifier_to_errno(rc); | ||
1213 | } | ||
1214 | |||
1163 | #ifdef CONFIG_PROC_DEVICETREE | 1215 | #ifdef CONFIG_PROC_DEVICETREE |
1164 | static void of_add_proc_dt_entry(struct device_node *dn) | 1216 | static void of_add_proc_dt_entry(struct device_node *dn) |
1165 | { | 1217 | { |
@@ -1179,9 +1231,14 @@ static void of_add_proc_dt_entry(struct device_node *dn) | |||
1179 | /** | 1231 | /** |
1180 | * of_attach_node - Plug a device node into the tree and global list. | 1232 | * of_attach_node - Plug a device node into the tree and global list. |
1181 | */ | 1233 | */ |
1182 | void of_attach_node(struct device_node *np) | 1234 | int of_attach_node(struct device_node *np) |
1183 | { | 1235 | { |
1184 | unsigned long flags; | 1236 | unsigned long flags; |
1237 | int rc; | ||
1238 | |||
1239 | rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); | ||
1240 | if (rc) | ||
1241 | return rc; | ||
1185 | 1242 | ||
1186 | write_lock_irqsave(&devtree_lock, flags); | 1243 | write_lock_irqsave(&devtree_lock, flags); |
1187 | np->sibling = np->parent->child; | 1244 | np->sibling = np->parent->child; |
@@ -1191,6 +1248,7 @@ void of_attach_node(struct device_node *np) | |||
1191 | write_unlock_irqrestore(&devtree_lock, flags); | 1248 | write_unlock_irqrestore(&devtree_lock, flags); |
1192 | 1249 | ||
1193 | of_add_proc_dt_entry(np); | 1250 | of_add_proc_dt_entry(np); |
1251 | return 0; | ||
1194 | } | 1252 | } |
1195 | 1253 | ||
1196 | #ifdef CONFIG_PROC_DEVICETREE | 1254 | #ifdef CONFIG_PROC_DEVICETREE |
@@ -1220,23 +1278,28 @@ static void of_remove_proc_dt_entry(struct device_node *dn) | |||
1220 | * The caller must hold a reference to the node. The memory associated with | 1278 | * The caller must hold a reference to the node. The memory associated with |
1221 | * the node is not freed until its refcount goes to zero. | 1279 | * the node is not freed until its refcount goes to zero. |
1222 | */ | 1280 | */ |
1223 | void of_detach_node(struct device_node *np) | 1281 | int of_detach_node(struct device_node *np) |
1224 | { | 1282 | { |
1225 | struct device_node *parent; | 1283 | struct device_node *parent; |
1226 | unsigned long flags; | 1284 | unsigned long flags; |
1285 | int rc = 0; | ||
1286 | |||
1287 | rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); | ||
1288 | if (rc) | ||
1289 | return rc; | ||
1227 | 1290 | ||
1228 | write_lock_irqsave(&devtree_lock, flags); | 1291 | write_lock_irqsave(&devtree_lock, flags); |
1229 | 1292 | ||
1230 | if (of_node_check_flag(np, OF_DETACHED)) { | 1293 | if (of_node_check_flag(np, OF_DETACHED)) { |
1231 | /* someone already detached it */ | 1294 | /* someone already detached it */ |
1232 | write_unlock_irqrestore(&devtree_lock, flags); | 1295 | write_unlock_irqrestore(&devtree_lock, flags); |
1233 | return; | 1296 | return rc; |
1234 | } | 1297 | } |
1235 | 1298 | ||
1236 | parent = np->parent; | 1299 | parent = np->parent; |
1237 | if (!parent) { | 1300 | if (!parent) { |
1238 | write_unlock_irqrestore(&devtree_lock, flags); | 1301 | write_unlock_irqrestore(&devtree_lock, flags); |
1239 | return; | 1302 | return rc; |
1240 | } | 1303 | } |
1241 | 1304 | ||
1242 | if (allnodes == np) | 1305 | if (allnodes == np) |
@@ -1265,6 +1328,7 @@ void of_detach_node(struct device_node *np) | |||
1265 | write_unlock_irqrestore(&devtree_lock, flags); | 1328 | write_unlock_irqrestore(&devtree_lock, flags); |
1266 | 1329 | ||
1267 | of_remove_proc_dt_entry(np); | 1330 | of_remove_proc_dt_entry(np); |
1331 | return rc; | ||
1268 | } | 1332 | } |
1269 | #endif /* defined(CONFIG_OF_DYNAMIC) */ | 1333 | #endif /* defined(CONFIG_OF_DYNAMIC) */ |
1270 | 1334 | ||