wusb.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Wireless Host Controller (WHC) WUSB operations.
  3. *
  4. * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License version
  8. * 2 as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <linux/version.h>
  19. #include <linux/kernel.h>
  20. #include <linux/init.h>
  21. #include <linux/uwb/umc.h>
  22. #define D_LOCAL 1
  23. #include <linux/uwb/debug.h>
  24. #include "../../wusbcore/wusbhc.h"
  25. #include "whcd.h"
  26. #if D_LOCAL >= 1
  27. static void dump_di(struct whc *whc, int idx)
  28. {
  29. struct di_buf_entry *di = &whc->di_buf[idx];
  30. struct device *dev = &whc->umc->dev;
  31. char buf[128];
  32. bitmap_scnprintf(buf, sizeof(buf), (unsigned long *)di->availability_info, UWB_NUM_MAS);
  33. d_printf(1, dev, "DI[%d]\n", idx);
  34. d_printf(1, dev, " availability: %s\n", buf);
  35. d_printf(1, dev, " %c%c key idx: %d dev addr: %d\n",
  36. (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
  37. (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
  38. (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
  39. (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
  40. }
  41. #else
  42. static inline void dump_di(struct whc *whc, int idx)
  43. {
  44. }
  45. #endif
  46. static int whc_update_di(struct whc *whc, int idx)
  47. {
  48. int offset = idx / 32;
  49. u32 bit = 1 << (idx % 32);
  50. dump_di(whc, idx);
  51. le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
  52. return whci_wait_for(&whc->umc->dev,
  53. whc->base + WUSBDIBUPDATED + offset, bit, 0,
  54. 100, "DI update");
  55. }
  56. /*
  57. * WHCI starts and stops MMCs based on there being a valid GTK so
  58. * these need only start/stop the asynchronous and periodic schedules.
  59. */
  60. int whc_wusbhc_start(struct wusbhc *wusbhc)
  61. {
  62. struct whc *whc = wusbhc_to_whc(wusbhc);
  63. asl_start(whc);
  64. pzl_start(whc);
  65. return 0;
  66. }
  67. void whc_wusbhc_stop(struct wusbhc *wusbhc)
  68. {
  69. struct whc *whc = wusbhc_to_whc(wusbhc);
  70. pzl_stop(whc);
  71. asl_stop(whc);
  72. }
  73. int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
  74. u8 handle, struct wuie_hdr *wuie)
  75. {
  76. struct whc *whc = wusbhc_to_whc(wusbhc);
  77. u32 params;
  78. params = (interval << 24)
  79. | (repeat_cnt << 16)
  80. | (wuie->bLength << 8)
  81. | handle;
  82. return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength);
  83. }
  84. int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
  85. {
  86. struct whc *whc = wusbhc_to_whc(wusbhc);
  87. u32 params;
  88. params = handle;
  89. return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0);
  90. }
  91. int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm)
  92. {
  93. struct whc *whc = wusbhc_to_whc(wusbhc);
  94. if (stream_index >= 0)
  95. whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index));
  96. return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm));
  97. }
  98. int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
  99. {
  100. struct whc *whc = wusbhc_to_whc(wusbhc);
  101. int idx = wusb_dev->port_idx;
  102. struct di_buf_entry *di = &whc->di_buf[idx];
  103. int ret;
  104. mutex_lock(&whc->mutex);
  105. uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability);
  106. di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK);
  107. di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr);
  108. ret = whc_update_di(whc, idx);
  109. mutex_unlock(&whc->mutex);
  110. return ret;
  111. }
  112. /*
  113. * Set the number of Device Notification Time Slots (DNTS) and enable
  114. * device notifications.
  115. */
  116. int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
  117. {
  118. struct whc *whc = wusbhc_to_whc(wusbhc);
  119. u32 dntsctrl;
  120. dntsctrl = WUSBDNTSCTRL_ACTIVE
  121. | WUSBDNTSCTRL_INTERVAL(interval)
  122. | WUSBDNTSCTRL_SLOTS(slots);
  123. le_writel(dntsctrl, whc->base + WUSBDNTSCTRL);
  124. return 0;
  125. }
  126. static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid,
  127. const void *key, size_t key_size, bool is_gtk)
  128. {
  129. uint32_t setkeycmd;
  130. uint32_t seckey[4];
  131. int i;
  132. int ret;
  133. memcpy(seckey, key, key_size);
  134. setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index);
  135. if (is_gtk)
  136. setkeycmd |= WUSBSETSECKEYCMD_GTK;
  137. le_writel(tkid, whc->base + WUSBTKID);
  138. for (i = 0; i < 4; i++)
  139. le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i);
  140. le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD);
  141. ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD,
  142. WUSBSETSECKEYCMD_SET, 0, 100, "set key");
  143. return ret;
  144. }
  145. /**
  146. * whc_set_ptk - set the PTK to use for a device.
  147. *
  148. * The index into the key table for this PTK is the same as the
  149. * device's port index.
  150. */
  151. int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
  152. const void *ptk, size_t key_size)
  153. {
  154. struct whc *whc = wusbhc_to_whc(wusbhc);
  155. struct di_buf_entry *di = &whc->di_buf[port_idx];
  156. int ret;
  157. mutex_lock(&whc->mutex);
  158. if (ptk) {
  159. ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false);
  160. if (ret)
  161. goto out;
  162. di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK;
  163. di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx);
  164. } else
  165. di->addr_sec_info &= ~WHC_DI_SECURE;
  166. ret = whc_update_di(whc, port_idx);
  167. out:
  168. mutex_unlock(&whc->mutex);
  169. return ret;
  170. }
  171. /**
  172. * whc_set_gtk - set the GTK for subsequent broadcast packets
  173. *
  174. * The GTK is stored in the last entry in the key table (the previous
  175. * N_DEVICES entries are for the per-device PTKs).
  176. */
  177. int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
  178. const void *gtk, size_t key_size)
  179. {
  180. struct whc *whc = wusbhc_to_whc(wusbhc);
  181. int ret;
  182. mutex_lock(&whc->mutex);
  183. ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true);
  184. mutex_unlock(&whc->mutex);
  185. return ret;
  186. }
  187. int whc_set_cluster_id(struct whc *whc, u8 bcid)
  188. {
  189. whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid));
  190. return 0;
  191. }