root/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. drvr_to_fws
  2. brcmf_proto_bcdc_msg
  3. brcmf_proto_bcdc_cmplt
  4. brcmf_proto_bcdc_query_dcmd
  5. brcmf_proto_bcdc_set_dcmd
  6. brcmf_proto_bcdc_hdrpush
  7. brcmf_proto_bcdc_hdrpull
  8. brcmf_proto_bcdc_tx_queue_data
  9. brcmf_proto_bcdc_txdata
  10. brcmf_proto_bcdc_txflowblock
  11. brcmf_proto_bcdc_txcomplete
  12. brcmf_proto_bcdc_configure_addr_mode
  13. brcmf_proto_bcdc_delete_peer
  14. brcmf_proto_bcdc_add_tdls_peer
  15. brcmf_proto_bcdc_rxreorder
  16. brcmf_proto_bcdc_add_if
  17. brcmf_proto_bcdc_del_if
  18. brcmf_proto_bcdc_reset_if
  19. brcmf_proto_bcdc_init_done
  20. brcmf_proto_bcdc_debugfs_create
  21. brcmf_proto_bcdc_attach
  22. brcmf_proto_bcdc_detach

   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)
 401 {
 402         brcmf_fws_rxreorder(ifp, skb);
 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 }

/* [<][>][^][v][top][bottom][index][help] */