143-reset-add-shared-resetcontrol-asserts.patch 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. From d25cfe9b4f9663216ce4e011e3f1e7fa669ab58a Mon Sep 17 00:00:00 2001
  2. From: Hans de Goede <hdegoede@redhat.com>
  3. Date: Fri, 27 Nov 2015 21:09:05 +0100
  4. Subject: [PATCH] reset: Add shared reset_control_[de]assert variants
  5. Add reset_control_deassert_shared / reset_control_assert_shared
  6. functions which are intended for use by drivers for hw blocks which
  7. (may) share a reset line with another driver / hw block.
  8. Unlike the regular reset_control_[de]assert functions these functions
  9. keep track of how often deassert_shared / assert_shared have been called
  10. and keep the line deasserted as long as deassert has been called more
  11. times than assert.
  12. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  13. ---
  14. Changes in v2:
  15. -This is a new patch in v2 of this patch-set
  16. ---
  17. drivers/reset/core.c | 121 ++++++++++++++++++++++++++++++++++++---
  18. include/linux/reset-controller.h | 2 +
  19. include/linux/reset.h | 2 +
  20. 3 files changed, 116 insertions(+), 9 deletions(-)
  21. --- a/drivers/reset/core.c
  22. +++ b/drivers/reset/core.c
  23. @@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_lis
  24. static LIST_HEAD(reset_controller_list);
  25. /**
  26. + * struct reset_line - a reset line
  27. + * @list: list entry for the reset controllers reset line list
  28. + * @id: ID of the reset line in the reset controller device
  29. + * @refcnt: Number of reset_control structs referencing this device
  30. + * @deassert_cnt: Number of times this reset line has been deasserted
  31. + */
  32. +struct reset_line {
  33. + struct list_head list;
  34. + unsigned int id;
  35. + unsigned int refcnt;
  36. + unsigned int deassert_cnt;
  37. +};
  38. +
  39. +/**
  40. * struct reset_control - a reset control
  41. * @rcdev: a pointer to the reset controller device
  42. * this reset control belongs to
  43. - * @id: ID of the reset controller in the reset
  44. - * controller device
  45. + * @line: reset line for this reset control
  46. */
  47. struct reset_control {
  48. struct reset_controller_dev *rcdev;
  49. + struct reset_line *line;
  50. struct device *dev;
  51. - unsigned int id;
  52. };
  53. /**
  54. @@ -66,6 +79,8 @@ int reset_controller_register(struct res
  55. rcdev->of_xlate = of_reset_simple_xlate;
  56. }
  57. + INIT_LIST_HEAD(&rcdev->reset_line_head);
  58. +
  59. mutex_lock(&reset_controller_list_mutex);
  60. list_add(&rcdev->list, &reset_controller_list);
  61. mutex_unlock(&reset_controller_list_mutex);
  62. @@ -93,7 +108,7 @@ EXPORT_SYMBOL_GPL(reset_controller_unreg
  63. int reset_control_reset(struct reset_control *rstc)
  64. {
  65. if (rstc->rcdev->ops->reset)
  66. - return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
  67. + return rstc->rcdev->ops->reset(rstc->rcdev, rstc->line->id);
  68. return -ENOTSUPP;
  69. }
  70. @@ -106,7 +121,7 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
  71. int reset_control_assert(struct reset_control *rstc)
  72. {
  73. if (rstc->rcdev->ops->assert)
  74. - return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
  75. + return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
  76. return -ENOTSUPP;
  77. }
  78. @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
  79. int reset_control_deassert(struct reset_control *rstc)
  80. {
  81. if (rstc->rcdev->ops->deassert)
  82. - return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
  83. + return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
  84. return -ENOTSUPP;
  85. }
  86. EXPORT_SYMBOL_GPL(reset_control_deassert);
  87. /**
  88. + * reset_control_assert_shared - asserts a shared reset line
  89. + * @rstc: reset controller
  90. + *
  91. + * Assert a shared reset line, this functions decreases the deassert count
  92. + * of the line by one and asserts it if, and only if, the deassert count
  93. + * reaches 0.
  94. + */
  95. +int reset_control_assert_shared(struct reset_control *rstc)
  96. +{
  97. + if (!rstc->rcdev->ops->assert)
  98. + return -ENOTSUPP;
  99. +
  100. + rstc->line->deassert_cnt--;
  101. + if (rstc->line->deassert_cnt)
  102. + return 0;
  103. +
  104. + return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
  105. +}
  106. +EXPORT_SYMBOL_GPL(reset_control_assert_shared);
  107. +
  108. +/**
  109. + * reset_control_deassert_shared - deasserts a shared reset line
  110. + * @rstc: reset controller
  111. + *
  112. + * Assert a shared reset line, this functions increases the deassert count
  113. + * of the line by one and deasserts the reset line (if it was not already
  114. + * deasserted).
  115. + */
  116. +int reset_control_deassert_shared(struct reset_control *rstc)
  117. +{
  118. + if (!rstc->rcdev->ops->deassert)
  119. + return -ENOTSUPP;
  120. +
  121. + rstc->line->deassert_cnt++;
  122. + if (rstc->line->deassert_cnt != 1)
  123. + return 0;
  124. +
  125. + return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
  126. +}
  127. +EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
  128. +
  129. +/**
  130. * reset_control_status - returns a negative errno if not supported, a
  131. * positive value if the reset line is asserted, or zero if the reset
  132. * line is not asserted.
  133. @@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert
  134. int reset_control_status(struct reset_control *rstc)
  135. {
  136. if (rstc->rcdev->ops->status)
  137. - return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
  138. + return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
  139. return -ENOTSUPP;
  140. }
  141. EXPORT_SYMBOL_GPL(reset_control_status);
  142. +static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
  143. + unsigned int index)
  144. +{
  145. + struct reset_line *line;
  146. +
  147. + list_for_each_entry(line, &rcdev->reset_line_head, list) {
  148. + if (line->id == index) {
  149. + line->refcnt++;
  150. + return line;
  151. + }
  152. + }
  153. +
  154. + line = kzalloc(sizeof(*line), GFP_KERNEL);
  155. + if (!line)
  156. + return NULL;
  157. +
  158. + list_add(&line->list, &rcdev->reset_line_head);
  159. + line->id = index;
  160. + line->refcnt = 1;
  161. +
  162. + return line;
  163. +}
  164. +
  165. +static void reset_line_put(struct reset_line *line)
  166. +{
  167. + if (!line)
  168. + return;
  169. +
  170. + if (--line->refcnt)
  171. + return;
  172. +
  173. + list_del(&line->list);
  174. + kfree(line);
  175. +}
  176. +
  177. /**
  178. * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
  179. * controller by index.
  180. @@ -155,6 +247,7 @@ struct reset_control *of_reset_control_g
  181. {
  182. struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
  183. struct reset_controller_dev *r, *rcdev;
  184. + struct reset_line *line;
  185. struct of_phandle_args args;
  186. int rstc_id;
  187. int ret;
  188. @@ -186,16 +279,22 @@ struct reset_control *of_reset_control_g
  189. }
  190. try_module_get(rcdev->owner);
  191. +
  192. + /* reset_controller_list_mutex also protects the reset_line list */
  193. + line = reset_line_get(rcdev, rstc_id);
  194. +
  195. mutex_unlock(&reset_controller_list_mutex);
  196. rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
  197. - if (!rstc) {
  198. + if (!line || !rstc) {
  199. + kfree(rstc);
  200. + reset_line_put(line);
  201. module_put(rcdev->owner);
  202. return ERR_PTR(-ENOMEM);
  203. }
  204. rstc->rcdev = rcdev;
  205. - rstc->id = rstc_id;
  206. + rstc->line = line;
  207. return rstc;
  208. }
  209. @@ -259,6 +358,10 @@ void reset_control_put(struct reset_cont
  210. if (IS_ERR(rstc))
  211. return;
  212. + mutex_lock(&reset_controller_list_mutex);
  213. + reset_line_put(rstc->line);
  214. + mutex_unlock(&reset_controller_list_mutex);
  215. +
  216. module_put(rstc->rcdev->owner);
  217. kfree(rstc);
  218. }
  219. --- a/include/linux/reset-controller.h
  220. +++ b/include/linux/reset-controller.h
  221. @@ -31,6 +31,7 @@ struct of_phandle_args;
  222. * @ops: a pointer to device specific struct reset_control_ops
  223. * @owner: kernel module of the reset controller driver
  224. * @list: internal list of reset controller devices
  225. + * @reset_line_head: head of internal list of reset lines
  226. * @of_node: corresponding device tree node as phandle target
  227. * @of_reset_n_cells: number of cells in reset line specifiers
  228. * @of_xlate: translation function to translate from specifier as found in the
  229. @@ -41,6 +42,7 @@ struct reset_controller_dev {
  230. struct reset_control_ops *ops;
  231. struct module *owner;
  232. struct list_head list;
  233. + struct list_head reset_line_head;
  234. struct device_node *of_node;
  235. int of_reset_n_cells;
  236. int (*of_xlate)(struct reset_controller_dev *rcdev,
  237. --- a/include/linux/reset.h
  238. +++ b/include/linux/reset.h
  239. @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_con
  240. int reset_control_assert(struct reset_control *rstc);
  241. int reset_control_deassert(struct reset_control *rstc);
  242. int reset_control_status(struct reset_control *rstc);
  243. +int reset_control_assert_shared(struct reset_control *rstc);
  244. +int reset_control_deassert_shared(struct reset_control *rstc);
  245. struct reset_control *reset_control_get(struct device *dev, const char *id);
  246. void reset_control_put(struct reset_control *rstc);