i2400m-usb.h 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Intel Wireless WiMAX Connection 2400m
  3. * USB-specific i2400m driver definitions
  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. * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
  37. * Yanir Lubetkin <yanirx.lubetkin@intel.com>
  38. * - Initial implementation
  39. *
  40. *
  41. * This driver implements the bus-specific part of the i2400m for
  42. * USB. Check i2400m.h for a generic driver description.
  43. *
  44. * ARCHITECTURE
  45. *
  46. * This driver listens to notifications sent from the notification
  47. * endpoint (in usb-notif.c); when data is ready to read, the code in
  48. * there schedules a read from the device (usb-rx.c) and then passes
  49. * the data to the generic RX code (rx.c).
  50. *
  51. * When the generic driver needs to send data (network or control), it
  52. * queues up in the TX FIFO (tx.c) and that will notify the driver
  53. * through the i2400m->bus_tx_kick() callback
  54. * (usb-tx.c:i2400mu_bus_tx_kick) which will send the items in the
  55. * FIFO queue.
  56. *
  57. * This driver, as well, implements the USB-specific ops for the generic
  58. * driver to be able to setup/teardown communication with the device
  59. * [i2400m_bus_dev_start() and i2400m_bus_dev_stop()], reseting the
  60. * device [i2400m_bus_reset()] and performing firmware upload
  61. * [i2400m_bus_bm_cmd() and i2400_bus_bm_wait_for_ack()].
  62. */
  63. #ifndef __I2400M_USB_H__
  64. #define __I2400M_USB_H__
  65. #include "i2400m.h"
  66. #include <linux/kthread.h>
  67. /*
  68. * Error Density Count: cheapo error density (over time) counter
  69. *
  70. * Originally by Reinette Chatre <reinette.chatre@intel.com>
  71. *
  72. * Embed an 'struct edc' somewhere. Each time there is a soft or
  73. * retryable error, call edc_inc() and check if the error top
  74. * watermark has been reached.
  75. */
  76. enum {
  77. EDC_MAX_ERRORS = 10,
  78. EDC_ERROR_TIMEFRAME = HZ,
  79. };
  80. /* error density counter */
  81. struct edc {
  82. unsigned long timestart;
  83. u16 errorcount;
  84. };
  85. struct i2400m_endpoint_cfg {
  86. unsigned char bulk_out;
  87. unsigned char notification;
  88. unsigned char reset_cold;
  89. unsigned char bulk_in;
  90. };
  91. static inline void edc_init(struct edc *edc)
  92. {
  93. edc->timestart = jiffies;
  94. }
  95. /**
  96. * edc_inc - report a soft error and check if we are over the watermark
  97. *
  98. * @edc: pointer to error density counter.
  99. * @max_err: maximum number of errors we can accept over the timeframe
  100. * @timeframe: length of the timeframe (in jiffies).
  101. *
  102. * Returns: !0 1 if maximum acceptable errors per timeframe has been
  103. * exceeded. 0 otherwise.
  104. *
  105. * This is way to determine if the number of acceptable errors per time
  106. * period has been exceeded. It is not accurate as there are cases in which
  107. * this scheme will not work, for example if there are periodic occurrences
  108. * of errors that straddle updates to the start time. This scheme is
  109. * sufficient for our usage.
  110. *
  111. * To use, embed a 'struct edc' somewhere, initialize it with
  112. * edc_init() and when an error hits:
  113. *
  114. * if (do_something_fails_with_a_soft_error) {
  115. * if (edc_inc(&my->edc, MAX_ERRORS, MAX_TIMEFRAME))
  116. * Ops, hard error, do something about it
  117. * else
  118. * Retry or ignore, depending on whatever
  119. * }
  120. */
  121. static inline int edc_inc(struct edc *edc, u16 max_err, u16 timeframe)
  122. {
  123. unsigned long now;
  124. now = jiffies;
  125. if (now - edc->timestart > timeframe) {
  126. edc->errorcount = 1;
  127. edc->timestart = now;
  128. } else if (++edc->errorcount > max_err) {
  129. edc->errorcount = 0;
  130. edc->timestart = now;
  131. return 1;
  132. }
  133. return 0;
  134. }
  135. /* Host-Device interface for USB */
  136. enum {
  137. I2400M_USB_BOOT_RETRIES = 3,
  138. I2400MU_MAX_NOTIFICATION_LEN = 256,
  139. I2400MU_BLK_SIZE = 16,
  140. I2400MU_PL_SIZE_MAX = 0x3EFF,
  141. /* Device IDs */
  142. USB_DEVICE_ID_I6050 = 0x0186,
  143. USB_DEVICE_ID_I6050_2 = 0x0188,
  144. USB_DEVICE_ID_I6150 = 0x07d6,
  145. USB_DEVICE_ID_I6150_2 = 0x07d7,
  146. USB_DEVICE_ID_I6150_3 = 0x07d9,
  147. USB_DEVICE_ID_I6250 = 0x0187,
  148. };
  149. /**
  150. * struct i2400mu - descriptor for a USB connected i2400m
  151. *
  152. * @i2400m: bus-generic i2400m implementation; has to be first (see
  153. * it's documentation in i2400m.h).
  154. *
  155. * @usb_dev: pointer to our USB device
  156. *
  157. * @usb_iface: pointer to our USB interface
  158. *
  159. * @urb_edc: error density counter; used to keep a density-on-time tab
  160. * on how many soft (retryable or ignorable) errors we get. If we
  161. * go over the threshold, we consider the bus transport is failing
  162. * too much and reset.
  163. *
  164. * @notif_urb: URB for receiving notifications from the device.
  165. *
  166. * @tx_kthread: thread we use for data TX. We use a thread because in
  167. * order to do deep power saving and put the device to sleep, we
  168. * need to call usb_autopm_*() [blocking functions].
  169. *
  170. * @tx_wq: waitqueue for the TX kthread to sleep when there is no data
  171. * to be sent; when more data is available, it is woken up by
  172. * i2400mu_bus_tx_kick().
  173. *
  174. * @rx_kthread: thread we use for data RX. We use a thread because in
  175. * order to do deep power saving and put the device to sleep, we
  176. * need to call usb_autopm_*() [blocking functions].
  177. *
  178. * @rx_wq: waitqueue for the RX kthread to sleep when there is no data
  179. * to receive. When data is available, it is woken up by
  180. * usb-notif.c:i2400mu_notification_grok().
  181. *
  182. * @rx_pending_count: number of rx-data-ready notifications that were
  183. * still not handled by the RX kthread.
  184. *
  185. * @rx_size: current RX buffer size that is being used.
  186. *
  187. * @rx_size_acc: accumulator of the sizes of the previous read
  188. * transactions.
  189. *
  190. * @rx_size_cnt: number of read transactions accumulated in
  191. * @rx_size_acc.
  192. *
  193. * @do_autopm: disable(0)/enable(>0) calling the
  194. * usb_autopm_get/put_interface() barriers when executing
  195. * commands. See doc in i2400mu_suspend() for more information.
  196. *
  197. * @rx_size_auto_shrink: if true, the rx_size is shrunk
  198. * automatically based on the average size of the received
  199. * transactions. This allows the receive code to allocate smaller
  200. * chunks of memory and thus reduce pressure on the memory
  201. * allocator by not wasting so much space. By default it is
  202. * enabled.
  203. *
  204. * @debugfs_dentry: hookup for debugfs files.
  205. * These have to be in a separate directory, a child of
  206. * (wimax_dev->debugfs_dentry) so they can be removed when the
  207. * module unloads, as we don't keep each dentry.
  208. */
  209. struct i2400mu {
  210. struct i2400m i2400m; /* FIRST! See doc */
  211. struct usb_device *usb_dev;
  212. struct usb_interface *usb_iface;
  213. struct edc urb_edc; /* Error density counter */
  214. struct i2400m_endpoint_cfg endpoint_cfg;
  215. struct urb *notif_urb;
  216. struct task_struct *tx_kthread;
  217. wait_queue_head_t tx_wq;
  218. struct task_struct *rx_kthread;
  219. wait_queue_head_t rx_wq;
  220. atomic_t rx_pending_count;
  221. size_t rx_size, rx_size_acc, rx_size_cnt;
  222. atomic_t do_autopm;
  223. u8 rx_size_auto_shrink;
  224. struct dentry *debugfs_dentry;
  225. unsigned i6050:1; /* 1 if this is a 6050 based SKU */
  226. };
  227. static inline
  228. void i2400mu_init(struct i2400mu *i2400mu)
  229. {
  230. i2400m_init(&i2400mu->i2400m);
  231. edc_init(&i2400mu->urb_edc);
  232. init_waitqueue_head(&i2400mu->tx_wq);
  233. atomic_set(&i2400mu->rx_pending_count, 0);
  234. init_waitqueue_head(&i2400mu->rx_wq);
  235. i2400mu->rx_size = PAGE_SIZE - sizeof(struct skb_shared_info);
  236. atomic_set(&i2400mu->do_autopm, 1);
  237. i2400mu->rx_size_auto_shrink = 1;
  238. }
  239. int i2400mu_notification_setup(struct i2400mu *);
  240. void i2400mu_notification_release(struct i2400mu *);
  241. int i2400mu_rx_setup(struct i2400mu *);
  242. void i2400mu_rx_release(struct i2400mu *);
  243. void i2400mu_rx_kick(struct i2400mu *);
  244. int i2400mu_tx_setup(struct i2400mu *);
  245. void i2400mu_tx_release(struct i2400mu *);
  246. void i2400mu_bus_tx_kick(struct i2400m *);
  247. ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *,
  248. const struct i2400m_bootrom_header *, size_t,
  249. int);
  250. ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *,
  251. struct i2400m_bootrom_header *, size_t);
  252. #endif /* #ifndef __I2400M_USB_H__ */