hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
....@@ -1,19 +1,9 @@
1
+// SPDX-License-Identifier: ISC
12 /*
23 * Copyright (c) 2013 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.
154 */
165
6
+#include <linux/efi.h>
177 #include <linux/kernel.h>
188 #include <linux/slab.h>
199 #include <linux/device.h>
....@@ -46,7 +36,7 @@
4636 * @state: current parser state.
4737 * @data: input buffer being parsed.
4838 * @nvram: output buffer with parse result.
49
- * @nvram_len: lenght of parse result.
39
+ * @nvram_len: length of parse result.
5040 * @line: current line.
5141 * @column: current column in line.
5242 * @pos: byte offset in input buffer.
....@@ -69,7 +59,7 @@
6959 bool boardrev_found;
7060 };
7161
72
-/**
62
+/*
7363 * is_nvram_char() - check if char is a valid one for NVRAM entry
7464 *
7565 * It accepts all printable ASCII chars except for '#' which opens a comment.
....@@ -217,6 +207,8 @@
217207 size = BRCMF_FW_MAX_NVRAM_SIZE;
218208 else
219209 size = data_len;
210
+ /* Add space for properties we may add */
211
+ size += strlen(BRCMF_FW_DEFAULT_BOARDREV) + 1;
220212 /* Alloc for extra 0 byte + roundup by 4 + length field */
221213 size += 1 + 3 + sizeof(u32);
222214 nvp->nvram = kzalloc(size, GFP_KERNEL);
....@@ -445,6 +437,75 @@
445437
446438 static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
447439
440
+#ifdef CONFIG_EFI
441
+/* In some cases the EFI-var stored nvram contains "ccode=ALL" or "ccode=XV"
442
+ * to specify "worldwide" compatible settings, but these 2 ccode-s do not work
443
+ * properly. "ccode=ALL" causes channels 12 and 13 to not be available,
444
+ * "ccode=XV" causes all 5GHz channels to not be available. So we replace both
445
+ * with "ccode=X2" which allows channels 12+13 and 5Ghz channels in
446
+ * no-Initiate-Radiation mode. This means that we will never send on these
447
+ * channels without first having received valid wifi traffic on the channel.
448
+ */
449
+static void brcmf_fw_fix_efi_nvram_ccode(char *data, unsigned long data_len)
450
+{
451
+ char *ccode;
452
+
453
+ ccode = strnstr((char *)data, "ccode=ALL", data_len);
454
+ if (!ccode)
455
+ ccode = strnstr((char *)data, "ccode=XV\r", data_len);
456
+ if (!ccode)
457
+ return;
458
+
459
+ ccode[6] = 'X';
460
+ ccode[7] = '2';
461
+ ccode[8] = '\r';
462
+}
463
+
464
+static u8 *brcmf_fw_nvram_from_efi(size_t *data_len_ret)
465
+{
466
+ const u16 name[] = { 'n', 'v', 'r', 'a', 'm', 0 };
467
+ struct efivar_entry *nvram_efivar;
468
+ unsigned long data_len = 0;
469
+ u8 *data = NULL;
470
+ int err;
471
+
472
+ nvram_efivar = kzalloc(sizeof(*nvram_efivar), GFP_KERNEL);
473
+ if (!nvram_efivar)
474
+ return NULL;
475
+
476
+ memcpy(&nvram_efivar->var.VariableName, name, sizeof(name));
477
+ nvram_efivar->var.VendorGuid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61,
478
+ 0xb5, 0x1f, 0x43, 0x26,
479
+ 0x81, 0x23, 0xd1, 0x13);
480
+
481
+ err = efivar_entry_size(nvram_efivar, &data_len);
482
+ if (err)
483
+ goto fail;
484
+
485
+ data = kmalloc(data_len, GFP_KERNEL);
486
+ if (!data)
487
+ goto fail;
488
+
489
+ err = efivar_entry_get(nvram_efivar, NULL, &data_len, data);
490
+ if (err)
491
+ goto fail;
492
+
493
+ brcmf_fw_fix_efi_nvram_ccode(data, data_len);
494
+ brcmf_info("Using nvram EFI variable\n");
495
+
496
+ kfree(nvram_efivar);
497
+ *data_len_ret = data_len;
498
+ return data;
499
+
500
+fail:
501
+ kfree(data);
502
+ kfree(nvram_efivar);
503
+ return NULL;
504
+}
505
+#else
506
+static inline u8 *brcmf_fw_nvram_from_efi(size_t *data_len) { return NULL; }
507
+#endif
508
+
448509 static void brcmf_fw_free_request(struct brcmf_fw_request *req)
449510 {
450511 struct brcmf_fw_item *item;
....@@ -463,11 +524,12 @@
463524 {
464525 struct brcmf_fw *fwctx = ctx;
465526 struct brcmf_fw_item *cur;
527
+ bool free_bcm47xx_nvram = false;
528
+ bool kfree_nvram = false;
466529 u32 nvram_length = 0;
467530 void *nvram = NULL;
468531 u8 *data = NULL;
469532 size_t data_len;
470
- bool raw_nvram;
471533
472534 brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
473535
....@@ -476,12 +538,13 @@
476538 if (fw && fw->data) {
477539 data = (u8 *)fw->data;
478540 data_len = fw->size;
479
- raw_nvram = false;
480541 } else {
481
- data = bcm47xx_nvram_get_contents(&data_len);
482
- if (!data && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
542
+ if ((data = bcm47xx_nvram_get_contents(&data_len)))
543
+ free_bcm47xx_nvram = true;
544
+ else if ((data = brcmf_fw_nvram_from_efi(&data_len)))
545
+ kfree_nvram = true;
546
+ else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL))
483547 goto fail;
484
- raw_nvram = true;
485548 }
486549
487550 if (data)
....@@ -489,8 +552,11 @@
489552 fwctx->req->domain_nr,
490553 fwctx->req->bus_nr);
491554
492
- if (raw_nvram)
555
+ if (free_bcm47xx_nvram)
493556 bcm47xx_nvram_release_contents(data);
557
+ if (kfree_nvram)
558
+ kfree(data);
559
+
494560 release_firmware(fw);
495561 if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
496562 goto fail;
....@@ -504,90 +570,75 @@
504570 return -ENOENT;
505571 }
506572
507
-static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async)
573
+static int brcmf_fw_complete_request(const struct firmware *fw,
574
+ struct brcmf_fw *fwctx)
508575 {
509
- struct brcmf_fw_item *cur;
510
- const struct firmware *fw = NULL;
511
- int ret;
512
-
513
- cur = &fwctx->req->items[fwctx->curpos];
514
-
515
- brcmf_dbg(TRACE, "%srequest for %s\n", async ? "async " : "",
516
- cur->path);
517
-
518
- if (async)
519
- ret = request_firmware_nowait(THIS_MODULE, true, cur->path,
520
- fwctx->dev, GFP_KERNEL, fwctx,
521
- brcmf_fw_request_done);
522
- else
523
- ret = request_firmware(&fw, cur->path, fwctx->dev);
524
-
525
- if (ret < 0) {
526
- brcmf_fw_request_done(NULL, fwctx);
527
- } else if (!async && fw) {
528
- brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path,
529
- fw ? "" : "not ");
530
- if (cur->type == BRCMF_FW_TYPE_BINARY)
531
- cur->binary = fw;
532
- else if (cur->type == BRCMF_FW_TYPE_NVRAM)
533
- brcmf_fw_request_nvram_done(fw, fwctx);
534
- else
535
- release_firmware(fw);
536
-
537
- return -EAGAIN;
538
- }
539
- return 0;
540
-}
541
-
542
-static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
543
-{
544
- struct brcmf_fw *fwctx = ctx;
545
- struct brcmf_fw_item *cur;
576
+ struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
546577 int ret = 0;
547578
548
- cur = &fwctx->req->items[fwctx->curpos];
549
-
550
- brcmf_dbg(TRACE, "enter: firmware %s %sfound\n", cur->path,
551
- fw ? "" : "not ");
552
-
553
- if (!fw)
554
- ret = -ENOENT;
579
+ brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path, fw ? "" : "not ");
555580
556581 switch (cur->type) {
557582 case BRCMF_FW_TYPE_NVRAM:
558583 ret = brcmf_fw_request_nvram_done(fw, fwctx);
559584 break;
560585 case BRCMF_FW_TYPE_BINARY:
561
- cur->binary = fw;
586
+ if (fw)
587
+ cur->binary = fw;
588
+ else
589
+ ret = -ENOENT;
562590 break;
563591 default:
564592 /* something fishy here so bail out early */
565593 brcmf_err("unknown fw type: %d\n", cur->type);
566594 release_firmware(fw);
567595 ret = -EINVAL;
568
- goto fail;
569596 }
570597
571
- if (ret < 0 && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
572
- goto fail;
598
+ return (cur->flags & BRCMF_FW_REQF_OPTIONAL) ? 0 : ret;
599
+}
573600
574
- do {
575
- if (++fwctx->curpos == fwctx->req->n_items) {
576
- ret = 0;
577
- goto done;
578
- }
601
+static int brcmf_fw_request_firmware(const struct firmware **fw,
602
+ struct brcmf_fw *fwctx)
603
+{
604
+ struct brcmf_fw_item *cur = &fwctx->req->items[fwctx->curpos];
605
+ int ret;
579606
580
- ret = brcmf_fw_request_next_item(fwctx, false);
581
- } while (ret == -EAGAIN);
607
+ /* nvram files are board-specific, first try a board-specific path */
608
+ if (cur->type == BRCMF_FW_TYPE_NVRAM && fwctx->req->board_type) {
609
+ char alt_path[BRCMF_FW_NAME_LEN];
582610
583
- return;
611
+ strlcpy(alt_path, cur->path, BRCMF_FW_NAME_LEN);
612
+ /* strip .txt at the end */
613
+ alt_path[strlen(alt_path) - 4] = 0;
614
+ strlcat(alt_path, ".", BRCMF_FW_NAME_LEN);
615
+ strlcat(alt_path, fwctx->req->board_type, BRCMF_FW_NAME_LEN);
616
+ strlcat(alt_path, ".txt", BRCMF_FW_NAME_LEN);
584617
585
-fail:
586
- brcmf_dbg(TRACE, "failed err=%d: dev=%s, fw=%s\n", ret,
587
- dev_name(fwctx->dev), cur->path);
588
- brcmf_fw_free_request(fwctx->req);
589
- fwctx->req = NULL;
590
-done:
618
+ ret = request_firmware(fw, alt_path, fwctx->dev);
619
+ if (ret == 0)
620
+ return ret;
621
+ }
622
+
623
+ return request_firmware(fw, cur->path, fwctx->dev);
624
+}
625
+
626
+static void brcmf_fw_request_done(const struct firmware *fw, void *ctx)
627
+{
628
+ struct brcmf_fw *fwctx = ctx;
629
+ int ret;
630
+
631
+ ret = brcmf_fw_complete_request(fw, fwctx);
632
+
633
+ while (ret == 0 && ++fwctx->curpos < fwctx->req->n_items) {
634
+ brcmf_fw_request_firmware(&fw, fwctx);
635
+ ret = brcmf_fw_complete_request(fw, ctx);
636
+ }
637
+
638
+ if (ret) {
639
+ brcmf_fw_free_request(fwctx->req);
640
+ fwctx->req = NULL;
641
+ }
591642 fwctx->done(fwctx->dev, ret, fwctx->req);
592643 kfree(fwctx);
593644 }
....@@ -611,7 +662,9 @@
611662 void (*fw_cb)(struct device *dev, int err,
612663 struct brcmf_fw_request *req))
613664 {
665
+ struct brcmf_fw_item *first = &req->items[0];
614666 struct brcmf_fw *fwctx;
667
+ int ret;
615668
616669 brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
617670 if (!fw_cb)
....@@ -628,7 +681,12 @@
628681 fwctx->req = req;
629682 fwctx->done = fw_cb;
630683
631
- brcmf_fw_request_next_item(fwctx, true);
684
+ ret = request_firmware_nowait(THIS_MODULE, true, first->path,
685
+ fwctx->dev, GFP_KERNEL, fwctx,
686
+ brcmf_fw_request_done);
687
+ if (ret < 0)
688
+ brcmf_fw_request_done(NULL, fwctx);
689
+
632690 return 0;
633691 }
634692
....@@ -644,7 +702,11 @@
644702 size_t mp_path_len;
645703 u32 i, j;
646704 char end = '\0';
647
- size_t reqsz;
705
+
706
+ if (chiprev >= BITS_PER_TYPE(u32)) {
707
+ brcmf_err("Invalid chip revision %u\n", chiprev);
708
+ return NULL;
709
+ }
648710
649711 for (i = 0; i < table_size; i++) {
650712 if (mapping_table[i].chipid == chip &&
....@@ -652,17 +714,16 @@
652714 break;
653715 }
654716
717
+ brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname));
718
+
655719 if (i == table_size) {
656
- brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev);
720
+ brcmf_err("Unknown chip %s\n", chipname);
657721 return NULL;
658722 }
659723
660
- reqsz = sizeof(*fwreq) + n_fwnames * sizeof(struct brcmf_fw_item);
661
- fwreq = kzalloc(reqsz, GFP_KERNEL);
724
+ fwreq = kzalloc(struct_size(fwreq, items, n_fwnames), GFP_KERNEL);
662725 if (!fwreq)
663726 return NULL;
664
-
665
- brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname));
666727
667728 brcmf_info("using %s for chip %s\n",
668729 mapping_table[i].fw_base, chipname);
....@@ -676,6 +737,7 @@
676737
677738 for (j = 0; j < n_fwnames; j++) {
678739 fwreq->items[j].path = fwnames[j].path;
740
+ fwnames[j].path[0] = '\0';
679741 /* check if firmware path is provided by module parameter */
680742 if (brcmf_mp_global.firmware_path[0] != '\0') {
681743 strlcpy(fwnames[j].path, mp_path,