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 /******************************************************************************* 18 * Communicates with the dongle by using dcmd codes. 19 * For certain dcmd codes, the dongle interprets string data from the host. 20 ******************************************************************************/ 21 22 #include <linux/types.h> 23 #include <linux/netdevice.h> 24 25 #include <brcmu_utils.h> 26 #include <brcmu_wifi.h> 27 28 #include "core.h" 29 #include "bus.h" 30 #include "fwsignal.h" 31 #include "debug.h" 32 #include "tracepoint.h" 33 #include "proto.h" 34 #include "bcdc.h" 35 36 struct brcmf_proto_bcdc_dcmd { 37 __le32 cmd; /* dongle command value */ 38 __le32 len; /* lower 16: output buflen; 39 * upper 16: input buflen (excludes header) */ 40 __le32 flags; /* flag defns given below */ 41 __le32 status; /* status code returned from the device */ 42 }; 43 44 /* BCDC flag definitions */ 45 #define BCDC_DCMD_ERROR 0x01 /* 1=cmd failed */ 46 #define BCDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ 47 #define BCDC_DCMD_IF_MASK 0xF000 /* I/F index */ 48 #define BCDC_DCMD_IF_SHIFT 12 49 #define BCDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ 50 #define BCDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ 51 #define BCDC_DCMD_ID(flags) \ 52 (((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT) 53 54 /* 55 * BCDC header - Broadcom specific extension of CDC. 56 * Used on data packets to convey priority across USB. 57 */ 58 #define BCDC_HEADER_LEN 4 59 #define BCDC_PROTO_VER 2 /* Protocol version */ 60 #define BCDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ 61 #define BCDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ 62 #define BCDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ 63 #define BCDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ 64 #define BCDC_PRIORITY_MASK 0x7 65 #define BCDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ 66 #define BCDC_FLAG2_IF_SHIFT 0 67 68 #define BCDC_GET_IF_IDX(hdr) \ 69 ((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT)) 70 #define BCDC_SET_IF_IDX(hdr, idx) \ 71 ((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \ 72 ((idx) << BCDC_FLAG2_IF_SHIFT))) 73 74 /** 75 * struct brcmf_proto_bcdc_header - BCDC header format 76 * 77 * @flags: flags contain protocol and checksum info. 78 * @priority: 802.1d priority and USB flow control info (bit 4:7). 79 * @flags2: additional flags containing dongle interface index. 80 * @data_offset: start of packet data. header is following by firmware signals. 81 */ 82 struct brcmf_proto_bcdc_header { 83 u8 flags; 84 u8 priority; 85 u8 flags2; 86 u8 data_offset; 87 }; 88 89 /* 90 * maximum length of firmware signal data between 91 * the BCDC header and packet data in the tx path. 92 */ 93 #define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12 94 95 #define RETRIES 2 /* # of retries to retrieve matching dcmd response */ 96 #define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE 97 * (amount of header tha might be added) 98 * plus any space that might be needed 99 * for bus alignment padding. 100 */ 101 struct brcmf_bcdc { 102 u16 reqid; 103 u8 bus_header[BUS_HEADER_LEN]; 104 struct brcmf_proto_bcdc_dcmd msg; 105 unsigned char buf[BRCMF_DCMD_MAXLEN]; 106 struct brcmf_fws_info *fws; 107 }; 108 109 110 struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr) 111 { 112 struct brcmf_bcdc *bcdc = drvr->proto->pd; 113 114 return bcdc->fws; 115 } 116 117 static int 118 brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, 119 uint len, bool set) 120 { 121 struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 122 struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 123 u32 flags; 124 125 brcmf_dbg(BCDC, "Enter\n"); 126 127 memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd)); 128 129 msg->cmd = cpu_to_le32(cmd); 130 msg->len = cpu_to_le32(len); 131 flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT); 132 if (set) 133 flags |= BCDC_DCMD_SET; 134 flags = (flags & ~BCDC_DCMD_IF_MASK) | 135 (ifidx << BCDC_DCMD_IF_SHIFT); 136 msg->flags = cpu_to_le32(flags); 137 138 if (buf) 139 memcpy(bcdc->buf, buf, len); 140 141 len += sizeof(*msg); 142 if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE) 143 len = BRCMF_TX_IOCTL_MAX_MSG_SIZE; 144 145 /* Send request */ 146 return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); 147 } 148 149 static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) 150 { 151 int ret; 152 struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 153 154 brcmf_dbg(BCDC, "Enter\n"); 155 len += sizeof(struct brcmf_proto_bcdc_dcmd); 156 do { 157 ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg, 158 len); 159 if (ret < 0) 160 break; 161 } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id); 162 163 return ret; 164 } 165 166 static int 167 brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, 168 void *buf, uint len, int *fwerr) 169 { 170 struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 171 struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 172 void *info; 173 int ret = 0, retries = 0; 174 u32 id, flags; 175 176 brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); 177 178 *fwerr = 0; 179 ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false); 180 if (ret < 0) { 181 brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n", 182 ret); 183 goto done; 184 } 185 186 retry: 187 /* wait for interrupt and get first fragment */ 188 ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); 189 if (ret < 0) 190 goto done; 191 192 flags = le32_to_cpu(msg->flags); 193 id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; 194 195 if ((id < bcdc->reqid) && (++retries < RETRIES)) 196 goto retry; 197 if (id != bcdc->reqid) { 198 brcmf_err("%s: unexpected request id %d (expected %d)\n", 199 brcmf_ifname(brcmf_get_ifp(drvr, ifidx)), id, 200 bcdc->reqid); 201 ret = -EINVAL; 202 goto done; 203 } 204 205 /* Check info buffer */ 206 info = (void *)&bcdc->buf[0]; 207 208 /* Copy info buffer */ 209 if (buf) { 210 if (ret < (int)len) 211 len = ret; 212 memcpy(buf, info, len); 213 } 214 215 ret = 0; 216 217 /* Check the ERROR flag */ 218 if (flags & BCDC_DCMD_ERROR) 219 *fwerr = le32_to_cpu(msg->status); 220 done: 221 return ret; 222 } 223 224 static int 225 brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, 226 void *buf, uint len, int *fwerr) 227 { 228 struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 229 struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 230 int ret; 231 u32 flags, id; 232 233 brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); 234 235 *fwerr = 0; 236 ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true); 237 if (ret < 0) 238 goto done; 239 240 ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); 241 if (ret < 0) 242 goto done; 243 244 flags = le32_to_cpu(msg->flags); 245 id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; 246 247 if (id != bcdc->reqid) { 248 brcmf_err("%s: unexpected request id %d (expected %d)\n", 249 brcmf_ifname(brcmf_get_ifp(drvr, ifidx)), id, 250 bcdc->reqid); 251 ret = -EINVAL; 252 goto done; 253 } 254 255 ret = 0; 256 257 /* Check the ERROR flag */ 258 if (flags & BCDC_DCMD_ERROR) 259 *fwerr = le32_to_cpu(msg->status); 260 261 done: 262 return ret; 263 } 264 265 static void 266 brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, 267 struct sk_buff *pktbuf) 268 { 269 struct brcmf_proto_bcdc_header *h; 270 271 brcmf_dbg(BCDC, "Enter\n"); 272 273 /* Push BDC header used to convey priority for buses that don't */ 274 skb_push(pktbuf, BCDC_HEADER_LEN); 275 276 h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); 277 278 h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT); 279 if (pktbuf->ip_summed == CHECKSUM_PARTIAL) 280 h->flags |= BCDC_FLAG_SUM_NEEDED; 281 282 h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK); 283 h->flags2 = 0; 284 h->data_offset = offset; 285 BCDC_SET_IF_IDX(h, ifidx); 286 trace_brcmf_bcdchdr(pktbuf->data); 287 } 288 289 static int 290 brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, 291 struct sk_buff *pktbuf, struct brcmf_if **ifp) 292 { 293 struct brcmf_proto_bcdc_header *h; 294 struct brcmf_if *tmp_if; 295 296 brcmf_dbg(BCDC, "Enter\n"); 297 298 /* Pop BCDC header used to convey priority for buses that don't */ 299 if (pktbuf->len <= BCDC_HEADER_LEN) { 300 brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", 301 pktbuf->len, BCDC_HEADER_LEN); 302 return -EBADE; 303 } 304 305 trace_brcmf_bcdchdr(pktbuf->data); 306 h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); 307 308 tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); 309 if (!tmp_if) { 310 brcmf_dbg(INFO, "no matching ifp found\n"); 311 return -EBADE; 312 } 313 if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != 314 BCDC_PROTO_VER) { 315 brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", 316 brcmf_ifname(tmp_if), h->flags); 317 return -EBADE; 318 } 319 320 if (h->flags & BCDC_FLAG_SUM_GOOD) { 321 brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", 322 brcmf_ifname(tmp_if), h->flags); 323 pktbuf->ip_summed = CHECKSUM_UNNECESSARY; 324 } 325 326 pktbuf->priority = h->priority & BCDC_PRIORITY_MASK; 327 328 skb_pull(pktbuf, BCDC_HEADER_LEN); 329 if (do_fws) 330 brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf); 331 else 332 skb_pull(pktbuf, h->data_offset << 2); 333 334 if (pktbuf->len == 0) 335 return -ENODATA; 336 337 if (ifp != NULL) 338 *ifp = tmp_if; 339 return 0; 340 } 341 342 static int brcmf_proto_bcdc_tx_queue_data(struct brcmf_pub *drvr, int ifidx, 343 struct sk_buff *skb) 344 { 345 struct brcmf_if *ifp = brcmf_get_ifp(drvr, ifidx); 346 struct brcmf_bcdc *bcdc = drvr->proto->pd; 347 348 if (!brcmf_fws_queue_skbs(bcdc->fws)) 349 return brcmf_proto_txdata(drvr, ifidx, 0, skb); 350 351 return brcmf_fws_process_skb(ifp, skb); 352 } 353 354 static int 355 brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset, 356 struct sk_buff *pktbuf) 357 { 358 brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf); 359 return brcmf_bus_txdata(drvr->bus_if, pktbuf); 360 } 361 362 void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state) 363 { 364 struct brcmf_bus *bus_if = dev_get_drvdata(dev); 365 struct brcmf_pub *drvr = bus_if->drvr; 366 367 brcmf_dbg(TRACE, "Enter\n"); 368 369 brcmf_fws_bus_blocked(drvr, state); 370 } 371 372 void 373 brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp, 374 bool success) 375 { 376 struct brcmf_bus *bus_if = dev_get_drvdata(dev); 377 struct brcmf_bcdc *bcdc = bus_if->drvr->proto->pd; 378 struct brcmf_if *ifp; 379 380 /* await txstatus signal for firmware if active */ 381 if (brcmf_fws_fc_active(bcdc->fws)) { 382 if (!success) 383 brcmf_fws_bustxfail(bcdc->fws, txp); 384 } else { 385 if (brcmf_proto_bcdc_hdrpull(bus_if->drvr, false, txp, &ifp)) 386 brcmu_pkt_buf_free_skb(txp); 387 else 388 brcmf_txfinalize(ifp, txp, success); 389 } 390 } 391 392 static void 393 brcmf_proto_bcdc_configure_addr_mode(struct brcmf_pub *drvr, int ifidx, 394 enum proto_addr_mode addr_mode) 395 { 396 } 397 398 static void 399 brcmf_proto_bcdc_delete_peer(struct brcmf_pub *drvr, int ifidx, 400 u8 peer[ETH_ALEN]) 401 { 402 } 403 404 static void 405 brcmf_proto_bcdc_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, 406 u8 peer[ETH_ALEN]) 407 { 408 } 409 410 static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp, 411 struct sk_buff *skb) 412 { 413 brcmf_fws_rxreorder(ifp, skb); 414 } 415 416 static void 417 brcmf_proto_bcdc_add_if(struct brcmf_if *ifp) 418 { 419 brcmf_fws_add_interface(ifp); 420 } 421 422 static void 423 brcmf_proto_bcdc_del_if(struct brcmf_if *ifp) 424 { 425 brcmf_fws_del_interface(ifp); 426 } 427 428 static void 429 brcmf_proto_bcdc_reset_if(struct brcmf_if *ifp) 430 { 431 brcmf_fws_reset_interface(ifp); 432 } 433 434 static int 435 brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr) 436 { 437 struct brcmf_bcdc *bcdc = drvr->proto->pd; 438 struct brcmf_fws_info *fws; 439 440 fws = brcmf_fws_attach(drvr); 441 if (IS_ERR(fws)) 442 return PTR_ERR(fws); 443 444 bcdc->fws = fws; 445 return 0; 446 } 447 448 int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) 449 { 450 struct brcmf_bcdc *bcdc; 451 452 bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC); 453 if (!bcdc) 454 goto fail; 455 456 /* ensure that the msg buf directly follows the cdc msg struct */ 457 if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) { 458 brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n"); 459 goto fail; 460 } 461 462 drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull; 463 drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd; 464 drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; 465 drvr->proto->tx_queue_data = brcmf_proto_bcdc_tx_queue_data; 466 drvr->proto->txdata = brcmf_proto_bcdc_txdata; 467 drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode; 468 drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer; 469 drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer; 470 drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder; 471 drvr->proto->add_if = brcmf_proto_bcdc_add_if; 472 drvr->proto->del_if = brcmf_proto_bcdc_del_if; 473 drvr->proto->reset_if = brcmf_proto_bcdc_reset_if; 474 drvr->proto->init_done = brcmf_proto_bcdc_init_done; 475 drvr->proto->pd = bcdc; 476 477 drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; 478 drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + 479 sizeof(struct brcmf_proto_bcdc_dcmd); 480 return 0; 481 482 fail: 483 kfree(bcdc); 484 return -ENOMEM; 485 } 486 487 void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) 488 { 489 struct brcmf_bcdc *bcdc = drvr->proto->pd; 490 491 drvr->proto->pd = NULL; 492 brcmf_fws_detach(bcdc->fws); 493 kfree(bcdc); 494 } 495