bcdc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * Copyright (c) 2010 Broadcom Corporation
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  11. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. /*******************************************************************************
  17. * Communicates with the dongle by using dcmd codes.
  18. * For certain dcmd codes, the dongle interprets string data from the host.
  19. ******************************************************************************/
  20. #include <linux/types.h>
  21. #include <linux/netdevice.h>
  22. #include <brcmu_utils.h>
  23. #include <brcmu_wifi.h>
  24. #include "core.h"
  25. #include "bus.h"
  26. #include "fwsignal.h"
  27. #include "debug.h"
  28. #include "tracepoint.h"
  29. #include "proto.h"
  30. #include "bcdc.h"
  31. struct brcmf_proto_bcdc_dcmd {
  32. __le32 cmd; /* dongle command value */
  33. __le32 len; /* lower 16: output buflen;
  34. * upper 16: input buflen (excludes header) */
  35. __le32 flags; /* flag defns given below */
  36. __le32 status; /* status code returned from the device */
  37. };
  38. /* BCDC flag definitions */
  39. #define BCDC_DCMD_ERROR 0x01 /* 1=cmd failed */
  40. #define BCDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */
  41. #define BCDC_DCMD_IF_MASK 0xF000 /* I/F index */
  42. #define BCDC_DCMD_IF_SHIFT 12
  43. #define BCDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */
  44. #define BCDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */
  45. #define BCDC_DCMD_ID(flags) \
  46. (((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT)
  47. /*
  48. * BCDC header - Broadcom specific extension of CDC.
  49. * Used on data packets to convey priority across USB.
  50. */
  51. #define BCDC_HEADER_LEN 4
  52. #define BCDC_PROTO_VER 2 /* Protocol version */
  53. #define BCDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */
  54. #define BCDC_FLAG_VER_SHIFT 4 /* Protocol version shift */
  55. #define BCDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */
  56. #define BCDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */
  57. #define BCDC_PRIORITY_MASK 0x7
  58. #define BCDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */
  59. #define BCDC_FLAG2_IF_SHIFT 0
  60. #define BCDC_GET_IF_IDX(hdr) \
  61. ((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT))
  62. #define BCDC_SET_IF_IDX(hdr, idx) \
  63. ((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \
  64. ((idx) << BCDC_FLAG2_IF_SHIFT)))
  65. /**
  66. * struct brcmf_proto_bcdc_header - BCDC header format
  67. *
  68. * @flags: flags contain protocol and checksum info.
  69. * @priority: 802.1d priority and USB flow control info (bit 4:7).
  70. * @flags2: additional flags containing dongle interface index.
  71. * @data_offset: start of packet data. header is following by firmware signals.
  72. */
  73. struct brcmf_proto_bcdc_header {
  74. u8 flags;
  75. u8 priority;
  76. u8 flags2;
  77. u8 data_offset;
  78. };
  79. /*
  80. * maximum length of firmware signal data between
  81. * the BCDC header and packet data in the tx path.
  82. */
  83. #define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12
  84. #define RETRIES 2 /* # of retries to retrieve matching dcmd response */
  85. #define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE
  86. * (amount of header tha might be added)
  87. * plus any space that might be needed
  88. * for bus alignment padding.
  89. */
  90. struct brcmf_bcdc {
  91. u16 reqid;
  92. u8 bus_header[BUS_HEADER_LEN];
  93. struct brcmf_proto_bcdc_dcmd msg;
  94. unsigned char buf[BRCMF_DCMD_MAXLEN];
  95. };
  96. static int
  97. brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
  98. uint len, bool set)
  99. {
  100. struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
  101. struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
  102. u32 flags;
  103. brcmf_dbg(BCDC, "Enter\n");
  104. memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));
  105. msg->cmd = cpu_to_le32(cmd);
  106. msg->len = cpu_to_le32(len);
  107. flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);
  108. if (set)
  109. flags |= BCDC_DCMD_SET;
  110. flags = (flags & ~BCDC_DCMD_IF_MASK) |
  111. (ifidx << BCDC_DCMD_IF_SHIFT);
  112. msg->flags = cpu_to_le32(flags);
  113. if (buf)
  114. memcpy(bcdc->buf, buf, len);
  115. len += sizeof(*msg);
  116. if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE)
  117. len = BRCMF_TX_IOCTL_MAX_MSG_SIZE;
  118. /* Send request */
  119. return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);
  120. }
  121. static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
  122. {
  123. int ret;
  124. struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
  125. brcmf_dbg(BCDC, "Enter\n");
  126. len += sizeof(struct brcmf_proto_bcdc_dcmd);
  127. do {
  128. ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg,
  129. len);
  130. if (ret < 0)
  131. break;
  132. } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id);
  133. return ret;
  134. }
  135. static int
  136. brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
  137. void *buf, uint len)
  138. {
  139. struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
  140. struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
  141. void *info;
  142. int ret = 0, retries = 0;
  143. u32 id, flags;
  144. brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
  145. ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false);
  146. if (ret < 0) {
  147. brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",
  148. ret);
  149. goto done;
  150. }
  151. retry:
  152. /* wait for interrupt and get first fragment */
  153. ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);
  154. if (ret < 0)
  155. goto done;
  156. flags = le32_to_cpu(msg->flags);
  157. id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;
  158. if ((id < bcdc->reqid) && (++retries < RETRIES))
  159. goto retry;
  160. if (id != bcdc->reqid) {
  161. brcmf_err("%s: unexpected request id %d (expected %d)\n",
  162. brcmf_ifname(drvr, ifidx), id, bcdc->reqid);
  163. ret = -EINVAL;
  164. goto done;
  165. }
  166. /* Check info buffer */
  167. info = (void *)&msg[1];
  168. /* Copy info buffer */
  169. if (buf) {
  170. if (ret < (int)len)
  171. len = ret;
  172. memcpy(buf, info, len);
  173. }
  174. /* Check the ERROR flag */
  175. if (flags & BCDC_DCMD_ERROR)
  176. ret = le32_to_cpu(msg->status);
  177. done:
  178. return ret;
  179. }
  180. static int
  181. brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
  182. void *buf, uint len)
  183. {
  184. struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;
  185. struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;
  186. int ret = 0;
  187. u32 flags, id;
  188. brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);
  189. ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true);
  190. if (ret < 0)
  191. goto done;
  192. ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);
  193. if (ret < 0)
  194. goto done;
  195. flags = le32_to_cpu(msg->flags);
  196. id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;
  197. if (id != bcdc->reqid) {
  198. brcmf_err("%s: unexpected request id %d (expected %d)\n",
  199. brcmf_ifname(drvr, ifidx), id, bcdc->reqid);
  200. ret = -EINVAL;
  201. goto done;
  202. }
  203. /* Check the ERROR flag */
  204. if (flags & BCDC_DCMD_ERROR)
  205. ret = le32_to_cpu(msg->status);
  206. done:
  207. return ret;
  208. }
  209. static void
  210. brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
  211. struct sk_buff *pktbuf)
  212. {
  213. struct brcmf_proto_bcdc_header *h;
  214. brcmf_dbg(BCDC, "Enter\n");
  215. /* Push BDC header used to convey priority for buses that don't */
  216. skb_push(pktbuf, BCDC_HEADER_LEN);
  217. h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
  218. h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT);
  219. if (pktbuf->ip_summed == CHECKSUM_PARTIAL)
  220. h->flags |= BCDC_FLAG_SUM_NEEDED;
  221. h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK);
  222. h->flags2 = 0;
  223. h->data_offset = offset;
  224. BCDC_SET_IF_IDX(h, ifidx);
  225. trace_brcmf_bcdchdr(pktbuf->data);
  226. }
  227. static int
  228. brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
  229. struct sk_buff *pktbuf)
  230. {
  231. struct brcmf_proto_bcdc_header *h;
  232. brcmf_dbg(BCDC, "Enter\n");
  233. /* Pop BCDC header used to convey priority for buses that don't */
  234. if (pktbuf->len <= BCDC_HEADER_LEN) {
  235. brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",
  236. pktbuf->len, BCDC_HEADER_LEN);
  237. return -EBADE;
  238. }
  239. trace_brcmf_bcdchdr(pktbuf->data);
  240. h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);
  241. *ifidx = BCDC_GET_IF_IDX(h);
  242. if (*ifidx >= BRCMF_MAX_IFS) {
  243. brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
  244. return -EBADE;
  245. }
  246. /* The ifidx is the idx to map to matching netdev/ifp. When receiving
  247. * events this is easy because it contains the bssidx which maps
  248. * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
  249. * bssidx 1 is used for p2p0 and no data can be received or
  250. * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
  251. */
  252. if (*ifidx)
  253. (*ifidx)++;
  254. if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=
  255. BCDC_PROTO_VER) {
  256. brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",
  257. brcmf_ifname(drvr, *ifidx), h->flags);
  258. return -EBADE;
  259. }
  260. if (h->flags & BCDC_FLAG_SUM_GOOD) {
  261. brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
  262. brcmf_ifname(drvr, *ifidx), h->flags);
  263. pktbuf->ip_summed = CHECKSUM_UNNECESSARY;
  264. }
  265. pktbuf->priority = h->priority & BCDC_PRIORITY_MASK;
  266. skb_pull(pktbuf, BCDC_HEADER_LEN);
  267. if (do_fws)
  268. brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
  269. else
  270. skb_pull(pktbuf, h->data_offset << 2);
  271. if (pktbuf->len == 0)
  272. return -ENODATA;
  273. return 0;
  274. }
  275. static int
  276. brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset,
  277. struct sk_buff *pktbuf)
  278. {
  279. brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf);
  280. return brcmf_bus_txdata(drvr->bus_if, pktbuf);
  281. }
  282. static void
  283. brcmf_proto_bcdc_configure_addr_mode(struct brcmf_pub *drvr, int ifidx,
  284. enum proto_addr_mode addr_mode)
  285. {
  286. }
  287. static void
  288. brcmf_proto_bcdc_delete_peer(struct brcmf_pub *drvr, int ifidx,
  289. u8 peer[ETH_ALEN])
  290. {
  291. }
  292. static void
  293. brcmf_proto_bcdc_add_tdls_peer(struct brcmf_pub *drvr, int ifidx,
  294. u8 peer[ETH_ALEN])
  295. {
  296. }
  297. int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
  298. {
  299. struct brcmf_bcdc *bcdc;
  300. bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC);
  301. if (!bcdc)
  302. goto fail;
  303. /* ensure that the msg buf directly follows the cdc msg struct */
  304. if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) {
  305. brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n");
  306. goto fail;
  307. }
  308. drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull;
  309. drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd;
  310. drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd;
  311. drvr->proto->txdata = brcmf_proto_bcdc_txdata;
  312. drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode;
  313. drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer;
  314. drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer;
  315. drvr->proto->pd = bcdc;
  316. drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
  317. drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
  318. sizeof(struct brcmf_proto_bcdc_dcmd);
  319. return 0;
  320. fail:
  321. kfree(bcdc);
  322. return -ENOMEM;
  323. }
  324. void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)
  325. {
  326. kfree(drvr->proto->pd);
  327. drvr->proto->pd = NULL;
  328. }