Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

of/overlay: add of overlay notifications

This patch add of overlay notifications.

When DT overlays are being added, some drivers/subsystems
need to see device tree overlays before the changes go into
the live tree.

This is distinct from reconfig notifiers that are
post-apply or post-remove and which issue very granular
notifications without providing access to the context
of a whole overlay.

The following 4 notificatons are issued:
OF_OVERLAY_PRE_APPLY
OF_OVERLAY_POST_APPLY
OF_OVERLAY_PRE_REMOVE
OF_OVERLAY_POST_REMOVE

In the case of pre-apply notification, if the notifier
returns error, the overlay will be rejected.

This patch exports two functions for registering/unregistering
notifications:
of_overlay_notifier_register(struct notifier_block *nb)
of_overlay_notifier_unregister(struct notifier_block *nb)

The of_mutex is held during these notifications. The
notification data includes pointers to the overlay target
and the overlay:

struct of_overlay_notify_data {
struct device_node *overlay;
struct device_node *target;
};

Signed-off-by: Alan Tull <atull@opensource.altera.com>
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Moritz Fischer <moritz.fischer@ettus.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Tull and committed by
Greg Kroah-Hartman
39a842e2 c1eac0d0

+71 -1
+46 -1
drivers/of/overlay.c
··· 58 58 static int of_overlay_apply_one(struct of_overlay *ov, 59 59 struct device_node *target, const struct device_node *overlay); 60 60 61 + static BLOCKING_NOTIFIER_HEAD(of_overlay_chain); 62 + 63 + int of_overlay_notifier_register(struct notifier_block *nb) 64 + { 65 + return blocking_notifier_chain_register(&of_overlay_chain, nb); 66 + } 67 + EXPORT_SYMBOL_GPL(of_overlay_notifier_register); 68 + 69 + int of_overlay_notifier_unregister(struct notifier_block *nb) 70 + { 71 + return blocking_notifier_chain_unregister(&of_overlay_chain, nb); 72 + } 73 + EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister); 74 + 75 + static int of_overlay_notify(struct of_overlay *ov, 76 + enum of_overlay_notify_action action) 77 + { 78 + struct of_overlay_notify_data nd; 79 + int i, ret; 80 + 81 + for (i = 0; i < ov->count; i++) { 82 + struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i]; 83 + 84 + nd.target = ovinfo->target; 85 + nd.overlay = ovinfo->overlay; 86 + 87 + ret = blocking_notifier_call_chain(&of_overlay_chain, 88 + action, &nd); 89 + if (ret) 90 + return notifier_to_errno(ret); 91 + } 92 + 93 + return 0; 94 + } 95 + 61 96 static int of_overlay_apply_single_property(struct of_overlay *ov, 62 97 struct device_node *target, struct property *prop) 63 98 { ··· 403 368 goto err_free_idr; 404 369 } 405 370 371 + err = of_overlay_notify(ov, OF_OVERLAY_PRE_APPLY); 372 + if (err < 0) { 373 + pr_err("%s: Pre-apply notifier failed (err=%d)\n", 374 + __func__, err); 375 + goto err_free_idr; 376 + } 377 + 406 378 /* apply the overlay */ 407 379 err = of_overlay_apply(ov); 408 380 if (err) ··· 423 381 424 382 /* add to the tail of the overlay list */ 425 383 list_add_tail(&ov->node, &ov_list); 384 + 385 + of_overlay_notify(ov, OF_OVERLAY_POST_APPLY); 426 386 427 387 mutex_unlock(&of_mutex); 428 388 ··· 542 498 goto out; 543 499 } 544 500 545 - 501 + of_overlay_notify(ov, OF_OVERLAY_PRE_REMOVE); 546 502 list_del(&ov->node); 547 503 __of_changeset_revert(&ov->cset); 504 + of_overlay_notify(ov, OF_OVERLAY_POST_REMOVE); 548 505 of_free_overlay_info(ov); 549 506 idr_remove(&ov_idr, id); 550 507 of_changeset_destroy(&ov->cset);
+25
include/linux/of.h
··· 1266 1266 * Overlay support 1267 1267 */ 1268 1268 1269 + enum of_overlay_notify_action { 1270 + OF_OVERLAY_PRE_APPLY, 1271 + OF_OVERLAY_POST_APPLY, 1272 + OF_OVERLAY_PRE_REMOVE, 1273 + OF_OVERLAY_POST_REMOVE, 1274 + }; 1275 + 1276 + struct of_overlay_notify_data { 1277 + struct device_node *overlay; 1278 + struct device_node *target; 1279 + }; 1280 + 1269 1281 #ifdef CONFIG_OF_OVERLAY 1270 1282 1271 1283 /* ID based overlays; the API for external users */ 1272 1284 int of_overlay_create(struct device_node *tree); 1273 1285 int of_overlay_destroy(int id); 1274 1286 int of_overlay_destroy_all(void); 1287 + 1288 + int of_overlay_notifier_register(struct notifier_block *nb); 1289 + int of_overlay_notifier_unregister(struct notifier_block *nb); 1275 1290 1276 1291 #else 1277 1292 ··· 1303 1288 static inline int of_overlay_destroy_all(void) 1304 1289 { 1305 1290 return -ENOTSUPP; 1291 + } 1292 + 1293 + static inline int of_overlay_notifier_register(struct notifier_block *nb) 1294 + { 1295 + return 0; 1296 + } 1297 + 1298 + static inline int of_overlay_notifier_unregister(struct notifier_block *nb) 1299 + { 1300 + return 0; 1306 1301 } 1307 1302 1308 1303 #endif