device-remove.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. int device_chld_unbind(struct udevice *dev, struct driver *drv)
  19. {
  20. struct udevice *pos, *n;
  21. int ret, saved_ret = 0;
  22. assert(dev);
  23. list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
  24. if (drv && (pos->driver != drv))
  25. continue;
  26. ret = device_unbind(pos);
  27. if (ret && !saved_ret)
  28. saved_ret = ret;
  29. }
  30. return saved_ret;
  31. }
  32. int device_chld_remove(struct udevice *dev, struct driver *drv,
  33. uint flags)
  34. {
  35. struct udevice *pos, *n;
  36. int ret;
  37. assert(dev);
  38. list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
  39. if (drv && (pos->driver != drv))
  40. continue;
  41. ret = device_remove(pos, flags);
  42. if (ret)
  43. return ret;
  44. }
  45. return 0;
  46. }
  47. int device_unbind(struct udevice *dev)
  48. {
  49. const struct driver *drv;
  50. int ret;
  51. if (!dev)
  52. return -EINVAL;
  53. if (dev->flags & DM_FLAG_ACTIVATED)
  54. return -EINVAL;
  55. if (!(dev->flags & DM_FLAG_BOUND))
  56. return -EINVAL;
  57. drv = dev->driver;
  58. assert(drv);
  59. if (drv->unbind) {
  60. ret = drv->unbind(dev);
  61. if (ret)
  62. return ret;
  63. }
  64. ret = device_chld_unbind(dev, NULL);
  65. if (ret)
  66. return ret;
  67. if (dev->flags & DM_FLAG_ALLOC_PDATA) {
  68. free(dev->platdata);
  69. dev->platdata = NULL;
  70. }
  71. if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
  72. free(dev->uclass_platdata);
  73. dev->uclass_platdata = NULL;
  74. }
  75. if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
  76. free(dev->parent_platdata);
  77. dev->parent_platdata = NULL;
  78. }
  79. ret = uclass_unbind_device(dev);
  80. if (ret)
  81. return ret;
  82. if (dev->parent)
  83. list_del(&dev->sibling_node);
  84. devres_release_all(dev);
  85. if (dev->flags & DM_FLAG_NAME_ALLOCED)
  86. free((char *)dev->name);
  87. free(dev);
  88. return 0;
  89. }
  90. /**
  91. * device_free() - Free memory buffers allocated by a device
  92. * @dev: Device that is to be started
  93. */
  94. void device_free(struct udevice *dev)
  95. {
  96. int size;
  97. if (dev->driver->priv_auto_alloc_size) {
  98. free(dev->priv);
  99. dev->priv = NULL;
  100. }
  101. size = dev->uclass->uc_drv->per_device_auto_alloc_size;
  102. if (size) {
  103. free(dev->uclass_priv);
  104. dev->uclass_priv = NULL;
  105. }
  106. if (dev->parent) {
  107. size = dev->parent->driver->per_child_auto_alloc_size;
  108. if (!size) {
  109. size = dev->parent->uclass->uc_drv->
  110. per_child_auto_alloc_size;
  111. }
  112. if (size) {
  113. free(dev->parent_priv);
  114. dev->parent_priv = NULL;
  115. }
  116. }
  117. devres_release_probe(dev);
  118. }
  119. static bool flags_remove(uint flags, uint drv_flags)
  120. {
  121. if ((flags & DM_REMOVE_NORMAL) ||
  122. (flags & (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE))))
  123. return true;
  124. return false;
  125. }
  126. int device_remove(struct udevice *dev, uint flags)
  127. {
  128. const struct driver *drv;
  129. int ret;
  130. if (!dev)
  131. return -EINVAL;
  132. if (!(dev->flags & DM_FLAG_ACTIVATED))
  133. return 0;
  134. drv = dev->driver;
  135. assert(drv);
  136. ret = uclass_pre_remove_device(dev);
  137. if (ret)
  138. return ret;
  139. ret = device_chld_remove(dev, NULL, flags);
  140. if (ret)
  141. goto err;
  142. /*
  143. * Remove the device if called with the "normal" remove flag set,
  144. * or if the remove flag matches any of the drivers remove flags
  145. */
  146. if (drv->remove && flags_remove(flags, drv->flags)) {
  147. ret = drv->remove(dev);
  148. if (ret)
  149. goto err_remove;
  150. }
  151. if (dev->parent && dev->parent->driver->child_post_remove) {
  152. ret = dev->parent->driver->child_post_remove(dev);
  153. if (ret) {
  154. dm_warn("%s: Device '%s' failed child_post_remove()",
  155. __func__, dev->name);
  156. }
  157. }
  158. if (flags_remove(flags, drv->flags)) {
  159. device_free(dev);
  160. dev->seq = -1;
  161. dev->flags &= ~DM_FLAG_ACTIVATED;
  162. }
  163. return ret;
  164. err_remove:
  165. /* We can't put the children back */
  166. dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
  167. __func__, dev->name);
  168. err:
  169. ret = uclass_post_probe_device(dev);
  170. if (ret) {
  171. dm_warn("%s: Device '%s' failed to post_probe on error path\n",
  172. __func__, dev->name);
  173. }
  174. return ret;
  175. }