forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-12 a5969cabbb4660eab42b6ef0412cbbd1200cf14d
kernel/drivers/net/wireless/ath/wil6210/fw_inc.c
....@@ -1,18 +1,7 @@
1
+// SPDX-License-Identifier: ISC
12 /*
23 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
3
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4
- *
5
- * Permission to use, copy, modify, and/or distribute this software for any
6
- * purpose with or without fee is hereby granted, provided that the above
7
- * copyright notice and this permission notice appear in all copies.
8
- *
9
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
165 */
176
187 /* Algorithmic part of the firmware download.
....@@ -156,17 +145,52 @@
156145 size_t size)
157146 {
158147 const struct wil_fw_record_brd_file *rec = data;
148
+ u32 max_num_ent, i, ent_size;
159149
160
- if (size < sizeof(*rec)) {
161
- wil_err_fw(wil, "brd_file record too short: %zu\n", size);
162
- return 0;
150
+ if (size <= offsetof(struct wil_fw_record_brd_file, brd_info)) {
151
+ wil_err(wil, "board record too short, size %zu\n", size);
152
+ return -EINVAL;
163153 }
164154
165
- wil->brd_file_addr = le32_to_cpu(rec->base_addr);
166
- wil->brd_file_max_size = le32_to_cpu(rec->max_size_bytes);
155
+ ent_size = size - offsetof(struct wil_fw_record_brd_file, brd_info);
156
+ max_num_ent = ent_size / sizeof(struct brd_info);
167157
168
- wil_dbg_fw(wil, "brd_file_addr 0x%x, brd_file_max_size %d\n",
169
- wil->brd_file_addr, wil->brd_file_max_size);
158
+ if (!max_num_ent) {
159
+ wil_err(wil, "brd info entries are missing\n");
160
+ return -EINVAL;
161
+ }
162
+
163
+ wil->brd_info = kcalloc(max_num_ent, sizeof(struct wil_brd_info),
164
+ GFP_KERNEL);
165
+ if (!wil->brd_info)
166
+ return -ENOMEM;
167
+
168
+ for (i = 0; i < max_num_ent; i++) {
169
+ wil->brd_info[i].file_addr =
170
+ le32_to_cpu(rec->brd_info[i].base_addr);
171
+ wil->brd_info[i].file_max_size =
172
+ le32_to_cpu(rec->brd_info[i].max_size_bytes);
173
+
174
+ if (!wil->brd_info[i].file_addr)
175
+ break;
176
+
177
+ wil_dbg_fw(wil,
178
+ "brd info %d: file_addr 0x%x, file_max_size %d\n",
179
+ i, wil->brd_info[i].file_addr,
180
+ wil->brd_info[i].file_max_size);
181
+ }
182
+
183
+ wil->num_of_brd_entries = i;
184
+ if (wil->num_of_brd_entries == 0) {
185
+ kfree(wil->brd_info);
186
+ wil->brd_info = NULL;
187
+ wil_dbg_fw(wil,
188
+ "no valid brd info entries, using brd file addr\n");
189
+
190
+ } else {
191
+ wil_dbg_fw(wil, "num of brd info entries %d\n",
192
+ wil->num_of_brd_entries);
193
+ }
170194
171195 return 0;
172196 }
....@@ -634,6 +658,11 @@
634658 }
635659 wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
636660
661
+ /* re-initialize board info params */
662
+ wil->num_of_brd_entries = 0;
663
+ kfree(wil->brd_info);
664
+ wil->brd_info = NULL;
665
+
637666 for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) {
638667 rc1 = wil_fw_verify(wil, d, sz);
639668 if (rc1 < 0) {
....@@ -647,6 +676,8 @@
647676
648677 out:
649678 release_firmware(fw);
679
+ if (rc)
680
+ wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc);
650681 return rc;
651682 }
652683
....@@ -660,11 +691,13 @@
660691 {
661692 int rc = 0;
662693 const struct wil_fw_record_head *hdr = data;
663
- size_t s, hdr_sz;
694
+ size_t s, hdr_sz = 0;
664695 u16 type;
696
+ int i = 0;
665697
666
- /* Assuming the board file includes only one header record and one data
667
- * record. Each record starts with wil_fw_record_head.
698
+ /* Assuming the board file includes only one file header
699
+ * and one or several data records.
700
+ * Each record starts with wil_fw_record_head.
668701 */
669702 if (size < sizeof(*hdr))
670703 return -EINVAL;
....@@ -672,40 +705,67 @@
672705 if (s > size)
673706 return -EINVAL;
674707
675
- /* Skip the header record and handle the data record */
676
- hdr = (const void *)hdr + s;
708
+ /* Skip the header record and handle the data records */
677709 size -= s;
678
- if (size < sizeof(*hdr))
679
- return -EINVAL;
680
- hdr_sz = le32_to_cpu(hdr->size);
681710
682
- if (wil->brd_file_max_size && hdr_sz > wil->brd_file_max_size)
683
- return -EINVAL;
684
- if (sizeof(*hdr) + hdr_sz > size)
685
- return -EINVAL;
686
- if (hdr_sz % 4) {
687
- wil_err_fw(wil, "unaligned record size: %zu\n",
688
- hdr_sz);
689
- return -EINVAL;
711
+ for (hdr = data + s;; hdr = (const void *)hdr + s, size -= s, i++) {
712
+ if (size < sizeof(*hdr))
713
+ break;
714
+
715
+ if (i >= wil->num_of_brd_entries) {
716
+ wil_err_fw(wil,
717
+ "Too many brd records: %d, num of expected entries %d\n",
718
+ i, wil->num_of_brd_entries);
719
+ break;
720
+ }
721
+
722
+ hdr_sz = le32_to_cpu(hdr->size);
723
+ s = sizeof(*hdr) + hdr_sz;
724
+ if (wil->brd_info[i].file_max_size &&
725
+ hdr_sz > wil->brd_info[i].file_max_size)
726
+ return -EINVAL;
727
+ if (sizeof(*hdr) + hdr_sz > size)
728
+ return -EINVAL;
729
+ if (hdr_sz % 4) {
730
+ wil_err_fw(wil, "unaligned record size: %zu\n",
731
+ hdr_sz);
732
+ return -EINVAL;
733
+ }
734
+ type = le16_to_cpu(hdr->type);
735
+ if (type != wil_fw_type_data) {
736
+ wil_err_fw(wil,
737
+ "invalid record type for board file: %d\n",
738
+ type);
739
+ return -EINVAL;
740
+ }
741
+ if (hdr_sz < sizeof(struct wil_fw_record_data)) {
742
+ wil_err_fw(wil, "data record too short: %zu\n", hdr_sz);
743
+ return -EINVAL;
744
+ }
745
+
746
+ wil_dbg_fw(wil,
747
+ "using info from fw file for record %d: addr[0x%08x], max size %d\n",
748
+ i, wil->brd_info[i].file_addr,
749
+ wil->brd_info[i].file_max_size);
750
+
751
+ rc = __fw_handle_data(wil, &hdr[1], hdr_sz,
752
+ cpu_to_le32(wil->brd_info[i].file_addr));
753
+ if (rc)
754
+ return rc;
690755 }
691
- type = le16_to_cpu(hdr->type);
692
- if (type != wil_fw_type_data) {
693
- wil_err_fw(wil, "invalid record type for board file: %d\n",
694
- type);
695
- return -EINVAL;
696
- }
697
- if (hdr_sz < sizeof(struct wil_fw_record_data)) {
698
- wil_err_fw(wil, "data record too short: %zu\n", hdr_sz);
756
+
757
+ if (size) {
758
+ wil_err_fw(wil, "unprocessed bytes: %zu\n", size);
759
+ if (size >= sizeof(*hdr)) {
760
+ wil_err_fw(wil,
761
+ "Stop at offset %ld record type %d [%zd bytes]\n",
762
+ (long)((const void *)hdr - data),
763
+ le16_to_cpu(hdr->type), hdr_sz);
764
+ }
699765 return -EINVAL;
700766 }
701767
702
- wil_dbg_fw(wil, "using addr from fw file: [0x%08x]\n",
703
- wil->brd_file_addr);
704
-
705
- rc = __fw_handle_data(wil, &hdr[1], hdr_sz,
706
- cpu_to_le32(wil->brd_file_addr));
707
-
708
- return rc;
768
+ return 0;
709769 }
710770
711771 /**
....@@ -736,11 +796,14 @@
736796 rc = dlen;
737797 goto out;
738798 }
739
- /* Process the data record */
799
+
800
+ /* Process the data records */
740801 rc = wil_brd_process(wil, brd->data, dlen);
741802
742803 out:
743804 release_firmware(brd);
805
+ if (rc)
806
+ wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc);
744807 return rc;
745808 }
746809