diff options
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r-- | drivers/of/base.c | 142 |
1 files changed, 127 insertions, 15 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index be846408dbc1..db8d211a0d05 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -1114,13 +1114,36 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na | |||
1114 | } | 1114 | } |
1115 | EXPORT_SYMBOL(of_parse_phandle_with_args); | 1115 | EXPORT_SYMBOL(of_parse_phandle_with_args); |
1116 | 1116 | ||
1117 | #if defined(CONFIG_OF_DYNAMIC) | ||
1118 | static int of_property_notify(int action, struct device_node *np, | ||
1119 | struct property *prop) | ||
1120 | { | ||
1121 | struct of_prop_reconfig pr; | ||
1122 | |||
1123 | pr.dn = np; | ||
1124 | pr.prop = prop; | ||
1125 | return of_reconfig_notify(action, &pr); | ||
1126 | } | ||
1127 | #else | ||
1128 | static int of_property_notify(int action, struct device_node *np, | ||
1129 | struct property *prop) | ||
1130 | { | ||
1131 | return 0; | ||
1132 | } | ||
1133 | #endif | ||
1134 | |||
1117 | /** | 1135 | /** |
1118 | * prom_add_property - Add a property to a node | 1136 | * of_add_property - Add a property to a node |
1119 | */ | 1137 | */ |
1120 | int prom_add_property(struct device_node *np, struct property *prop) | 1138 | int of_add_property(struct device_node *np, struct property *prop) |
1121 | { | 1139 | { |
1122 | struct property **next; | 1140 | struct property **next; |
1123 | unsigned long flags; | 1141 | unsigned long flags; |
1142 | int rc; | ||
1143 | |||
1144 | rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop); | ||
1145 | if (rc) | ||
1146 | return rc; | ||
1124 | 1147 | ||
1125 | prop->next = NULL; | 1148 | prop->next = NULL; |
1126 | write_lock_irqsave(&devtree_lock, flags); | 1149 | write_lock_irqsave(&devtree_lock, flags); |
@@ -1146,18 +1169,23 @@ int prom_add_property(struct device_node *np, struct property *prop) | |||
1146 | } | 1169 | } |
1147 | 1170 | ||
1148 | /** | 1171 | /** |
1149 | * prom_remove_property - Remove a property from a node. | 1172 | * of_remove_property - Remove a property from a node. |
1150 | * | 1173 | * |
1151 | * Note that we don't actually remove it, since we have given out | 1174 | * Note that we don't actually remove it, since we have given out |
1152 | * who-knows-how-many pointers to the data using get-property. | 1175 | * who-knows-how-many pointers to the data using get-property. |
1153 | * Instead we just move the property to the "dead properties" | 1176 | * Instead we just move the property to the "dead properties" |
1154 | * list, so it won't be found any more. | 1177 | * list, so it won't be found any more. |
1155 | */ | 1178 | */ |
1156 | int prom_remove_property(struct device_node *np, struct property *prop) | 1179 | int of_remove_property(struct device_node *np, struct property *prop) |
1157 | { | 1180 | { |
1158 | struct property **next; | 1181 | struct property **next; |
1159 | unsigned long flags; | 1182 | unsigned long flags; |
1160 | int found = 0; | 1183 | int found = 0; |
1184 | int rc; | ||
1185 | |||
1186 | rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); | ||
1187 | if (rc) | ||
1188 | return rc; | ||
1161 | 1189 | ||
1162 | write_lock_irqsave(&devtree_lock, flags); | 1190 | write_lock_irqsave(&devtree_lock, flags); |
1163 | next = &np->properties; | 1191 | next = &np->properties; |
@@ -1187,7 +1215,7 @@ int prom_remove_property(struct device_node *np, struct property *prop) | |||
1187 | } | 1215 | } |
1188 | 1216 | ||
1189 | /* | 1217 | /* |
1190 | * prom_update_property - Update a property in a node, if the property does | 1218 | * of_update_property - Update a property in a node, if the property does |
1191 | * not exist, add it. | 1219 | * not exist, add it. |
1192 | * | 1220 | * |
1193 | * Note that we don't actually remove it, since we have given out | 1221 | * Note that we don't actually remove it, since we have given out |
@@ -1195,19 +1223,22 @@ int prom_remove_property(struct device_node *np, struct property *prop) | |||
1195 | * Instead we just move the property to the "dead properties" list, | 1223 | * Instead we just move the property to the "dead properties" list, |
1196 | * and add the new property to the property list | 1224 | * and add the new property to the property list |
1197 | */ | 1225 | */ |
1198 | int prom_update_property(struct device_node *np, | 1226 | int of_update_property(struct device_node *np, struct property *newprop) |
1199 | struct property *newprop) | ||
1200 | { | 1227 | { |
1201 | struct property **next, *oldprop; | 1228 | struct property **next, *oldprop; |
1202 | unsigned long flags; | 1229 | unsigned long flags; |
1203 | int found = 0; | 1230 | int rc, found = 0; |
1231 | |||
1232 | rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); | ||
1233 | if (rc) | ||
1234 | return rc; | ||
1204 | 1235 | ||
1205 | if (!newprop->name) | 1236 | if (!newprop->name) |
1206 | return -EINVAL; | 1237 | return -EINVAL; |
1207 | 1238 | ||
1208 | oldprop = of_find_property(np, newprop->name, NULL); | 1239 | oldprop = of_find_property(np, newprop->name, NULL); |
1209 | if (!oldprop) | 1240 | if (!oldprop) |
1210 | return prom_add_property(np, newprop); | 1241 | return of_add_property(np, newprop); |
1211 | 1242 | ||
1212 | write_lock_irqsave(&devtree_lock, flags); | 1243 | write_lock_irqsave(&devtree_lock, flags); |
1213 | next = &np->properties; | 1244 | next = &np->properties; |
@@ -1246,12 +1277,55 @@ int prom_update_property(struct device_node *np, | |||
1246 | * device tree nodes. | 1277 | * device tree nodes. |
1247 | */ | 1278 | */ |
1248 | 1279 | ||
1280 | static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); | ||
1281 | |||
1282 | int of_reconfig_notifier_register(struct notifier_block *nb) | ||
1283 | { | ||
1284 | return blocking_notifier_chain_register(&of_reconfig_chain, nb); | ||
1285 | } | ||
1286 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); | ||
1287 | |||
1288 | int of_reconfig_notifier_unregister(struct notifier_block *nb) | ||
1289 | { | ||
1290 | return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); | ||
1291 | } | ||
1292 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); | ||
1293 | |||
1294 | int of_reconfig_notify(unsigned long action, void *p) | ||
1295 | { | ||
1296 | int rc; | ||
1297 | |||
1298 | rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); | ||
1299 | return notifier_to_errno(rc); | ||
1300 | } | ||
1301 | |||
1302 | #ifdef CONFIG_PROC_DEVICETREE | ||
1303 | static void of_add_proc_dt_entry(struct device_node *dn) | ||
1304 | { | ||
1305 | struct proc_dir_entry *ent; | ||
1306 | |||
1307 | ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); | ||
1308 | if (ent) | ||
1309 | proc_device_tree_add_node(dn, ent); | ||
1310 | } | ||
1311 | #else | ||
1312 | static void of_add_proc_dt_entry(struct device_node *dn) | ||
1313 | { | ||
1314 | return; | ||
1315 | } | ||
1316 | #endif | ||
1317 | |||
1249 | /** | 1318 | /** |
1250 | * of_attach_node - Plug a device node into the tree and global list. | 1319 | * of_attach_node - Plug a device node into the tree and global list. |
1251 | */ | 1320 | */ |
1252 | void of_attach_node(struct device_node *np) | 1321 | int of_attach_node(struct device_node *np) |
1253 | { | 1322 | { |
1254 | unsigned long flags; | 1323 | unsigned long flags; |
1324 | int rc; | ||
1325 | |||
1326 | rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); | ||
1327 | if (rc) | ||
1328 | return rc; | ||
1255 | 1329 | ||
1256 | write_lock_irqsave(&devtree_lock, flags); | 1330 | write_lock_irqsave(&devtree_lock, flags); |
1257 | np->sibling = np->parent->child; | 1331 | np->sibling = np->parent->child; |
@@ -1259,24 +1333,61 @@ void of_attach_node(struct device_node *np) | |||
1259 | np->parent->child = np; | 1333 | np->parent->child = np; |
1260 | of_allnodes = np; | 1334 | of_allnodes = np; |
1261 | write_unlock_irqrestore(&devtree_lock, flags); | 1335 | write_unlock_irqrestore(&devtree_lock, flags); |
1336 | |||
1337 | of_add_proc_dt_entry(np); | ||
1338 | return 0; | ||
1262 | } | 1339 | } |
1263 | 1340 | ||
1341 | #ifdef CONFIG_PROC_DEVICETREE | ||
1342 | static void of_remove_proc_dt_entry(struct device_node *dn) | ||
1343 | { | ||
1344 | struct device_node *parent = dn->parent; | ||
1345 | struct property *prop = dn->properties; | ||
1346 | |||
1347 | while (prop) { | ||
1348 | remove_proc_entry(prop->name, dn->pde); | ||
1349 | prop = prop->next; | ||
1350 | } | ||
1351 | |||
1352 | if (dn->pde) | ||
1353 | remove_proc_entry(dn->pde->name, parent->pde); | ||
1354 | } | ||
1355 | #else | ||
1356 | static void of_remove_proc_dt_entry(struct device_node *dn) | ||
1357 | { | ||
1358 | return; | ||
1359 | } | ||
1360 | #endif | ||
1361 | |||
1264 | /** | 1362 | /** |
1265 | * of_detach_node - "Unplug" a node from the device tree. | 1363 | * of_detach_node - "Unplug" a node from the device tree. |
1266 | * | 1364 | * |
1267 | * The caller must hold a reference to the node. The memory associated with | 1365 | * The caller must hold a reference to the node. The memory associated with |
1268 | * the node is not freed until its refcount goes to zero. | 1366 | * the node is not freed until its refcount goes to zero. |
1269 | */ | 1367 | */ |
1270 | void of_detach_node(struct device_node *np) | 1368 | int of_detach_node(struct device_node *np) |
1271 | { | 1369 | { |
1272 | struct device_node *parent; | 1370 | struct device_node *parent; |
1273 | unsigned long flags; | 1371 | unsigned long flags; |
1372 | int rc = 0; | ||
1373 | |||
1374 | rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); | ||
1375 | if (rc) | ||
1376 | return rc; | ||
1274 | 1377 | ||
1275 | write_lock_irqsave(&devtree_lock, flags); | 1378 | write_lock_irqsave(&devtree_lock, flags); |
1276 | 1379 | ||
1380 | if (of_node_check_flag(np, OF_DETACHED)) { | ||
1381 | /* someone already detached it */ | ||
1382 | write_unlock_irqrestore(&devtree_lock, flags); | ||
1383 | return rc; | ||
1384 | } | ||
1385 | |||
1277 | parent = np->parent; | 1386 | parent = np->parent; |
1278 | if (!parent) | 1387 | if (!parent) { |
1279 | goto out_unlock; | 1388 | write_unlock_irqrestore(&devtree_lock, flags); |
1389 | return rc; | ||
1390 | } | ||
1280 | 1391 | ||
1281 | if (of_allnodes == np) | 1392 | if (of_allnodes == np) |
1282 | of_allnodes = np->allnext; | 1393 | of_allnodes = np->allnext; |
@@ -1301,9 +1412,10 @@ void of_detach_node(struct device_node *np) | |||
1301 | } | 1412 | } |
1302 | 1413 | ||
1303 | of_node_set_flag(np, OF_DETACHED); | 1414 | of_node_set_flag(np, OF_DETACHED); |
1304 | |||
1305 | out_unlock: | ||
1306 | write_unlock_irqrestore(&devtree_lock, flags); | 1415 | write_unlock_irqrestore(&devtree_lock, flags); |
1416 | |||
1417 | of_remove_proc_dt_entry(np); | ||
1418 | return rc; | ||
1307 | } | 1419 | } |
1308 | #endif /* defined(CONFIG_OF_DYNAMIC) */ | 1420 | #endif /* defined(CONFIG_OF_DYNAMIC) */ |
1309 | 1421 | ||