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