aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@linaro.org>2014-06-24 11:13:47 -0400
committerGrant Likely <grant.likely@linaro.org>2014-07-07 08:33:46 -0400
commit75f353b61342b5847c7f6d8499fd6301dce09845 (patch)
tree39181c9145ae4a6625128a9b81ebbac2011429eb
parentcd3de83f147601356395b57a8673e9c5ff1e59d1 (diff)
of/platform: Fix of_platform_device_destroy iteration of devices
of_platform_destroy does not work properly, since the tree population test was iterating on all devices having as its parent the given platform device. The check was intended to check whether any other platform or amba devices created by of_platform_populate were still populated, but instead checked for every kind of device. This is wrong, since platform devices typically create a subsystem regular device and set themselves as parents. Instead, go ahead and call the unregister functions for any devices created with of_platform_populate. The driver core will take care of unbinding drivers, and drivers are responsible for getting rid of any child devices that weren't created by of_platform_populate. Signed-off-by: Grant Likely <grant.likely@linaro.org> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
-rw-r--r--drivers/of/platform.c32
-rw-r--r--include/linux/of.h1
-rw-r--r--include/linux/of_platform.h7
3 files changed, 12 insertions, 28 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 500436f9be7f..0197725e033a 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -422,6 +422,7 @@ static int of_platform_bus_create(struct device_node *bus,
422 break; 422 break;
423 } 423 }
424 } 424 }
425 of_node_set_flag(bus, OF_POPULATED_BUS);
425 return rc; 426 return rc;
426} 427}
427 428
@@ -508,19 +509,13 @@ EXPORT_SYMBOL_GPL(of_platform_populate);
508 509
509static int of_platform_device_destroy(struct device *dev, void *data) 510static int of_platform_device_destroy(struct device *dev, void *data)
510{ 511{
511 bool *children_left = data;
512
513 /* Do not touch devices not populated from the device tree */ 512 /* Do not touch devices not populated from the device tree */
514 if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED)) { 513 if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
515 *children_left = true;
516 return 0; 514 return 0;
517 }
518 515
519 /* Recurse, but don't touch this device if it has any children left */ 516 /* Recurse for any nodes that were treated as busses */
520 if (of_platform_depopulate(dev) != 0) { 517 if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS))
521 *children_left = true; 518 device_for_each_child(dev, NULL, of_platform_device_destroy);
522 return 0;
523 }
524 519
525 if (dev->bus == &platform_bus_type) 520 if (dev->bus == &platform_bus_type)
526 platform_device_unregister(to_platform_device(dev)); 521 platform_device_unregister(to_platform_device(dev));
@@ -528,19 +523,15 @@ static int of_platform_device_destroy(struct device *dev, void *data)
528 else if (dev->bus == &amba_bustype) 523 else if (dev->bus == &amba_bustype)
529 amba_device_unregister(to_amba_device(dev)); 524 amba_device_unregister(to_amba_device(dev));
530#endif 525#endif
531 else {
532 *children_left = true;
533 return 0;
534 }
535 526
536 of_node_clear_flag(dev->of_node, OF_POPULATED); 527 of_node_clear_flag(dev->of_node, OF_POPULATED);
537 528 of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
538 return 0; 529 return 0;
539} 530}
540 531
541/** 532/**
542 * of_platform_depopulate() - Remove devices populated from device tree 533 * of_platform_depopulate() - Remove devices populated from device tree
543 * @parent: device which childred will be removed 534 * @parent: device which children will be removed
544 * 535 *
545 * Complementary to of_platform_populate(), this function removes children 536 * Complementary to of_platform_populate(), this function removes children
546 * of the given device (and, recurrently, their children) that have been 537 * of the given device (and, recurrently, their children) that have been
@@ -550,14 +541,9 @@ static int of_platform_device_destroy(struct device *dev, void *data)
550 * Returns 0 when all children devices have been removed or 541 * Returns 0 when all children devices have been removed or
551 * -EBUSY when some children remained. 542 * -EBUSY when some children remained.
552 */ 543 */
553int of_platform_depopulate(struct device *parent) 544void of_platform_depopulate(struct device *parent)
554{ 545{
555 bool children_left = false; 546 device_for_each_child(parent, NULL, of_platform_device_destroy);
556
557 device_for_each_child(parent, &children_left,
558 of_platform_device_destroy);
559
560 return children_left ? -EBUSY : 0;
561} 547}
562EXPORT_SYMBOL_GPL(of_platform_depopulate); 548EXPORT_SYMBOL_GPL(of_platform_depopulate);
563 549
diff --git a/include/linux/of.h b/include/linux/of.h
index 196b34c1ef4e..abf829a1f150 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -204,6 +204,7 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
204#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ 204#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
205#define OF_DETACHED 2 /* node has been detached from the device tree */ 205#define OF_DETACHED 2 /* node has been detached from the device tree */
206#define OF_POPULATED 3 /* device already created for the node */ 206#define OF_POPULATED 3 /* device already created for the node */
207#define OF_POPULATED_BUS 4 /* of_platform_populate recursed to children of this node */
207 208
208#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) 209#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
209#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) 210#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index d96e1badbee0..c2b0627a2317 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -72,7 +72,7 @@ extern int of_platform_populate(struct device_node *root,
72 const struct of_device_id *matches, 72 const struct of_device_id *matches,
73 const struct of_dev_auxdata *lookup, 73 const struct of_dev_auxdata *lookup,
74 struct device *parent); 74 struct device *parent);
75extern int of_platform_depopulate(struct device *parent); 75extern void of_platform_depopulate(struct device *parent);
76#else 76#else
77static inline int of_platform_populate(struct device_node *root, 77static inline int of_platform_populate(struct device_node *root,
78 const struct of_device_id *matches, 78 const struct of_device_id *matches,
@@ -81,10 +81,7 @@ static inline int of_platform_populate(struct device_node *root,
81{ 81{
82 return -ENODEV; 82 return -ENODEV;
83} 83}
84static inline int of_platform_depopulate(struct device *parent) 84static inline void of_platform_depopulate(struct device *parent) { }
85{
86 return -ENODEV;
87}
88#endif 85#endif
89 86
90#endif /* _LINUX_OF_PLATFORM_H */ 87#endif /* _LINUX_OF_PLATFORM_H */