ozeltbuf.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /* -----------------------------------------------------------------------------
  2. * Copyright (c) 2011 Ozmo Inc
  3. * Released under the GNU General Public License Version 2 (GPLv2).
  4. * -----------------------------------------------------------------------------
  5. */
  6. #include <linux/module.h>
  7. #include <linux/netdevice.h>
  8. #include "ozdbg.h"
  9. #include "ozprotocol.h"
  10. #include "ozeltbuf.h"
  11. #include "ozpd.h"
  12. /*
  13. * Context: softirq-serialized
  14. */
  15. void oz_elt_buf_init(struct oz_elt_buf *buf)
  16. {
  17. memset(buf, 0, sizeof(struct oz_elt_buf));
  18. INIT_LIST_HEAD(&buf->stream_list);
  19. INIT_LIST_HEAD(&buf->order_list);
  20. INIT_LIST_HEAD(&buf->isoc_list);
  21. spin_lock_init(&buf->lock);
  22. }
  23. /*
  24. * Context: softirq or process
  25. */
  26. void oz_elt_buf_term(struct oz_elt_buf *buf)
  27. {
  28. struct oz_elt_info *ei, *n;
  29. list_for_each_entry_safe(ei, n, &buf->isoc_list, link_order)
  30. kfree(ei);
  31. list_for_each_entry_safe(ei, n, &buf->order_list, link_order)
  32. kfree(ei);
  33. }
  34. /*
  35. * Context: softirq or process
  36. */
  37. struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf)
  38. {
  39. struct oz_elt_info *ei;
  40. ei = kmem_cache_zalloc(oz_elt_info_cache, GFP_ATOMIC);
  41. if (ei) {
  42. INIT_LIST_HEAD(&ei->link);
  43. INIT_LIST_HEAD(&ei->link_order);
  44. }
  45. return ei;
  46. }
  47. /*
  48. * Precondition: oz_elt_buf.lock must be held.
  49. * Context: softirq or process
  50. */
  51. void oz_elt_info_free(struct oz_elt_buf *buf, struct oz_elt_info *ei)
  52. {
  53. if (ei)
  54. kmem_cache_free(oz_elt_info_cache, ei);
  55. }
  56. /*------------------------------------------------------------------------------
  57. * Context: softirq
  58. */
  59. void oz_elt_info_free_chain(struct oz_elt_buf *buf, struct list_head *list)
  60. {
  61. struct oz_elt_info *ei, *n;
  62. spin_lock_bh(&buf->lock);
  63. list_for_each_entry_safe(ei, n, list->next, link)
  64. oz_elt_info_free(buf, ei);
  65. spin_unlock_bh(&buf->lock);
  66. }
  67. int oz_elt_stream_create(struct oz_elt_buf *buf, u8 id, int max_buf_count)
  68. {
  69. struct oz_elt_stream *st;
  70. oz_dbg(ON, "%s: (0x%x)\n", __func__, id);
  71. st = kzalloc(sizeof(struct oz_elt_stream), GFP_ATOMIC);
  72. if (st == NULL)
  73. return -ENOMEM;
  74. atomic_set(&st->ref_count, 1);
  75. st->id = id;
  76. st->max_buf_count = max_buf_count;
  77. INIT_LIST_HEAD(&st->elt_list);
  78. spin_lock_bh(&buf->lock);
  79. list_add_tail(&st->link, &buf->stream_list);
  80. spin_unlock_bh(&buf->lock);
  81. return 0;
  82. }
  83. int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id)
  84. {
  85. struct list_head *e, *n;
  86. struct oz_elt_stream *st = NULL;
  87. oz_dbg(ON, "%s: (0x%x)\n", __func__, id);
  88. spin_lock_bh(&buf->lock);
  89. list_for_each(e, &buf->stream_list) {
  90. st = list_entry(e, struct oz_elt_stream, link);
  91. if (st->id == id) {
  92. list_del(e);
  93. break;
  94. }
  95. st = NULL;
  96. }
  97. if (!st) {
  98. spin_unlock_bh(&buf->lock);
  99. return -1;
  100. }
  101. list_for_each_safe(e, n, &st->elt_list) {
  102. struct oz_elt_info *ei =
  103. list_entry(e, struct oz_elt_info, link);
  104. list_del_init(&ei->link);
  105. list_del_init(&ei->link_order);
  106. st->buf_count -= ei->length;
  107. oz_dbg(STREAM, "Stream down: %d %d %d\n",
  108. st->buf_count, ei->length, atomic_read(&st->ref_count));
  109. oz_elt_stream_put(st);
  110. oz_elt_info_free(buf, ei);
  111. }
  112. spin_unlock_bh(&buf->lock);
  113. oz_elt_stream_put(st);
  114. return 0;
  115. }
  116. void oz_elt_stream_get(struct oz_elt_stream *st)
  117. {
  118. atomic_inc(&st->ref_count);
  119. }
  120. void oz_elt_stream_put(struct oz_elt_stream *st)
  121. {
  122. if (atomic_dec_and_test(&st->ref_count)) {
  123. oz_dbg(ON, "Stream destroyed\n");
  124. kfree(st);
  125. }
  126. }
  127. /*
  128. * Precondition: Element buffer lock must be held.
  129. * If this function fails the caller is responsible for deallocating the elt
  130. * info structure.
  131. */
  132. int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id,
  133. struct oz_elt_info *ei)
  134. {
  135. struct oz_elt_stream *st = NULL;
  136. struct list_head *e;
  137. if (id) {
  138. list_for_each(e, &buf->stream_list) {
  139. st = list_entry(e, struct oz_elt_stream, link);
  140. if (st->id == id)
  141. break;
  142. }
  143. if (e == &buf->stream_list) {
  144. /* Stream specified but stream not known so fail.
  145. * Caller deallocates element info. */
  146. return -1;
  147. }
  148. }
  149. if (st) {
  150. /* If this is an ISOC fixed element that needs a frame number
  151. * then insert that now. Earlier we stored the unit count in
  152. * this field.
  153. */
  154. struct oz_isoc_fixed *body = (struct oz_isoc_fixed *)
  155. &ei->data[sizeof(struct oz_elt)];
  156. if ((body->app_id == OZ_APPID_USB) && (body->type
  157. == OZ_USB_ENDPOINT_DATA) &&
  158. (body->format == OZ_DATA_F_ISOC_FIXED)) {
  159. u8 unit_count = body->frame_number;
  160. body->frame_number = st->frame_number;
  161. st->frame_number += unit_count;
  162. }
  163. /* Claim stream and update accounts */
  164. oz_elt_stream_get(st);
  165. ei->stream = st;
  166. st->buf_count += ei->length;
  167. /* Add to list in stream. */
  168. list_add_tail(&ei->link, &st->elt_list);
  169. oz_dbg(STREAM, "Stream up: %d %d\n", st->buf_count, ei->length);
  170. /* Check if we have too much buffered for this stream. If so
  171. * start dropping elements until we are back in bounds.
  172. */
  173. while ((st->buf_count > st->max_buf_count) &&
  174. !list_empty(&st->elt_list)) {
  175. struct oz_elt_info *ei2 =
  176. list_first_entry(&st->elt_list,
  177. struct oz_elt_info, link);
  178. list_del_init(&ei2->link);
  179. list_del_init(&ei2->link_order);
  180. st->buf_count -= ei2->length;
  181. oz_elt_info_free(buf, ei2);
  182. oz_elt_stream_put(st);
  183. }
  184. }
  185. list_add_tail(&ei->link_order, isoc ?
  186. &buf->isoc_list : &buf->order_list);
  187. return 0;
  188. }
  189. int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len,
  190. unsigned max_len, struct list_head *list)
  191. {
  192. int count = 0;
  193. struct list_head *el;
  194. struct oz_elt_info *ei, *n;
  195. spin_lock_bh(&buf->lock);
  196. if (isoc)
  197. el = &buf->isoc_list;
  198. else
  199. el = &buf->order_list;
  200. list_for_each_entry_safe(ei, n, el, link_order) {
  201. if ((*len + ei->length) <= max_len) {
  202. struct oz_app_hdr *app_hdr = (struct oz_app_hdr *)
  203. &ei->data[sizeof(struct oz_elt)];
  204. app_hdr->elt_seq_num = buf->tx_seq_num[ei->app_id]++;
  205. if (buf->tx_seq_num[ei->app_id] == 0)
  206. buf->tx_seq_num[ei->app_id] = 1;
  207. *len += ei->length;
  208. list_del(&ei->link);
  209. list_del(&ei->link_order);
  210. if (ei->stream) {
  211. ei->stream->buf_count -= ei->length;
  212. oz_dbg(STREAM, "Stream down: %d %d\n",
  213. ei->stream->buf_count, ei->length);
  214. oz_elt_stream_put(ei->stream);
  215. ei->stream = NULL;
  216. }
  217. INIT_LIST_HEAD(&ei->link_order);
  218. list_add_tail(&ei->link, list);
  219. count++;
  220. } else {
  221. break;
  222. }
  223. }
  224. spin_unlock_bh(&buf->lock);
  225. return count;
  226. }
  227. int oz_are_elts_available(struct oz_elt_buf *buf)
  228. {
  229. return !list_empty(&buf->order_list);
  230. }