device-remove.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Device manager
  4. *
  5. * Copyright (c) 2014 Google, Inc
  6. *
  7. * (C) Copyright 2012
  8. * Pavel Herrmann <morpheus.ibis@gmail.com>
  9. */
  10. #include <common.h>
  11. #include <errno.h>
  12. #include <malloc.h>
  13. #include <dm/device.h>
  14. #include <dm/device-internal.h>
  15. #include <dm/uclass.h>
  16. #include <dm/uclass-internal.h>
  17. #include <dm/util.h>
  18. /**
  19. * device_chld_unbind() - Unbind all device's children from the device
  20. *
  21. * On error, the function continues to unbind all children, and reports the
  22. * first error.
  23. *
  24. * @dev: The device that is to be stripped of its children
  25. * @return 0 on success, -ve on error
  26. */
  27. static int device_chld_unbind(struct udevice *dev)
  28. {
  29. struct udevice *pos, *n;
  30. int ret, saved_ret = 0;
  31. assert(dev);
  32. list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
  33. ret = device_unbind(pos);
  34. if (ret && !saved_ret)
  35. saved_ret = ret;
  36. }
  37. return saved_ret;
  38. }
  39. /**
  40. * device_chld_remove() - Stop all device's children
  41. * @dev: The device whose children are to be removed
  42. * @pre_os_remove: Flag, if this functions is called in the pre-OS stage
  43. * @return 0 on success, -ve on error
  44. */
  45. static int device_chld_remove(struct udevice *dev, uint flags)
  46. {
  47. struct udevice *pos, *n;
  48. int ret;
  49. assert(dev);
  50. list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
  51. ret = device_remove(pos, flags);
  52. if (ret)
  53. return ret;
  54. }
  55. return 0;
  56. }
  57. int device_unbind(struct udevice *dev)
  58. {
  59. const struct driver *drv;
  60. int ret;
  61. if (!dev)
  62. return -EINVAL;
  63. if (dev->flags & DM_FLAG_ACTIVATED)
  64. return -EINVAL;
  65. if (!(dev->flags & DM_FLAG_BOUND))
  66. return -EINVAL;
  67. drv = dev->driver;
  68. assert(drv);
  69. if (drv->unbind) {
  70. ret = drv->unbind(dev);
  71. if (ret)
  72. return ret;
  73. }
  74. ret = device_chld_unbind(dev);
  75. if (ret)
  76. return ret;
  77. if (dev->flags & DM_FLAG_ALLOC_PDATA) {
  78. free(dev->platdata);
  79. dev->platdata = NULL;
  80. }
  81. if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
  82. free(dev->uclass_platdata);
  83. dev->uclass_platdata = NULL;
  84. }
  85. if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
  86. free(dev->parent_platdata);
  87. dev->parent_platdata = NULL;
  88. }
  89. ret = uclass_unbind_device(dev);
  90. if (ret)
  91. return ret;
  92. if (dev->parent)
  93. list_del(&dev->sibling_node);
  94. devres_release_all(dev);
  95. if (dev->flags & DM_FLAG_NAME_ALLOCED)
  96. free((char *)dev->name);
  97. free(dev);
  98. return 0;
  99. }
  100. /**
  101. * device_free() - Free memory buffers allocated by a device
  102. * @dev: Device that is to be started
  103. */
  104. void device_free(struct udevice *dev)
  105. {
  106. int size;
  107. if (dev->driver->priv_auto_alloc_size) {
  108. free(dev->priv);
  109. dev->priv = NULL;
  110. }
  111. size = dev->uclass->uc_drv->per_device_auto_alloc_size;
  112. if (size) {
  113. free(dev->uclass_priv);
  114. dev->uclass_priv = NULL;
  115. }
  116. if (dev->parent) {
  117. size = dev->parent->driver->per_child_auto_alloc_size;
  118. if (!size) {
  119. size = dev->parent->uclass->uc_drv->
  120. per_child_auto_alloc_size;
  121. }
  122. if (size) {
  123. free(dev->parent_priv);
  124. dev->parent_priv = NULL;
  125. }
  126. }
  127. devres_release_probe(dev);
  128. }
  129. static bool flags_remove(uint flags, uint drv_flags)
  130. {
  131. if ((flags & DM_REMOVE_NORMAL) ||
  132. (flags & (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE))))
  133. return true;
  134. return false;
  135. }
  136. int device_remove(struct udevice *dev, uint flags)
  137. {
  138. const struct driver *drv;
  139. int ret;
  140. if (!dev)
  141. return -EINVAL;
  142. if (!(dev->flags & DM_FLAG_ACTIVATED))
  143. return 0;
  144. drv = dev->driver;
  145. assert(drv);
  146. ret = uclass_pre_remove_device(dev);
  147. if (ret)
  148. return ret;
  149. ret = device_chld_remove(dev, flags);
  150. if (ret)
  151. goto err;
  152. /*
  153. * Remove the device if called with the "normal" remove flag set,
  154. * or if the remove flag matches any of the drivers remove flags
  155. */
  156. if (drv->remove && flags_remove(flags, drv->flags)) {
  157. ret = drv->remove(dev);
  158. if (ret)
  159. goto err_remove;
  160. }
  161. if (dev->parent && dev->parent->driver->child_post_remove) {
  162. ret = dev->parent->driver->child_post_remove(dev);
  163. if (ret) {
  164. dm_warn("%s: Device '%s' failed child_post_remove()",
  165. __func__, dev->name);
  166. }
  167. }
  168. if (flags_remove(flags, drv->flags)) {
  169. device_free(dev);
  170. dev->seq = -1;
  171. dev->flags &= ~DM_FLAG_ACTIVATED;
  172. }
  173. return ret;
  174. err_remove:
  175. /* We can't put the children back */
  176. dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
  177. __func__, dev->name);
  178. err:
  179. ret = uclass_post_probe_device(dev);
  180. if (ret) {
  181. dm_warn("%s: Device '%s' failed to post_probe on error path\n",
  182. __func__, dev->name);
  183. }
  184. return ret;
  185. }