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 #define ROUND_UP_MARGIN 2048 91 92 struct brcmf_bcdc { 93 u16 reqid; 94 u8 bus_header[BUS_HEADER_LEN]; 95 struct brcmf_proto_bcdc_dcmd msg; 96 unsigned char buf[BRCMF_DCMD_MAXLEN]; 97 struct brcmf_fws_info *fws; 98 }; 99 100 101 struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr) 102 { 103 struct brcmf_bcdc *bcdc = drvr->proto->pd; 104 105 return bcdc->fws; 106 } 107 108 static int 109 brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, 110 uint len, bool set) 111 { 112 struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 113 struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 114 u32 flags; 115 116 brcmf_dbg(BCDC, "Enter\n"); 117 118 memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd)); 119 120 msg->cmd = cpu_to_le32(cmd); 121 msg->len = cpu_to_le32(len); 122 flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT); 123 if (set) 124 flags |= BCDC_DCMD_SET; 125 flags = (flags & ~BCDC_DCMD_IF_MASK) | 126 (ifidx << BCDC_DCMD_IF_SHIFT); 127 msg->flags = cpu_to_le32(flags); 128 129 if (buf) 130 memcpy(bcdc->buf, buf, len); 131 132 len += sizeof(*msg); 133 if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE) 134 len = BRCMF_TX_IOCTL_MAX_MSG_SIZE; 135 136 /* Send request */ 137 return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); 138 } 139 140 static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) 141 { 142 int ret; 143 struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 144 145 brcmf_dbg(BCDC, "Enter\n"); 146 len += sizeof(struct brcmf_proto_bcdc_dcmd); 147 do { 148 ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg, 149 len); 150 if (ret < 0) 151 break; 152 } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id); 153 154 return ret; 155 } 156 157 static int 158 brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, 159 void *buf, uint len, int *fwerr) 160 { 161 struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 162 struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 163 void *info; 164 int ret = 0, retries = 0; 165 u32 id, flags; 166 167 brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); 168 169 *fwerr = 0; 170 ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false); 171 if (ret < 0) { 172 bphy_err(drvr, "brcmf_proto_bcdc_msg failed w/status %d\n", 173 ret); 174 goto done; 175 } 176 177 retry: 178 /* wait for interrupt and get first fragment */ 179 ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); 180 if (ret < 0) 181 goto done; 182 183 flags = le32_to_cpu(msg->flags); 184 id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; 185 186 if ((id < bcdc->reqid) && (++retries < RETRIES)) 187 goto retry; 188 if (id != bcdc->reqid) { 189 bphy_err(drvr, "%s: unexpected request id %d (expected %d)\n", 190 brcmf_ifname(brcmf_get_ifp(drvr, ifidx)), id, 191 bcdc->reqid); 192 ret = -EINVAL; 193 goto done; 194 } 195 196 /* Check info buffer */ 197 info = (void *)&bcdc->buf[0]; 198 199 /* Copy info buffer */ 200 if (buf) { 201 if (ret < (int)len) 202 len = ret; 203 memcpy(buf, info, len); 204 } 205 206 ret = 0; 207 208 /* Check the ERROR flag */ 209 if (flags & BCDC_DCMD_ERROR) 210 *fwerr = le32_to_cpu(msg->status); 211 done: 212 return ret; 213 } 214 215 static int 216 brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, 217 void *buf, uint len, int *fwerr) 218 { 219 struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 220 struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 221 int ret; 222 u32 flags, id; 223 224 brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); 225 226 *fwerr = 0; 227 ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true); 228 if (ret < 0) 229 goto done; 230 231 ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); 232 if (ret < 0) 233 goto done; 234 235 flags = le32_to_cpu(msg->flags); 236 id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; 237 238 if (id != bcdc->reqid) { 239 bphy_err(drvr, "%s: unexpected request id %d (expected %d)\n", 240 brcmf_ifname(brcmf_get_ifp(drvr, ifidx)), id, 241 bcdc->reqid); 242 ret = -EINVAL; 243 goto done; 244 } 245 246 ret = 0; 247 248 /* Check the ERROR flag */ 249 if (flags & BCDC_DCMD_ERROR) 250 *fwerr = le32_to_cpu(msg->status); 251 252 done: 253 return ret; 254 } 255 256 static void 257 brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, 258 struct sk_buff *pktbuf) 259 { 260 struct brcmf_proto_bcdc_header *h; 261 262 brcmf_dbg(BCDC, "Enter\n"); 263 264 /* Push BDC header used to convey priority for buses that don't */ 265 skb_push(pktbuf, BCDC_HEADER_LEN); 266 267 h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); 268 269 h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT); 270 if (pktbuf->ip_summed == CHECKSUM_PARTIAL) 271 h->flags |= BCDC_FLAG_SUM_NEEDED; 272 273 h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK); 274 h->flags2 = 0; 275 h->data_offset = offset; 276 BCDC_SET_IF_IDX(h, ifidx); 277 trace_brcmf_bcdchdr(pktbuf->data); 278 } 279 280 static int 281 brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, 282 struct sk_buff *pktbuf, struct brcmf_if **ifp) 283 { 284 struct brcmf_proto_bcdc_header *h; 285 struct brcmf_if *tmp_if; 286 287 brcmf_dbg(BCDC, "Enter\n"); 288 289 /* Pop BCDC header used to convey priority for buses that don't */ 290 if (pktbuf->len <= BCDC_HEADER_LEN) { 291 brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", 292 pktbuf->len, BCDC_HEADER_LEN); 293 return -EBADE; 294 } 295 296 trace_brcmf_bcdchdr(pktbuf->data); 297 h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); 298 299 tmp_if = brcmf_get_ifp(drvr, BCDC_GET_IF_IDX(h)); 300 if (!tmp_if) { 301 brcmf_dbg(INFO, "no matching ifp found\n"); 302 return -EBADE; 303 } 304 if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != 305 BCDC_PROTO_VER) { 306 bphy_err(drvr, "%s: non-BCDC packet received, flags 0x%x\n", 307 brcmf_ifname(tmp_if), h->flags); 308 return -EBADE; 309 } 310 311 if (h->flags & BCDC_FLAG_SUM_GOOD) { 312 brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", 313 brcmf_ifname(tmp_if), h->flags); 314 pktbuf->ip_summed = CHECKSUM_UNNECESSARY; 315 } 316 317 pktbuf->priority = h->priority & BCDC_PRIORITY_MASK; 318 319 skb_pull(pktbuf, BCDC_HEADER_LEN); 320 if (do_fws) 321 brcmf_fws_hdrpull(tmp_if, h->data_offset << 2, pktbuf); 322 else 323 skb_pull(pktbuf, h->data_offset << 2); 324 325 if (pktbuf->len == 0) 326 return -ENODATA; 327 328 if (ifp != NULL) 329 *ifp = tmp_if; 330 return 0; 331 } 332 333 static int brcmf_proto_bcdc_tx_queue_data(struct brcmf_pub *drvr, int ifidx, 334 struct sk_buff *skb) 335 { 336 struct brcmf_if *ifp = brcmf_get_ifp(drvr, ifidx); 337 struct brcmf_bcdc *bcdc = drvr->proto->pd; 338 339 if (!brcmf_fws_queue_skbs(bcdc->fws)) 340 return brcmf_proto_txdata(drvr, ifidx, 0, skb); 341 342 return brcmf_fws_process_skb(ifp, skb); 343 } 344 345 static int 346 brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset, 347 struct sk_buff *pktbuf) 348 { 349 brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf); 350 return brcmf_bus_txdata(drvr->bus_if, pktbuf); 351 } 352 353 void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state) 354 { 355 struct brcmf_bus *bus_if = dev_get_drvdata(dev); 356 struct brcmf_pub *drvr = bus_if->drvr; 357 358 brcmf_dbg(TRACE, "Enter\n"); 359 360 brcmf_fws_bus_blocked(drvr, state); 361 } 362 363 void 364 brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp, 365 bool success) 366 { 367 struct brcmf_bus *bus_if = dev_get_drvdata(dev); 368 struct brcmf_bcdc *bcdc = bus_if->drvr->proto->pd; 369 struct brcmf_if *ifp; 370 371 /* await txstatus signal for firmware if active */ 372 if (brcmf_fws_fc_active(bcdc->fws)) { 373 brcmf_fws_bustxcomplete(bcdc->fws, txp, success); 374 } else { 375 if (brcmf_proto_bcdc_hdrpull(bus_if->drvr, false, txp, &ifp)) 376 brcmu_pkt_buf_free_skb(txp); 377 else 378 brcmf_txfinalize(ifp, txp, success); 379 } 380 } 381 382 static void 383 brcmf_proto_bcdc_configure_addr_mode(struct brcmf_pub *drvr, int ifidx, 384 enum proto_addr_mode addr_mode) 385 { 386 } 387 388 static void 389 brcmf_proto_bcdc_delete_peer(struct brcmf_pub *drvr, int ifidx, 390 u8 peer[ETH_ALEN]) 391 { 392 } 393 394 static void 395 brcmf_proto_bcdc_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, 396 u8 peer[ETH_ALEN]) 397 { 398 } 399 400 static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp, 401 struct sk_buff *skb) 402 { 403 brcmf_fws_rxreorder(ifp, skb); 404 } 405 406 static void 407 brcmf_proto_bcdc_add_if(struct brcmf_if *ifp) 408 { 409 brcmf_fws_add_interface(ifp); 410 } 411 412 static void 413 brcmf_proto_bcdc_del_if(struct brcmf_if *ifp) 414 { 415 brcmf_fws_del_interface(ifp); 416 } 417 418 static void 419 brcmf_proto_bcdc_reset_if(struct brcmf_if *ifp) 420 { 421 brcmf_fws_reset_interface(ifp); 422 } 423 424 static int 425 brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr) 426 { 427 struct brcmf_bcdc *bcdc = drvr->proto->pd; 428 struct brcmf_fws_info *fws; 429 430 fws = brcmf_fws_attach(drvr); 431 if (IS_ERR(fws)) 432 return PTR_ERR(fws); 433 434 bcdc->fws = fws; 435 return 0; 436 } 437 438 static void brcmf_proto_bcdc_debugfs_create(struct brcmf_pub *drvr) 439 { 440 brcmf_fws_debugfs_create(drvr); 441 } 442 443 int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) 444 { 445 struct brcmf_bcdc *bcdc; 446 447 bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC); 448 if (!bcdc) 449 goto fail; 450 451 /* ensure that the msg buf directly follows the cdc msg struct */ 452 if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) { 453 bphy_err(drvr, "struct brcmf_proto_bcdc is not correctly defined\n"); 454 goto fail; 455 } 456 457 drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull; 458 drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd; 459 drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; 460 drvr->proto->tx_queue_data = brcmf_proto_bcdc_tx_queue_data; 461 drvr->proto->txdata = brcmf_proto_bcdc_txdata; 462 drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode; 463 drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer; 464 drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer; 465 drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder; 466 drvr->proto->add_if = brcmf_proto_bcdc_add_if; 467 drvr->proto->del_if = brcmf_proto_bcdc_del_if; 468 drvr->proto->reset_if = brcmf_proto_bcdc_reset_if; 469 drvr->proto->init_done = brcmf_proto_bcdc_init_done; 470 drvr->proto->debugfs_create = brcmf_proto_bcdc_debugfs_create; 471 drvr->proto->pd = bcdc; 472 473 drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; 474 drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + 475 sizeof(struct brcmf_proto_bcdc_dcmd) + ROUND_UP_MARGIN; 476 return 0; 477 478 fail: 479 kfree(bcdc); 480 return -ENOMEM; 481 } 482 483 void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) 484 { 485 struct brcmf_bcdc *bcdc = drvr->proto->pd; 486 487 drvr->proto->pd = NULL; 488 brcmf_fws_detach(bcdc->fws); 489 kfree(bcdc); 490 } 491