usb-tx.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Intel Wireless WiMAX Connection 2400m
  3. * USB specific TX handling
  4. *
  5. *
  6. * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * * Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. * * Neither the name of Intel Corporation nor the names of its
  19. * contributors may be used to endorse or promote products derived
  20. * from this software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. *
  35. * Intel Corporation <linux-wimax@intel.com>
  36. * Yanir Lubetkin <yanirx.lubetkin@intel.com>
  37. * - Initial implementation
  38. * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
  39. * - Split transport/device specific
  40. *
  41. *
  42. * Takes the TX messages in the i2400m's driver TX FIFO and sends them
  43. * to the device until there are no more.
  44. *
  45. * If we fail sending the message, we just drop it. There isn't much
  46. * we can do at this point. We could also retry, but the USB stack has
  47. * already retried and still failed, so there is not much of a
  48. * point. As well, most of the traffic is network, which has recovery
  49. * methods for dropped packets.
  50. *
  51. * For sending we just obtain a FIFO buffer to send, send it to the
  52. * USB bulk out, tell the TX FIFO code we have sent it; query for
  53. * another one, etc... until done.
  54. *
  55. * We use a thread so we can call usb_autopm_enable() and
  56. * usb_autopm_disable() for each transaction; this way when the device
  57. * goes idle, it will suspend. It also has less overhead than a
  58. * dedicated workqueue, as it is being used for a single task.
  59. *
  60. * ROADMAP
  61. *
  62. * i2400mu_tx_setup()
  63. * i2400mu_tx_release()
  64. *
  65. * i2400mu_bus_tx_kick() - Called by the tx.c code when there
  66. * is new data in the FIFO.
  67. * i2400mu_txd()
  68. * i2400m_tx_msg_get()
  69. * i2400m_tx_msg_sent()
  70. */
  71. #include "i2400m-usb.h"
  72. #define D_SUBMODULE tx
  73. #include "usb-debug-levels.h"
  74. /*
  75. * Get the next TX message in the TX FIFO and send it to the device
  76. *
  77. * Note that any iteration consumes a message to be sent, no matter if
  78. * it succeeds or fails (we have no real way to retry or complain).
  79. *
  80. * Return: 0 if ok, < 0 errno code on hard error.
  81. */
  82. static
  83. int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
  84. size_t tx_msg_size)
  85. {
  86. int result = 0;
  87. struct i2400m *i2400m = &i2400mu->i2400m;
  88. struct device *dev = &i2400mu->usb_iface->dev;
  89. int usb_pipe, sent_size, do_autopm;
  90. struct usb_endpoint_descriptor *epd;
  91. d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
  92. do_autopm = atomic_read(&i2400mu->do_autopm);
  93. result = do_autopm ?
  94. usb_autopm_get_interface(i2400mu->usb_iface) : 0;
  95. if (result < 0) {
  96. dev_err(dev, "TX: can't get autopm: %d\n", result);
  97. do_autopm = 0;
  98. }
  99. epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out);
  100. usb_pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
  101. retry:
  102. result = usb_bulk_msg(i2400mu->usb_dev, usb_pipe,
  103. tx_msg, tx_msg_size, &sent_size, 200);
  104. usb_mark_last_busy(i2400mu->usb_dev);
  105. switch (result) {
  106. case 0:
  107. if (sent_size != tx_msg_size) { /* Too short? drop it */
  108. dev_err(dev, "TX: short write (%d B vs %zu "
  109. "expected)\n", sent_size, tx_msg_size);
  110. result = -EIO;
  111. }
  112. break;
  113. case -EPIPE:
  114. /*
  115. * Stall -- maybe the device is choking with our
  116. * requests. Clear it and give it some time. If they
  117. * happen to often, it might be another symptom, so we
  118. * reset.
  119. *
  120. * No error handling for usb_clear_halt(0; if it
  121. * works, the retry works; if it fails, this switch
  122. * does the error handling for us.
  123. */
  124. if (edc_inc(&i2400mu->urb_edc,
  125. 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
  126. dev_err(dev, "BM-CMD: too many stalls in "
  127. "URB; resetting device\n");
  128. usb_queue_reset_device(i2400mu->usb_iface);
  129. } else {
  130. usb_clear_halt(i2400mu->usb_dev, usb_pipe);
  131. msleep(10); /* give the device some time */
  132. goto retry;
  133. }
  134. /* fall through */
  135. case -EINVAL: /* while removing driver */
  136. case -ENODEV: /* dev disconnect ... */
  137. case -ENOENT: /* just ignore it */
  138. case -ESHUTDOWN: /* and exit */
  139. case -ECONNRESET:
  140. result = -ESHUTDOWN;
  141. break;
  142. default: /* Some error? */
  143. if (edc_inc(&i2400mu->urb_edc,
  144. EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
  145. dev_err(dev, "TX: maximum errors in URB "
  146. "exceeded; resetting device\n");
  147. usb_queue_reset_device(i2400mu->usb_iface);
  148. } else {
  149. dev_err(dev, "TX: cannot send URB; retrying. "
  150. "tx_msg @%zu %zu B [%d sent]: %d\n",
  151. (void *) tx_msg - i2400m->tx_buf,
  152. tx_msg_size, sent_size, result);
  153. goto retry;
  154. }
  155. }
  156. if (do_autopm)
  157. usb_autopm_put_interface(i2400mu->usb_iface);
  158. d_fnend(4, dev, "(i2400mu %p) = result\n", i2400mu);
  159. return result;
  160. }
  161. /*
  162. * Get the next TX message in the TX FIFO and send it to the device
  163. *
  164. * Note we exit the loop if i2400mu_tx() fails; that function only
  165. * fails on hard error (failing to tx a buffer not being one of them,
  166. * see its doc).
  167. *
  168. * Return: 0
  169. */
  170. static
  171. int i2400mu_txd(void *_i2400mu)
  172. {
  173. struct i2400mu *i2400mu = _i2400mu;
  174. struct i2400m *i2400m = &i2400mu->i2400m;
  175. struct device *dev = &i2400mu->usb_iface->dev;
  176. struct i2400m_msg_hdr *tx_msg;
  177. size_t tx_msg_size;
  178. unsigned long flags;
  179. d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
  180. spin_lock_irqsave(&i2400m->tx_lock, flags);
  181. BUG_ON(i2400mu->tx_kthread != NULL);
  182. i2400mu->tx_kthread = current;
  183. spin_unlock_irqrestore(&i2400m->tx_lock, flags);
  184. while (1) {
  185. d_printf(2, dev, "TX: waiting for messages\n");
  186. tx_msg = NULL;
  187. wait_event_interruptible(
  188. i2400mu->tx_wq,
  189. (kthread_should_stop() /* check this first! */
  190. || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size)))
  191. );
  192. if (kthread_should_stop())
  193. break;
  194. WARN_ON(tx_msg == NULL); /* should not happen...*/
  195. d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size);
  196. d_dump(5, dev, tx_msg, tx_msg_size);
  197. /* Yeah, we ignore errors ... not much we can do */
  198. i2400mu_tx(i2400mu, tx_msg, tx_msg_size);
  199. i2400m_tx_msg_sent(i2400m); /* ack it, advance the FIFO */
  200. }
  201. spin_lock_irqsave(&i2400m->tx_lock, flags);
  202. i2400mu->tx_kthread = NULL;
  203. spin_unlock_irqrestore(&i2400m->tx_lock, flags);
  204. d_fnend(4, dev, "(i2400mu %p)\n", i2400mu);
  205. return 0;
  206. }
  207. /*
  208. * i2400m TX engine notifies us that there is data in the FIFO ready
  209. * for TX
  210. *
  211. * If there is a URB in flight, don't do anything; when it finishes,
  212. * it will see there is data in the FIFO and send it. Else, just
  213. * submit a write.
  214. */
  215. void i2400mu_bus_tx_kick(struct i2400m *i2400m)
  216. {
  217. struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
  218. struct device *dev = &i2400mu->usb_iface->dev;
  219. d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m);
  220. wake_up_all(&i2400mu->tx_wq);
  221. d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
  222. }
  223. int i2400mu_tx_setup(struct i2400mu *i2400mu)
  224. {
  225. int result = 0;
  226. struct i2400m *i2400m = &i2400mu->i2400m;
  227. struct device *dev = &i2400mu->usb_iface->dev;
  228. struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
  229. struct task_struct *kthread;
  230. kthread = kthread_run(i2400mu_txd, i2400mu, "%s-tx",
  231. wimax_dev->name);
  232. /* the kthread function sets i2400mu->tx_thread */
  233. if (IS_ERR(kthread)) {
  234. result = PTR_ERR(kthread);
  235. dev_err(dev, "TX: cannot start thread: %d\n", result);
  236. }
  237. return result;
  238. }
  239. void i2400mu_tx_release(struct i2400mu *i2400mu)
  240. {
  241. unsigned long flags;
  242. struct i2400m *i2400m = &i2400mu->i2400m;
  243. struct device *dev = i2400m_dev(i2400m);
  244. struct task_struct *kthread;
  245. spin_lock_irqsave(&i2400m->tx_lock, flags);
  246. kthread = i2400mu->tx_kthread;
  247. i2400mu->tx_kthread = NULL;
  248. spin_unlock_irqrestore(&i2400m->tx_lock, flags);
  249. if (kthread)
  250. kthread_stop(kthread);
  251. else
  252. d_printf(1, dev, "TX: kthread had already exited\n");
  253. }