1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Atheros CARL9170 driver
7 * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
10 #include <linux/kernel.h>
11 #include <linux/firmware.h>
12 #include <linux/crc32.h>
13 #include <linux/module.h>
18 static const u8 otus_magic
[4] = { OTUS_MAGIC
};
20 static const void *carl9170_fw_find_desc(struct ar9170
*ar
, const u8 descid
[4],
21 const unsigned int len
, const u8 compatible_revision
)
23 const struct carl9170fw_desc_head
*iter
;
25 carl9170fw_for_each_hdr(iter
, ar
->fw
.desc
) {
26 if (carl9170fw_desc_cmp(iter
, descid
, len
,
31 /* needed to find the LAST desc */
32 if (carl9170fw_desc_cmp(iter
, descid
, len
,
39 static int carl9170_fw_verify_descs(struct ar9170
*ar
,
40 const struct carl9170fw_desc_head
*head
, unsigned int max_len
)
42 const struct carl9170fw_desc_head
*pos
;
43 unsigned long pos_addr
, end_addr
;
44 unsigned int pos_length
;
46 if (max_len
< sizeof(*pos
))
49 max_len
= min_t(unsigned int, CARL9170FW_DESC_MAX_LENGTH
, max_len
);
52 pos_addr
= (unsigned long) pos
;
53 end_addr
= pos_addr
+ max_len
;
55 while (pos_addr
< end_addr
) {
56 if (pos_addr
+ sizeof(*head
) > end_addr
)
59 pos_length
= le16_to_cpu(pos
->length
);
61 if (pos_length
< sizeof(*head
))
64 if (pos_length
> max_len
)
67 if (pos_addr
+ pos_length
> end_addr
)
70 if (carl9170fw_desc_cmp(pos
, LAST_MAGIC
,
71 CARL9170FW_LAST_DESC_SIZE
,
72 CARL9170FW_LAST_DESC_CUR_VER
))
75 pos_addr
+= pos_length
;
76 pos
= (void *)pos_addr
;
77 max_len
-= pos_length
;
82 static void carl9170_fw_info(struct ar9170
*ar
)
84 const struct carl9170fw_motd_desc
*motd_desc
;
85 unsigned int str_ver_len
;
88 dev_info(&ar
->udev
->dev
, "driver API: %s 2%03d-%02d-%02d [%d-%d]\n",
89 CARL9170FW_VERSION_GIT
, CARL9170FW_VERSION_YEAR
,
90 CARL9170FW_VERSION_MONTH
, CARL9170FW_VERSION_DAY
,
91 CARL9170FW_API_MIN_VER
, CARL9170FW_API_MAX_VER
);
93 motd_desc
= carl9170_fw_find_desc(ar
, MOTD_MAGIC
,
94 sizeof(*motd_desc
), CARL9170FW_MOTD_DESC_CUR_VER
);
97 str_ver_len
= strnlen(motd_desc
->release
,
98 CARL9170FW_MOTD_RELEASE_LEN
);
100 fw_date
= le32_to_cpu(motd_desc
->fw_year_month_day
);
102 dev_info(&ar
->udev
->dev
, "firmware API: %.*s 2%03d-%02d-%02d\n",
103 str_ver_len
, motd_desc
->release
,
104 CARL9170FW_GET_YEAR(fw_date
),
105 CARL9170FW_GET_MONTH(fw_date
),
106 CARL9170FW_GET_DAY(fw_date
));
108 strlcpy(ar
->hw
->wiphy
->fw_version
, motd_desc
->release
,
109 sizeof(ar
->hw
->wiphy
->fw_version
));
113 static bool valid_dma_addr(const u32 address
)
115 if (address
>= AR9170_SRAM_OFFSET
&&
116 address
< (AR9170_SRAM_OFFSET
+ AR9170_SRAM_SIZE
))
122 static bool valid_cpu_addr(const u32 address
)
124 if (valid_dma_addr(address
) || (address
>= AR9170_PRAM_OFFSET
&&
125 address
< (AR9170_PRAM_OFFSET
+ AR9170_PRAM_SIZE
)))
131 static int carl9170_fw_checksum(struct ar9170
*ar
, const __u8
*data
,
134 const struct carl9170fw_otus_desc
*otus_desc
;
135 const struct carl9170fw_last_desc
*last_desc
;
136 const struct carl9170fw_chk_desc
*chk_desc
;
137 unsigned long fin
, diff
;
138 unsigned int dsc_len
;
141 last_desc
= carl9170_fw_find_desc(ar
, LAST_MAGIC
,
142 sizeof(*last_desc
), CARL9170FW_LAST_DESC_CUR_VER
);
146 otus_desc
= carl9170_fw_find_desc(ar
, OTUS_MAGIC
,
147 sizeof(*otus_desc
), CARL9170FW_OTUS_DESC_CUR_VER
);
149 dev_err(&ar
->udev
->dev
, "failed to find compatible firmware "
154 chk_desc
= carl9170_fw_find_desc(ar
, CHK_MAGIC
,
155 sizeof(*chk_desc
), CARL9170FW_CHK_DESC_CUR_VER
);
158 dev_warn(&ar
->udev
->dev
, "Unprotected firmware image.\n");
162 dsc_len
= min_t(unsigned int, len
,
163 (unsigned long)chk_desc
- (unsigned long)otus_desc
);
165 fin
= (unsigned long) last_desc
+ sizeof(*last_desc
);
166 diff
= fin
- (unsigned long) otus_desc
;
174 crc32
= crc32_le(~0, data
, len
);
175 if (cpu_to_le32(crc32
) != chk_desc
->fw_crc32
) {
176 dev_err(&ar
->udev
->dev
, "fw checksum test failed.\n");
180 crc32
= crc32_le(crc32
, (void *)otus_desc
, dsc_len
);
181 if (cpu_to_le32(crc32
) != chk_desc
->hdr_crc32
) {
182 dev_err(&ar
->udev
->dev
, "descriptor check failed.\n");
188 static int carl9170_fw_tx_sequence(struct ar9170
*ar
)
190 const struct carl9170fw_txsq_desc
*txsq_desc
;
192 txsq_desc
= carl9170_fw_find_desc(ar
, TXSQ_MAGIC
, sizeof(*txsq_desc
),
193 CARL9170FW_TXSQ_DESC_CUR_VER
);
195 ar
->fw
.tx_seq_table
= le32_to_cpu(txsq_desc
->seq_table_addr
);
196 if (!valid_cpu_addr(ar
->fw
.tx_seq_table
))
199 ar
->fw
.tx_seq_table
= 0;
205 static void carl9170_fw_set_if_combinations(struct ar9170
*ar
,
208 if (ar
->fw
.vif_num
< 2)
211 ar
->if_comb_limits
[0].max
= ar
->fw
.vif_num
;
212 ar
->if_comb_limits
[0].types
= if_comb_types
;
214 ar
->if_combs
[0].num_different_channels
= 1;
215 ar
->if_combs
[0].max_interfaces
= ar
->fw
.vif_num
;
216 ar
->if_combs
[0].limits
= ar
->if_comb_limits
;
217 ar
->if_combs
[0].n_limits
= ARRAY_SIZE(ar
->if_comb_limits
);
219 ar
->hw
->wiphy
->iface_combinations
= ar
->if_combs
;
220 ar
->hw
->wiphy
->n_iface_combinations
= ARRAY_SIZE(ar
->if_combs
);
223 static int carl9170_fw(struct ar9170
*ar
, const __u8
*data
, size_t len
)
225 const struct carl9170fw_otus_desc
*otus_desc
;
229 err
= carl9170_fw_checksum(ar
, data
, len
);
233 otus_desc
= carl9170_fw_find_desc(ar
, OTUS_MAGIC
,
234 sizeof(*otus_desc
), CARL9170FW_OTUS_DESC_CUR_VER
);
240 (carl9170fw_supports(otus_desc->feature_set, feat))
242 if (!SUPP(CARL9170FW_DUMMY_FEATURE
)) {
243 dev_err(&ar
->udev
->dev
, "invalid firmware descriptor "
244 "format detected.\n");
248 ar
->fw
.api_version
= otus_desc
->api_ver
;
250 if (ar
->fw
.api_version
< CARL9170FW_API_MIN_VER
||
251 ar
->fw
.api_version
> CARL9170FW_API_MAX_VER
) {
252 dev_err(&ar
->udev
->dev
, "unsupported firmware api version.\n");
256 if (!SUPP(CARL9170FW_COMMAND_PHY
) || SUPP(CARL9170FW_UNUSABLE
) ||
257 !SUPP(CARL9170FW_HANDLE_BACK_REQ
)) {
258 dev_err(&ar
->udev
->dev
, "firmware does support "
259 "mandatory features.\n");
263 if (ilog2(le32_to_cpu(otus_desc
->feature_set
)) >=
264 __CARL9170FW_FEATURE_NUM
) {
265 dev_warn(&ar
->udev
->dev
, "driver does not support all "
266 "firmware features.\n");
269 if (!SUPP(CARL9170FW_COMMAND_CAM
)) {
270 dev_info(&ar
->udev
->dev
, "crypto offloading is disabled "
272 ar
->fw
.disable_offload_fw
= true;
275 if (SUPP(CARL9170FW_PSM
) && SUPP(CARL9170FW_FIXED_5GHZ_PSM
))
276 ieee80211_hw_set(ar
->hw
, SUPPORTS_PS
);
278 if (!SUPP(CARL9170FW_USB_INIT_FIRMWARE
)) {
279 dev_err(&ar
->udev
->dev
, "firmware does not provide "
280 "mandatory interfaces.\n");
284 if (SUPP(CARL9170FW_MINIBOOT
))
285 ar
->fw
.offset
= le16_to_cpu(otus_desc
->miniboot_size
);
289 if (SUPP(CARL9170FW_USB_DOWN_STREAM
)) {
290 ar
->hw
->extra_tx_headroom
+= sizeof(struct ar9170_stream
);
291 ar
->fw
.tx_stream
= true;
294 if (SUPP(CARL9170FW_USB_UP_STREAM
))
295 ar
->fw
.rx_stream
= true;
297 if (SUPP(CARL9170FW_RX_FILTER
)) {
298 ar
->fw
.rx_filter
= true;
299 ar
->rx_filter_caps
= FIF_FCSFAIL
| FIF_PLCPFAIL
|
300 FIF_CONTROL
| FIF_PSPOLL
| FIF_OTHER_BSS
;
303 if (SUPP(CARL9170FW_HW_COUNTERS
))
304 ar
->fw
.hw_counters
= true;
306 if (SUPP(CARL9170FW_WOL
))
307 device_set_wakeup_enable(&ar
->udev
->dev
, true);
309 if (SUPP(CARL9170FW_RX_BA_FILTER
))
310 ar
->fw
.ba_filter
= true;
312 if_comb_types
= BIT(NL80211_IFTYPE_STATION
) |
313 BIT(NL80211_IFTYPE_P2P_CLIENT
);
315 ar
->fw
.vif_num
= otus_desc
->vif_num
;
316 ar
->fw
.cmd_bufs
= otus_desc
->cmd_bufs
;
317 ar
->fw
.address
= le32_to_cpu(otus_desc
->fw_address
);
318 ar
->fw
.rx_size
= le16_to_cpu(otus_desc
->rx_max_frame_len
);
319 ar
->fw
.mem_blocks
= min_t(unsigned int, otus_desc
->tx_descs
, 0xfe);
320 atomic_set(&ar
->mem_free_blocks
, ar
->fw
.mem_blocks
);
321 ar
->fw
.mem_block_size
= le16_to_cpu(otus_desc
->tx_frag_len
);
323 if (ar
->fw
.vif_num
>= AR9170_MAX_VIRTUAL_MAC
|| !ar
->fw
.vif_num
||
324 ar
->fw
.mem_blocks
< 16 || !ar
->fw
.cmd_bufs
||
325 ar
->fw
.mem_block_size
< 64 || ar
->fw
.mem_block_size
> 512 ||
326 ar
->fw
.rx_size
> 32768 || ar
->fw
.rx_size
< 4096 ||
327 !valid_cpu_addr(ar
->fw
.address
)) {
328 dev_err(&ar
->udev
->dev
, "firmware shows obvious signs of "
329 "malicious tampering.\n");
333 ar
->fw
.beacon_addr
= le32_to_cpu(otus_desc
->bcn_addr
);
334 ar
->fw
.beacon_max_len
= le16_to_cpu(otus_desc
->bcn_len
);
336 if (valid_dma_addr(ar
->fw
.beacon_addr
) && ar
->fw
.beacon_max_len
>=
337 AR9170_MAC_BCN_LENGTH_MAX
) {
338 ar
->hw
->wiphy
->interface_modes
|= BIT(NL80211_IFTYPE_ADHOC
);
340 if (SUPP(CARL9170FW_WLANTX_CAB
)) {
341 if_comb_types
|= BIT(NL80211_IFTYPE_AP
);
343 #ifdef CONFIG_MAC80211_MESH
345 BIT(NL80211_IFTYPE_MESH_POINT
);
346 #endif /* CONFIG_MAC80211_MESH */
350 carl9170_fw_set_if_combinations(ar
, if_comb_types
);
352 ar
->hw
->wiphy
->interface_modes
|= if_comb_types
;
354 ar
->hw
->wiphy
->flags
&= ~WIPHY_FLAG_PS_ON_BY_DEFAULT
;
356 /* As IBSS Encryption is software-based, IBSS RSN is supported. */
357 ar
->hw
->wiphy
->flags
|= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
|
358 WIPHY_FLAG_IBSS_RSN
| WIPHY_FLAG_SUPPORTS_TDLS
;
361 return carl9170_fw_tx_sequence(ar
);
364 static struct carl9170fw_desc_head
*
365 carl9170_find_fw_desc(struct ar9170
*ar
, const __u8
*fw_data
, const size_t len
)
368 int scan
= 0, found
= 0;
370 if (!carl9170fw_size_check(len
)) {
371 dev_err(&ar
->udev
->dev
, "firmware size is out of bound.\n");
375 while (scan
< len
- sizeof(struct carl9170fw_desc_head
)) {
376 if (fw_data
[scan
++] == otus_magic
[found
])
384 if (found
== sizeof(otus_magic
))
388 if (found
!= sizeof(otus_magic
))
391 return (void *)&fw_data
[scan
- found
];
394 int carl9170_parse_firmware(struct ar9170
*ar
)
396 const struct carl9170fw_desc_head
*fw_desc
= NULL
;
397 const struct firmware
*fw
= ar
->fw
.fw
;
398 unsigned long header_offset
= 0;
404 fw_desc
= carl9170_find_fw_desc(ar
, fw
->data
, fw
->size
);
407 dev_err(&ar
->udev
->dev
, "unsupported firmware.\n");
411 header_offset
= (unsigned long)fw_desc
- (unsigned long)fw
->data
;
413 err
= carl9170_fw_verify_descs(ar
, fw_desc
, fw
->size
- header_offset
);
415 dev_err(&ar
->udev
->dev
, "damaged firmware (%d).\n", err
);
419 ar
->fw
.desc
= fw_desc
;
421 carl9170_fw_info(ar
);
423 err
= carl9170_fw(ar
, fw
->data
, fw
->size
);
425 dev_err(&ar
->udev
->dev
, "failed to parse firmware (%d).\n",