Commit | Line | Data |
---|---|---|
04b8e659 RL |
1 | // SPDX-License-Identifier: ISC |
2 | /* Copyright (C) 2019 MediaTek Inc. | |
3 | * | |
4 | * Author: Roy Luo <royluo@google.com> | |
5 | * Ryder Lee <ryder.lee@mediatek.com> | |
6 | */ | |
7 | ||
8 | #include <linux/firmware.h> | |
9 | #include "mt7615.h" | |
10 | #include "mcu.h" | |
11 | #include "mac.h" | |
12 | #include "eeprom.h" | |
13 | ||
14 | struct mt7615_patch_hdr { | |
15 | char build_date[16]; | |
16 | char platform[4]; | |
17 | __be32 hw_sw_ver; | |
18 | __be32 patch_ver; | |
19 | __be16 checksum; | |
20 | } __packed; | |
21 | ||
22 | struct mt7615_fw_trailer { | |
23 | __le32 addr; | |
24 | u8 chip_id; | |
25 | u8 feature_set; | |
26 | u8 eco_code; | |
27 | char fw_ver[10]; | |
28 | char build_date[15]; | |
29 | __le32 len; | |
30 | } __packed; | |
31 | ||
32 | #define MCU_PATCH_ADDRESS 0x80000 | |
33 | ||
34 | #define N9_REGION_NUM 2 | |
35 | #define CR4_REGION_NUM 1 | |
36 | ||
37 | #define IMG_CRC_LEN 4 | |
38 | ||
39 | #define FW_FEATURE_SET_ENCRYPT BIT(0) | |
40 | #define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) | |
41 | ||
42 | #define DL_MODE_ENCRYPT BIT(0) | |
43 | #define DL_MODE_KEY_IDX GENMASK(2, 1) | |
44 | #define DL_MODE_RESET_SEC_IV BIT(3) | |
45 | #define DL_MODE_WORKING_PDA_CR4 BIT(4) | |
46 | #define DL_MODE_NEED_RSP BIT(31) | |
47 | ||
48 | #define FW_START_OVERRIDE BIT(0) | |
49 | #define FW_START_WORKING_PDA_CR4 BIT(2) | |
50 | ||
51 | static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb, | |
33d9ed72 | 52 | int cmd, int *wait_seq) |
04b8e659 RL |
53 | { |
54 | struct mt7615_mcu_txd *mcu_txd; | |
55 | u8 seq, q_idx, pkt_fmt; | |
56 | enum mt76_txq_id qid; | |
57 | u32 val; | |
58 | __le32 *txd; | |
59 | ||
04b8e659 RL |
60 | seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf; |
61 | if (!seq) | |
62 | seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf; | |
63 | ||
64 | mcu_txd = (struct mt7615_mcu_txd *)skb_push(skb, | |
65 | sizeof(struct mt7615_mcu_txd)); | |
66 | memset(mcu_txd, 0, sizeof(struct mt7615_mcu_txd)); | |
67 | ||
68 | if (cmd != -MCU_CMD_FW_SCATTER) { | |
69 | q_idx = MT_TX_MCU_PORT_RX_Q0; | |
70 | pkt_fmt = MT_TX_TYPE_CMD; | |
71 | } else { | |
72 | q_idx = MT_TX_MCU_PORT_RX_FWDL; | |
73 | pkt_fmt = MT_TX_TYPE_FW; | |
74 | } | |
75 | ||
76 | txd = mcu_txd->txd; | |
77 | ||
132d8da5 | 78 | val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | |
04b8e659 RL |
79 | FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) | |
80 | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); | |
81 | txd[0] = cpu_to_le32(val); | |
82 | ||
83 | val = MT_TXD1_LONG_FORMAT | | |
84 | FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD) | | |
85 | FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt); | |
86 | txd[1] = cpu_to_le32(val); | |
87 | ||
b28e22bd | 88 | mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); |
04b8e659 RL |
89 | mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx)); |
90 | mcu_txd->pkt_type = MCU_PKT_ID; | |
91 | mcu_txd->seq = seq; | |
92 | ||
93 | if (cmd < 0) { | |
27da3bfd | 94 | mcu_txd->set_query = MCU_Q_NA; |
04b8e659 RL |
95 | mcu_txd->cid = -cmd; |
96 | } else { | |
97 | mcu_txd->cid = MCU_CMD_EXT_CID; | |
27da3bfd | 98 | mcu_txd->set_query = MCU_Q_SET; |
04b8e659 | 99 | mcu_txd->ext_cid = cmd; |
27da3bfd | 100 | mcu_txd->ext_cid_ack = 1; |
04b8e659 | 101 | } |
33d9ed72 | 102 | mcu_txd->s2d_index = MCU_S2D_H2N; |
04b8e659 RL |
103 | |
104 | if (wait_seq) | |
105 | *wait_seq = seq; | |
106 | ||
107 | if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state)) | |
108 | qid = MT_TXQ_MCU; | |
109 | else | |
110 | qid = MT_TXQ_FWDL; | |
111 | ||
112 | return mt76_tx_queue_skb_raw(dev, qid, skb, 0); | |
113 | } | |
114 | ||
0e6a29e4 LB |
115 | static int |
116 | mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, | |
117 | struct sk_buff *skb, int seq) | |
118 | { | |
119 | struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; | |
120 | int ret = 0; | |
121 | ||
122 | if (seq != rxd->seq) | |
123 | return -EAGAIN; | |
124 | ||
125 | switch (cmd) { | |
126 | case -MCU_CMD_PATCH_SEM_CONTROL: | |
127 | skb_pull(skb, sizeof(*rxd) - 4); | |
128 | ret = *skb->data; | |
129 | break; | |
130 | case MCU_EXT_CMD_GET_TEMP: | |
131 | skb_pull(skb, sizeof(*rxd)); | |
132 | ret = le32_to_cpu(*(__le32 *)skb->data); | |
133 | break; | |
134 | default: | |
135 | break; | |
136 | } | |
137 | dev_kfree_skb(skb); | |
138 | ||
139 | return ret; | |
140 | } | |
141 | ||
27da3bfd | 142 | static int |
a3a2c2e7 | 143 | mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, |
516c3e38 | 144 | int len, bool wait_resp) |
04b8e659 | 145 | { |
a3a2c2e7 | 146 | struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); |
04b8e659 | 147 | unsigned long expires = jiffies + 10 * HZ; |
516c3e38 | 148 | struct sk_buff *skb; |
04b8e659 RL |
149 | int ret, seq; |
150 | ||
516c3e38 LB |
151 | skb = mt7615_mcu_msg_alloc(data, len); |
152 | if (!skb) | |
153 | return -ENOMEM; | |
154 | ||
a3a2c2e7 | 155 | mutex_lock(&mdev->mmio.mcu.mutex); |
04b8e659 | 156 | |
33d9ed72 | 157 | ret = __mt7615_mcu_msg_send(dev, skb, cmd, &seq); |
04b8e659 RL |
158 | if (ret) |
159 | goto out; | |
160 | ||
516c3e38 | 161 | while (wait_resp) { |
a3a2c2e7 | 162 | skb = mt76_mcu_get_response(mdev, expires); |
04b8e659 | 163 | if (!skb) { |
a3a2c2e7 | 164 | dev_err(mdev->dev, "Message %d (seq %d) timeout\n", |
04b8e659 RL |
165 | cmd, seq); |
166 | ret = -ETIMEDOUT; | |
167 | break; | |
168 | } | |
169 | ||
0e6a29e4 LB |
170 | ret = mt7615_mcu_parse_response(dev, cmd, skb, seq); |
171 | if (ret != -EAGAIN) | |
172 | break; | |
04b8e659 RL |
173 | } |
174 | ||
175 | out: | |
a3a2c2e7 | 176 | mutex_unlock(&mdev->mmio.mcu.mutex); |
04b8e659 RL |
177 | |
178 | return ret; | |
179 | } | |
180 | ||
5ec87dc8 LB |
181 | static void |
182 | mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) | |
183 | { | |
184 | if (vif->csa_active) | |
185 | ieee80211_csa_finish(vif); | |
186 | } | |
187 | ||
d67a6646 LB |
188 | static void |
189 | mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb) | |
190 | { | |
191 | struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; | |
192 | ||
193 | switch (rxd->ext_eid) { | |
194 | case MCU_EXT_EVENT_RDD_REPORT: | |
195 | ieee80211_radar_detected(dev->mt76.hw); | |
196 | dev->hw_pattern++; | |
197 | break; | |
5ec87dc8 LB |
198 | case MCU_EXT_EVENT_CSA_NOTIFY: |
199 | ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, | |
200 | IEEE80211_IFACE_ITER_RESUME_ALL, | |
201 | mt7615_mcu_csa_finish, dev); | |
202 | break; | |
d67a6646 LB |
203 | default: |
204 | break; | |
205 | } | |
206 | } | |
207 | ||
208 | static void | |
209 | mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) | |
210 | { | |
211 | struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; | |
212 | ||
213 | switch (rxd->eid) { | |
214 | case MCU_EVENT_EXT: | |
215 | mt7615_mcu_rx_ext_event(dev, skb); | |
216 | break; | |
217 | default: | |
218 | break; | |
219 | } | |
220 | dev_kfree_skb(skb); | |
221 | } | |
222 | ||
223 | void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) | |
224 | { | |
225 | struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; | |
226 | ||
227 | if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || | |
228 | rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || | |
229 | rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || | |
230 | rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || | |
231 | !rxd->seq) | |
232 | mt7615_mcu_rx_unsolicited_event(dev, skb); | |
233 | else | |
234 | mt76_mcu_rx_event(&dev->mt76, skb); | |
235 | } | |
236 | ||
04b8e659 RL |
237 | static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr, |
238 | u32 len, u32 mode) | |
239 | { | |
240 | struct { | |
241 | __le32 addr; | |
242 | __le32 len; | |
243 | __le32 mode; | |
244 | } req = { | |
245 | .addr = cpu_to_le32(addr), | |
246 | .len = cpu_to_le32(len), | |
247 | .mode = cpu_to_le32(mode), | |
248 | }; | |
04b8e659 | 249 | |
a3a2c2e7 | 250 | return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ, |
516c3e38 | 251 | &req, sizeof(req), true); |
04b8e659 RL |
252 | } |
253 | ||
254 | static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data, | |
255 | int len) | |
256 | { | |
b28248ec | 257 | int ret = 0, cur_len; |
04b8e659 RL |
258 | |
259 | while (len > 0) { | |
b28248ec LB |
260 | cur_len = min_t(int, 4096 - sizeof(struct mt7615_mcu_txd), |
261 | len); | |
04b8e659 | 262 | |
b28248ec LB |
263 | ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER, |
264 | data, cur_len, false); | |
04b8e659 RL |
265 | if (ret) |
266 | break; | |
267 | ||
268 | data += cur_len; | |
269 | len -= cur_len; | |
5abe8baf | 270 | mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); |
04b8e659 RL |
271 | } |
272 | ||
273 | return ret; | |
274 | } | |
275 | ||
276 | static int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr, | |
277 | u32 option) | |
278 | { | |
279 | struct { | |
280 | __le32 option; | |
281 | __le32 addr; | |
282 | } req = { | |
283 | .option = cpu_to_le32(option), | |
284 | .addr = cpu_to_le32(addr), | |
285 | }; | |
04b8e659 | 286 | |
a3a2c2e7 | 287 | return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, |
516c3e38 | 288 | &req, sizeof(req), true); |
04b8e659 RL |
289 | } |
290 | ||
5d15f2ea | 291 | static int mt7615_mcu_restart(struct mt76_dev *dev) |
04b8e659 | 292 | { |
5d15f2ea LB |
293 | return __mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, |
294 | 0, true); | |
04b8e659 RL |
295 | } |
296 | ||
297 | static int mt7615_mcu_patch_sem_ctrl(struct mt7615_dev *dev, bool get) | |
298 | { | |
299 | struct { | |
893369b7 | 300 | __le32 op; |
04b8e659 | 301 | } req = { |
893369b7 | 302 | .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE), |
04b8e659 | 303 | }; |
04b8e659 | 304 | |
a3a2c2e7 | 305 | return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL, |
516c3e38 | 306 | &req, sizeof(req), true); |
04b8e659 RL |
307 | } |
308 | ||
309 | static int mt7615_mcu_start_patch(struct mt7615_dev *dev) | |
310 | { | |
311 | struct { | |
312 | u8 check_crc; | |
313 | u8 reserved[3]; | |
314 | } req = { | |
315 | .check_crc = 0, | |
316 | }; | |
04b8e659 | 317 | |
a3a2c2e7 | 318 | return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ, |
516c3e38 | 319 | &req, sizeof(req), true); |
04b8e659 RL |
320 | } |
321 | ||
322 | static int mt7615_driver_own(struct mt7615_dev *dev) | |
323 | { | |
324 | mt76_wr(dev, MT_CFG_LPCR_HOST, MT_CFG_LPCR_HOST_DRV_OWN); | |
325 | if (!mt76_poll_msec(dev, MT_CFG_LPCR_HOST, | |
326 | MT_CFG_LPCR_HOST_FW_OWN, 0, 500)) { | |
327 | dev_err(dev->mt76.dev, "Timeout for driver own\n"); | |
328 | return -EIO; | |
329 | } | |
330 | ||
331 | return 0; | |
332 | } | |
333 | ||
334 | static int mt7615_load_patch(struct mt7615_dev *dev) | |
335 | { | |
2fc44648 LB |
336 | const struct mt7615_patch_hdr *hdr; |
337 | const struct firmware *fw = NULL; | |
04b8e659 RL |
338 | int len, ret, sem; |
339 | ||
340 | sem = mt7615_mcu_patch_sem_ctrl(dev, 1); | |
341 | switch (sem) { | |
342 | case PATCH_IS_DL: | |
343 | return 0; | |
344 | case PATCH_NOT_DL_SEM_SUCCESS: | |
345 | break; | |
346 | default: | |
347 | dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); | |
348 | return -EAGAIN; | |
349 | } | |
350 | ||
9d4d0d06 | 351 | ret = request_firmware(&fw, MT7615_ROM_PATCH, dev->mt76.dev); |
04b8e659 | 352 | if (ret) |
2fc44648 | 353 | goto out; |
04b8e659 RL |
354 | |
355 | if (!fw || !fw->data || fw->size < sizeof(*hdr)) { | |
356 | dev_err(dev->mt76.dev, "Invalid firmware\n"); | |
357 | ret = -EINVAL; | |
358 | goto out; | |
359 | } | |
360 | ||
361 | hdr = (const struct mt7615_patch_hdr *)(fw->data); | |
362 | ||
363 | dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", | |
364 | be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); | |
365 | ||
366 | len = fw->size - sizeof(*hdr); | |
367 | ||
368 | ret = mt7615_mcu_init_download(dev, MCU_PATCH_ADDRESS, len, | |
369 | DL_MODE_NEED_RSP); | |
370 | if (ret) { | |
371 | dev_err(dev->mt76.dev, "Download request failed\n"); | |
372 | goto out; | |
373 | } | |
374 | ||
375 | ret = mt7615_mcu_send_firmware(dev, fw->data + sizeof(*hdr), len); | |
376 | if (ret) { | |
377 | dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); | |
378 | goto out; | |
379 | } | |
380 | ||
381 | ret = mt7615_mcu_start_patch(dev); | |
382 | if (ret) | |
383 | dev_err(dev->mt76.dev, "Failed to start patch\n"); | |
384 | ||
385 | out: | |
386 | release_firmware(fw); | |
387 | ||
388 | sem = mt7615_mcu_patch_sem_ctrl(dev, 0); | |
389 | switch (sem) { | |
390 | case PATCH_REL_SEM_SUCCESS: | |
391 | break; | |
392 | default: | |
393 | ret = -EAGAIN; | |
394 | dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); | |
395 | break; | |
396 | } | |
397 | ||
398 | return ret; | |
399 | } | |
400 | ||
6c6a3fe6 | 401 | static u32 mt7615_mcu_gen_dl_mode(u8 feature_set, bool is_cr4) |
04b8e659 RL |
402 | { |
403 | u32 ret = 0; | |
404 | ||
405 | ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? | |
406 | (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; | |
407 | ret |= FIELD_PREP(DL_MODE_KEY_IDX, | |
408 | FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); | |
409 | ret |= DL_MODE_NEED_RSP; | |
410 | ret |= is_cr4 ? DL_MODE_WORKING_PDA_CR4 : 0; | |
411 | ||
412 | return ret; | |
413 | } | |
414 | ||
6c6a3fe6 LB |
415 | static int |
416 | mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, | |
417 | const struct mt7615_fw_trailer *hdr, | |
418 | const u8 *data, bool is_cr4) | |
419 | { | |
420 | int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM; | |
421 | int err, i, offset = 0; | |
422 | u32 len, addr, mode; | |
423 | ||
424 | for (i = 0; i < n_region; i++) { | |
425 | mode = mt7615_mcu_gen_dl_mode(hdr[i].feature_set, is_cr4); | |
426 | len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN; | |
427 | addr = le32_to_cpu(hdr[i].addr); | |
428 | ||
429 | err = mt7615_mcu_init_download(dev, addr, len, mode); | |
430 | if (err) { | |
431 | dev_err(dev->mt76.dev, "Download request failed\n"); | |
432 | return err; | |
433 | } | |
434 | ||
435 | err = mt7615_mcu_send_firmware(dev, data + offset, len); | |
436 | if (err) { | |
437 | dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); | |
438 | return err; | |
439 | } | |
440 | ||
441 | offset += len; | |
442 | } | |
443 | ||
444 | return 0; | |
445 | } | |
446 | ||
04b8e659 RL |
447 | static int mt7615_load_ram(struct mt7615_dev *dev) |
448 | { | |
04b8e659 | 449 | const struct mt7615_fw_trailer *hdr; |
9d4d0d06 | 450 | const struct firmware *fw; |
6c6a3fe6 | 451 | int ret; |
04b8e659 | 452 | |
9d4d0d06 | 453 | ret = request_firmware(&fw, MT7615_FIRMWARE_N9, dev->mt76.dev); |
04b8e659 RL |
454 | if (ret) |
455 | return ret; | |
456 | ||
457 | if (!fw || !fw->data || fw->size < N9_REGION_NUM * sizeof(*hdr)) { | |
458 | dev_err(dev->mt76.dev, "Invalid firmware\n"); | |
459 | ret = -EINVAL; | |
460 | goto out; | |
461 | } | |
462 | ||
463 | hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size - | |
464 | N9_REGION_NUM * sizeof(*hdr)); | |
465 | ||
466 | dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n", | |
467 | hdr->fw_ver, hdr->build_date); | |
468 | ||
6c6a3fe6 LB |
469 | ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false); |
470 | if (ret) | |
471 | goto out; | |
04b8e659 | 472 | |
6c6a3fe6 LB |
473 | ret = mt7615_mcu_start_firmware(dev, le32_to_cpu(hdr->addr), |
474 | FW_START_OVERRIDE); | |
04b8e659 RL |
475 | if (ret) { |
476 | dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); | |
477 | goto out; | |
478 | } | |
479 | ||
480 | release_firmware(fw); | |
481 | ||
9d4d0d06 | 482 | ret = request_firmware(&fw, MT7615_FIRMWARE_CR4, dev->mt76.dev); |
04b8e659 RL |
483 | if (ret) |
484 | return ret; | |
485 | ||
486 | if (!fw || !fw->data || fw->size < CR4_REGION_NUM * sizeof(*hdr)) { | |
487 | dev_err(dev->mt76.dev, "Invalid firmware\n"); | |
488 | ret = -EINVAL; | |
489 | goto out; | |
490 | } | |
491 | ||
492 | hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size - | |
493 | CR4_REGION_NUM * sizeof(*hdr)); | |
494 | ||
495 | dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n", | |
496 | hdr->fw_ver, hdr->build_date); | |
497 | ||
6c6a3fe6 LB |
498 | ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true); |
499 | if (ret) | |
500 | goto out; | |
04b8e659 RL |
501 | |
502 | ret = mt7615_mcu_start_firmware(dev, 0, FW_START_WORKING_PDA_CR4); | |
503 | if (ret) | |
504 | dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n"); | |
505 | ||
506 | out: | |
507 | release_firmware(fw); | |
508 | ||
509 | return ret; | |
510 | } | |
511 | ||
512 | static int mt7615_load_firmware(struct mt7615_dev *dev) | |
513 | { | |
514 | int ret; | |
515 | u32 val; | |
516 | ||
517 | val = mt76_get_field(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE); | |
518 | ||
519 | if (val != FW_STATE_FW_DOWNLOAD) { | |
520 | dev_err(dev->mt76.dev, "Firmware is not ready for download\n"); | |
521 | return -EIO; | |
522 | } | |
523 | ||
524 | ret = mt7615_load_patch(dev); | |
525 | if (ret) | |
526 | return ret; | |
527 | ||
528 | ret = mt7615_load_ram(dev); | |
529 | if (ret) | |
530 | return ret; | |
531 | ||
532 | if (!mt76_poll_msec(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE, | |
533 | FIELD_PREP(MT_TOP_MISC2_FW_STATE, | |
534 | FW_STATE_CR4_RDY), 500)) { | |
535 | dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); | |
536 | return -EIO; | |
537 | } | |
538 | ||
5abe8baf FF |
539 | mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); |
540 | ||
04b8e659 RL |
541 | dev_dbg(dev->mt76.dev, "Firmware init done\n"); |
542 | ||
543 | return 0; | |
544 | } | |
545 | ||
546 | int mt7615_mcu_init(struct mt7615_dev *dev) | |
547 | { | |
a3a2c2e7 LB |
548 | static const struct mt76_mcu_ops mt7615_mcu_ops = { |
549 | .mcu_send_msg = mt7615_mcu_msg_send, | |
5d15f2ea | 550 | .mcu_restart = mt7615_mcu_restart, |
a3a2c2e7 | 551 | }; |
04b8e659 RL |
552 | int ret; |
553 | ||
a3a2c2e7 LB |
554 | dev->mt76.mcu_ops = &mt7615_mcu_ops, |
555 | ||
04b8e659 RL |
556 | ret = mt7615_driver_own(dev); |
557 | if (ret) | |
558 | return ret; | |
559 | ||
560 | ret = mt7615_load_firmware(dev); | |
561 | if (ret) | |
562 | return ret; | |
563 | ||
564 | set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); | |
565 | ||
566 | return 0; | |
567 | } | |
568 | ||
569 | void mt7615_mcu_exit(struct mt7615_dev *dev) | |
570 | { | |
5d15f2ea | 571 | __mt76_mcu_restart(&dev->mt76); |
04b8e659 RL |
572 | mt76_wr(dev, MT_CFG_LPCR_HOST, MT_CFG_LPCR_HOST_FW_OWN); |
573 | skb_queue_purge(&dev->mt76.mmio.mcu.res_q); | |
574 | } | |
575 | ||
576 | int mt7615_mcu_set_eeprom(struct mt7615_dev *dev) | |
577 | { | |
04b8e659 RL |
578 | struct { |
579 | u8 buffer_mode; | |
580 | u8 pad; | |
581 | u16 len; | |
582 | } __packed req_hdr = { | |
583 | .buffer_mode = 1, | |
584 | .len = __MT_EE_MAX - MT_EE_NIC_CONF_0, | |
585 | }; | |
516c3e38 LB |
586 | int ret, len = sizeof(req_hdr) + __MT_EE_MAX - MT_EE_NIC_CONF_0; |
587 | u8 *req, *eep = (u8 *)dev->mt76.eeprom.data; | |
588 | ||
589 | req = kzalloc(len, GFP_KERNEL); | |
590 | if (!req) | |
591 | return -ENOMEM; | |
04b8e659 | 592 | |
516c3e38 LB |
593 | memcpy(req, &req_hdr, sizeof(req_hdr)); |
594 | memcpy(req + sizeof(req_hdr), eep + MT_EE_NIC_CONF_0, | |
595 | __MT_EE_MAX - MT_EE_NIC_CONF_0); | |
04b8e659 | 596 | |
a3a2c2e7 | 597 | ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, |
516c3e38 LB |
598 | req, len, true); |
599 | kfree(req); | |
04b8e659 | 600 | |
516c3e38 | 601 | return ret; |
04b8e659 RL |
602 | } |
603 | ||
604 | int mt7615_mcu_init_mac(struct mt7615_dev *dev) | |
605 | { | |
606 | struct { | |
607 | u8 enable; | |
608 | u8 band; | |
609 | u8 rsv[2]; | |
610 | } __packed req = { | |
611 | .enable = 1, | |
612 | .band = 0, | |
613 | }; | |
04b8e659 | 614 | |
a3a2c2e7 | 615 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL, |
516c3e38 | 616 | &req, sizeof(req), true); |
04b8e659 RL |
617 | } |
618 | ||
619 | int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val) | |
620 | { | |
621 | struct { | |
622 | u8 prot_idx; | |
623 | u8 band; | |
624 | u8 rsv[2]; | |
625 | __le32 len_thresh; | |
626 | __le32 pkt_thresh; | |
627 | } __packed req = { | |
628 | .prot_idx = 1, | |
629 | .band = 0, | |
630 | .len_thresh = cpu_to_le32(val), | |
631 | .pkt_thresh = cpu_to_le32(0x2), | |
632 | }; | |
04b8e659 | 633 | |
a3a2c2e7 | 634 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, |
516c3e38 | 635 | &req, sizeof(req), true); |
04b8e659 RL |
636 | } |
637 | ||
638 | int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, | |
639 | const struct ieee80211_tx_queue_params *params) | |
640 | { | |
641 | #define WMM_AIFS_SET BIT(0) | |
642 | #define WMM_CW_MIN_SET BIT(1) | |
643 | #define WMM_CW_MAX_SET BIT(2) | |
644 | #define WMM_TXOP_SET BIT(3) | |
4f8a4f17 RL |
645 | #define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ |
646 | WMM_CW_MAX_SET | WMM_TXOP_SET) | |
04b8e659 RL |
647 | struct req_data { |
648 | u8 number; | |
649 | u8 rsv[3]; | |
650 | u8 queue; | |
651 | u8 valid; | |
652 | u8 aifs; | |
653 | u8 cw_min; | |
654 | __le16 cw_max; | |
655 | __le16 txop; | |
656 | } __packed req = { | |
657 | .number = 1, | |
658 | .queue = queue, | |
4f8a4f17 | 659 | .valid = WMM_PARAM_SET, |
04b8e659 | 660 | .aifs = params->aifs, |
4f8a4f17 RL |
661 | .cw_min = 5, |
662 | .cw_max = cpu_to_le16(10), | |
04b8e659 RL |
663 | .txop = cpu_to_le16(params->txop), |
664 | }; | |
04b8e659 | 665 | |
4f8a4f17 RL |
666 | if (params->cw_min) |
667 | req.cw_min = fls(params->cw_min); | |
668 | if (params->cw_max) | |
669 | req.cw_max = cpu_to_le16(fls(params->cw_max)); | |
04b8e659 | 670 | |
a3a2c2e7 | 671 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, |
516c3e38 | 672 | &req, sizeof(req), true); |
04b8e659 RL |
673 | } |
674 | ||
675 | int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter) | |
676 | { | |
677 | #define ENTER_PM_STATE 1 | |
678 | #define EXIT_PM_STATE 2 | |
679 | struct { | |
680 | u8 pm_number; | |
681 | u8 pm_state; | |
682 | u8 bssid[ETH_ALEN]; | |
683 | u8 dtim_period; | |
684 | u8 wlan_idx; | |
685 | __le16 bcn_interval; | |
686 | __le32 aid; | |
687 | __le32 rx_filter; | |
688 | u8 band_idx; | |
689 | u8 rsv[3]; | |
690 | __le32 feature; | |
691 | u8 omac_idx; | |
692 | u8 wmm_idx; | |
693 | u8 bcn_loss_cnt; | |
694 | u8 bcn_sp_duration; | |
695 | } __packed req = { | |
696 | .pm_number = 5, | |
697 | .pm_state = (enter) ? ENTER_PM_STATE : EXIT_PM_STATE, | |
698 | .band_idx = 0, | |
699 | }; | |
04b8e659 | 700 | |
a3a2c2e7 | 701 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL, |
516c3e38 | 702 | &req, sizeof(req), true); |
04b8e659 RL |
703 | } |
704 | ||
fddc827f LB |
705 | int mt7615_mcu_set_dev_info(struct mt7615_dev *dev, |
706 | struct ieee80211_vif *vif, bool enable) | |
04b8e659 | 707 | { |
fddc827f LB |
708 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; |
709 | struct { | |
710 | struct req_hdr { | |
711 | u8 omac_idx; | |
712 | u8 band_idx; | |
713 | __le16 tlv_num; | |
714 | u8 is_tlv_append; | |
715 | u8 rsv[3]; | |
716 | } __packed hdr; | |
717 | struct req_tlv { | |
718 | __le16 tag; | |
719 | __le16 len; | |
720 | u8 active; | |
721 | u8 band_idx; | |
722 | u8 omac_addr[ETH_ALEN]; | |
723 | } __packed tlv; | |
724 | } data = { | |
725 | .hdr = { | |
726 | .omac_idx = mvif->omac_idx, | |
727 | .band_idx = mvif->band_idx, | |
728 | .tlv_num = cpu_to_le16(1), | |
729 | .is_tlv_append = 1, | |
730 | }, | |
731 | .tlv = { | |
04b8e659 | 732 | .tag = cpu_to_le16(DEV_INFO_ACTIVE), |
fddc827f LB |
733 | .len = cpu_to_le16(sizeof(struct req_tlv)), |
734 | .active = enable, | |
735 | .band_idx = mvif->band_idx, | |
736 | }, | |
737 | }; | |
04b8e659 | 738 | |
fddc827f | 739 | memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); |
a3a2c2e7 | 740 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE, |
516c3e38 | 741 | &data, sizeof(data), true); |
04b8e659 RL |
742 | } |
743 | ||
1ca8089a LB |
744 | static void |
745 | mt7615_mcu_bss_info_omac_header(struct mt7615_vif *mvif, u8 *data, | |
746 | u32 conn_type) | |
04b8e659 | 747 | { |
1ca8089a LB |
748 | struct bss_info_omac *hdr = (struct bss_info_omac *)data; |
749 | u8 idx; | |
750 | ||
751 | idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; | |
752 | hdr->tag = cpu_to_le16(BSS_INFO_OMAC); | |
753 | hdr->len = cpu_to_le16(sizeof(struct bss_info_omac)); | |
754 | hdr->hw_bss_idx = idx; | |
755 | hdr->omac_idx = mvif->omac_idx; | |
756 | hdr->band_idx = mvif->band_idx; | |
757 | hdr->conn_type = cpu_to_le32(conn_type); | |
04b8e659 RL |
758 | } |
759 | ||
1ca8089a LB |
760 | static void |
761 | mt7615_mcu_bss_info_basic_header(struct ieee80211_vif *vif, u8 *data, | |
762 | u32 net_type, u8 tx_wlan_idx, | |
763 | bool enable) | |
04b8e659 | 764 | { |
1ca8089a LB |
765 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; |
766 | struct bss_info_basic *hdr = (struct bss_info_basic *)data; | |
767 | ||
768 | hdr->tag = cpu_to_le16(BSS_INFO_BASIC); | |
769 | hdr->len = cpu_to_le16(sizeof(struct bss_info_basic)); | |
770 | hdr->network_type = cpu_to_le32(net_type); | |
771 | hdr->active = enable; | |
772 | hdr->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); | |
773 | memcpy(hdr->bssid, vif->bss_conf.bssid, ETH_ALEN); | |
774 | hdr->wmm_idx = mvif->wmm_idx; | |
775 | hdr->dtim_period = vif->bss_conf.dtim_period; | |
776 | hdr->bmc_tx_wlan_idx = tx_wlan_idx; | |
04b8e659 RL |
777 | } |
778 | ||
1ca8089a LB |
779 | static void |
780 | mt7615_mcu_bss_info_ext_header(struct mt7615_vif *mvif, u8 *data) | |
04b8e659 RL |
781 | { |
782 | /* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */ | |
783 | #define BCN_TX_ESTIMATE_TIME (4096 + 20) | |
1ca8089a | 784 | struct bss_info_ext_bss *hdr = (struct bss_info_ext_bss *)data; |
eda96044 | 785 | int ext_bss_idx, tsf_offset; |
04b8e659 | 786 | |
1ca8089a | 787 | ext_bss_idx = mvif->omac_idx - EXT_BSSID_START; |
04b8e659 RL |
788 | if (ext_bss_idx < 0) |
789 | return; | |
790 | ||
1ca8089a LB |
791 | hdr->tag = cpu_to_le16(BSS_INFO_EXT_BSS); |
792 | hdr->len = cpu_to_le16(sizeof(struct bss_info_ext_bss)); | |
eda96044 LB |
793 | tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME; |
794 | hdr->mbss_tsf_offset = cpu_to_le32(tsf_offset); | |
04b8e659 RL |
795 | } |
796 | ||
1ca8089a LB |
797 | int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, |
798 | struct ieee80211_vif *vif, int en) | |
04b8e659 | 799 | { |
1ca8089a | 800 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; |
04b8e659 RL |
801 | struct req_hdr { |
802 | u8 bss_idx; | |
803 | u8 rsv0; | |
804 | __le16 tlv_num; | |
805 | u8 is_tlv_append; | |
806 | u8 rsv1[3]; | |
1ca8089a LB |
807 | } __packed; |
808 | int len = sizeof(struct req_hdr) + sizeof(struct bss_info_basic); | |
809 | int ret, i, features = BIT(BSS_INFO_BASIC), ntlv = 1; | |
810 | u32 conn_type = 0, net_type = NETWORK_INFRA; | |
811 | u8 *buf, *data, tx_wlan_idx = 0; | |
812 | struct req_hdr *hdr; | |
04b8e659 | 813 | |
1ca8089a LB |
814 | if (en) { |
815 | len += sizeof(struct bss_info_omac); | |
816 | features |= BIT(BSS_INFO_OMAC); | |
817 | if (mvif->omac_idx > EXT_BSSID_START) { | |
818 | len += sizeof(struct bss_info_ext_bss); | |
819 | features |= BIT(BSS_INFO_EXT_BSS); | |
820 | ntlv++; | |
821 | } | |
822 | ntlv++; | |
823 | } | |
04b8e659 | 824 | |
b876457c LB |
825 | switch (vif->type) { |
826 | case NL80211_IFTYPE_AP: | |
f4ec7fdf | 827 | case NL80211_IFTYPE_MESH_POINT: |
1ca8089a LB |
828 | tx_wlan_idx = mvif->sta.wcid.idx; |
829 | conn_type = CONNECTION_INFRA_AP; | |
b876457c LB |
830 | break; |
831 | case NL80211_IFTYPE_STATION: { | |
e991c4c2 RL |
832 | /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ |
833 | if (en) { | |
834 | struct ieee80211_sta *sta; | |
835 | struct mt7615_sta *msta; | |
836 | ||
837 | rcu_read_lock(); | |
838 | sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); | |
839 | if (!sta) { | |
840 | rcu_read_unlock(); | |
841 | return -EINVAL; | |
842 | } | |
843 | ||
844 | msta = (struct mt7615_sta *)sta->drv_priv; | |
845 | tx_wlan_idx = msta->wcid.idx; | |
04b8e659 | 846 | rcu_read_unlock(); |
04b8e659 | 847 | } |
1ca8089a | 848 | conn_type = CONNECTION_INFRA_STA; |
b876457c LB |
849 | break; |
850 | } | |
7f4b7920 LB |
851 | case NL80211_IFTYPE_ADHOC: |
852 | conn_type = CONNECTION_IBSS_ADHOC; | |
853 | tx_wlan_idx = mvif->sta.wcid.idx; | |
854 | net_type = NETWORK_IBSS; | |
855 | break; | |
b876457c | 856 | default: |
04b8e659 | 857 | WARN_ON(1); |
b876457c | 858 | break; |
04b8e659 | 859 | } |
b876457c | 860 | |
1ca8089a LB |
861 | buf = kzalloc(len, GFP_KERNEL); |
862 | if (!buf) | |
863 | return -ENOMEM; | |
864 | ||
865 | hdr = (struct req_hdr *)buf; | |
866 | hdr->bss_idx = mvif->idx; | |
867 | hdr->tlv_num = cpu_to_le16(ntlv); | |
868 | hdr->is_tlv_append = 1; | |
869 | ||
870 | data = buf + sizeof(*hdr); | |
871 | for (i = 0; i < BSS_INFO_MAX_NUM; i++) { | |
872 | int tag = ffs(features & BIT(i)) - 1; | |
873 | ||
874 | switch (tag) { | |
875 | case BSS_INFO_OMAC: | |
876 | mt7615_mcu_bss_info_omac_header(mvif, data, | |
877 | conn_type); | |
878 | data += sizeof(struct bss_info_omac); | |
879 | break; | |
880 | case BSS_INFO_BASIC: | |
881 | mt7615_mcu_bss_info_basic_header(vif, data, net_type, | |
882 | tx_wlan_idx, en); | |
883 | data += sizeof(struct bss_info_basic); | |
884 | break; | |
885 | case BSS_INFO_EXT_BSS: | |
886 | mt7615_mcu_bss_info_ext_header(mvif, data); | |
887 | data += sizeof(struct bss_info_ext_bss); | |
888 | break; | |
889 | default: | |
890 | break; | |
891 | } | |
892 | } | |
893 | ||
a3a2c2e7 | 894 | ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BSS_INFO_UPDATE, |
516c3e38 | 895 | buf, len, true); |
1ca8089a LB |
896 | kfree(buf); |
897 | ||
898 | return ret; | |
04b8e659 RL |
899 | } |
900 | ||
598a4434 LB |
901 | static int |
902 | mt7615_mcu_add_wtbl_bmc(struct mt7615_dev *dev, | |
903 | struct mt7615_vif *mvif) | |
04b8e659 | 904 | { |
77eaa281 | 905 | struct { |
516c3e38 | 906 | struct wtbl_req_hdr hdr; |
77eaa281 LB |
907 | struct wtbl_generic g_wtbl; |
908 | struct wtbl_rx rx_wtbl; | |
516c3e38 LB |
909 | } req = { |
910 | .hdr = { | |
911 | .wlan_idx = mvif->sta.wcid.idx, | |
912 | .operation = WTBL_RESET_AND_SET, | |
913 | .tlv_num = cpu_to_le16(2), | |
914 | }, | |
77eaa281 LB |
915 | .g_wtbl = { |
916 | .tag = cpu_to_le16(WTBL_GENERIC), | |
917 | .len = cpu_to_le16(sizeof(struct wtbl_generic)), | |
918 | .muar_idx = 0xe, | |
919 | }, | |
920 | .rx_wtbl = { | |
921 | .tag = cpu_to_le16(WTBL_RX), | |
922 | .len = cpu_to_le16(sizeof(struct wtbl_rx)), | |
923 | .rca1 = 1, | |
924 | .rca2 = 1, | |
925 | .rv = 1, | |
926 | }, | |
927 | }; | |
516c3e38 | 928 | eth_broadcast_addr(req.g_wtbl.peer_addr); |
04b8e659 | 929 | |
a3a2c2e7 | 930 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, |
516c3e38 | 931 | &req, sizeof(req), true); |
04b8e659 RL |
932 | } |
933 | ||
598a4434 LB |
934 | int mt7615_mcu_wtbl_bmc(struct mt7615_dev *dev, |
935 | struct ieee80211_vif *vif, bool enable) | |
04b8e659 RL |
936 | { |
937 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
938 | ||
516c3e38 LB |
939 | if (!enable) { |
940 | struct wtbl_req_hdr req = { | |
941 | .wlan_idx = mvif->sta.wcid.idx, | |
942 | .operation = WTBL_RESET_AND_SET, | |
943 | }; | |
598a4434 | 944 | |
a3a2c2e7 | 945 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, |
516c3e38 LB |
946 | &req, sizeof(req), true); |
947 | } | |
948 | ||
949 | return mt7615_mcu_add_wtbl_bmc(dev, mvif); | |
04b8e659 RL |
950 | } |
951 | ||
952 | int mt7615_mcu_add_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif, | |
953 | struct ieee80211_sta *sta) | |
954 | { | |
955 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
956 | struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; | |
d7228bcf | 957 | struct { |
516c3e38 | 958 | struct wtbl_req_hdr hdr; |
d7228bcf LB |
959 | struct wtbl_generic g_wtbl; |
960 | struct wtbl_rx rx_wtbl; | |
516c3e38 LB |
961 | } req = { |
962 | .hdr = { | |
963 | .wlan_idx = msta->wcid.idx, | |
964 | .operation = WTBL_RESET_AND_SET, | |
965 | .tlv_num = cpu_to_le16(2), | |
966 | }, | |
d7228bcf LB |
967 | .g_wtbl = { |
968 | .tag = cpu_to_le16(WTBL_GENERIC), | |
969 | .len = cpu_to_le16(sizeof(struct wtbl_generic)), | |
970 | .muar_idx = mvif->omac_idx, | |
971 | .qos = sta->wme, | |
972 | .partial_aid = cpu_to_le16(sta->aid), | |
973 | }, | |
974 | .rx_wtbl = { | |
975 | .tag = cpu_to_le16(WTBL_RX), | |
976 | .len = cpu_to_le16(sizeof(struct wtbl_rx)), | |
1a09d9e0 | 977 | .rca1 = vif->type != NL80211_IFTYPE_AP, |
d7228bcf LB |
978 | .rca2 = 1, |
979 | .rv = 1, | |
980 | }, | |
981 | }; | |
516c3e38 | 982 | memcpy(req.g_wtbl.peer_addr, sta->addr, ETH_ALEN); |
d7228bcf | 983 | |
a3a2c2e7 | 984 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, |
516c3e38 | 985 | &req, sizeof(req), true); |
04b8e659 RL |
986 | } |
987 | ||
b1722925 | 988 | int mt7615_mcu_del_wtbl(struct mt7615_dev *dev, |
04b8e659 RL |
989 | struct ieee80211_sta *sta) |
990 | { | |
991 | struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; | |
516c3e38 LB |
992 | struct wtbl_req_hdr req = { |
993 | .wlan_idx = msta->wcid.idx, | |
994 | .operation = WTBL_RESET_AND_SET, | |
995 | }; | |
04b8e659 | 996 | |
a3a2c2e7 | 997 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, |
516c3e38 | 998 | &req, sizeof(req), true); |
04b8e659 RL |
999 | } |
1000 | ||
1001 | int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev) | |
1002 | { | |
516c3e38 LB |
1003 | struct wtbl_req_hdr req = { |
1004 | .operation = WTBL_RESET_ALL, | |
0467448d | 1005 | }; |
04b8e659 | 1006 | |
a3a2c2e7 | 1007 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, |
516c3e38 | 1008 | &req, sizeof(req), true); |
04b8e659 RL |
1009 | } |
1010 | ||
1011 | int mt7615_mcu_set_sta_rec_bmc(struct mt7615_dev *dev, | |
1012 | struct ieee80211_vif *vif, bool en) | |
1013 | { | |
1014 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
516c3e38 LB |
1015 | struct { |
1016 | struct sta_req_hdr hdr; | |
1017 | struct sta_rec_basic basic; | |
1018 | } req = { | |
1019 | .hdr = { | |
1020 | .bss_idx = mvif->idx, | |
1021 | .wlan_idx = mvif->sta.wcid.idx, | |
1022 | .tlv_num = cpu_to_le16(1), | |
1023 | .is_tlv_append = 1, | |
1024 | .muar_idx = mvif->omac_idx, | |
1025 | }, | |
1026 | .basic = { | |
1027 | .tag = cpu_to_le16(STA_REC_BASIC), | |
1028 | .len = cpu_to_le16(sizeof(struct sta_rec_basic)), | |
1029 | .conn_type = cpu_to_le32(CONNECTION_INFRA_BC), | |
1030 | }, | |
1031 | }; | |
1032 | eth_broadcast_addr(req.basic.peer_addr); | |
04b8e659 | 1033 | |
04b8e659 | 1034 | if (en) { |
516c3e38 LB |
1035 | req.basic.conn_state = CONN_STATE_PORT_SECURE; |
1036 | req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER | | |
1037 | EXTRA_INFO_NEW); | |
04b8e659 | 1038 | } else { |
516c3e38 LB |
1039 | req.basic.conn_state = CONN_STATE_DISCONNECT; |
1040 | req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER); | |
04b8e659 RL |
1041 | } |
1042 | ||
a3a2c2e7 | 1043 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE, |
516c3e38 | 1044 | &req, sizeof(req), true); |
04b8e659 RL |
1045 | } |
1046 | ||
04b8e659 RL |
1047 | int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif, |
1048 | struct ieee80211_sta *sta, bool en) | |
1049 | { | |
1050 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
1051 | struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; | |
04b8e659 | 1052 | |
516c3e38 LB |
1053 | struct { |
1054 | struct sta_req_hdr hdr; | |
1055 | struct sta_rec_basic basic; | |
1056 | } req = { | |
1057 | .hdr = { | |
1058 | .bss_idx = mvif->idx, | |
1059 | .wlan_idx = msta->wcid.idx, | |
1060 | .tlv_num = cpu_to_le16(1), | |
1061 | .is_tlv_append = 1, | |
1062 | .muar_idx = mvif->omac_idx, | |
1063 | }, | |
1064 | .basic = { | |
1065 | .tag = cpu_to_le16(STA_REC_BASIC), | |
1066 | .len = cpu_to_le16(sizeof(struct sta_rec_basic)), | |
1067 | .qos = sta->wme, | |
1068 | .aid = cpu_to_le16(sta->aid), | |
1069 | }, | |
1070 | }; | |
1071 | memcpy(req.basic.peer_addr, sta->addr, ETH_ALEN); | |
04b8e659 | 1072 | |
76055604 LB |
1073 | switch (vif->type) { |
1074 | case NL80211_IFTYPE_AP: | |
1075 | case NL80211_IFTYPE_MESH_POINT: | |
1076 | req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); | |
1077 | break; | |
1078 | case NL80211_IFTYPE_STATION: | |
1079 | req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); | |
1080 | break; | |
7f4b7920 LB |
1081 | case NL80211_IFTYPE_ADHOC: |
1082 | req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); | |
1083 | break; | |
76055604 LB |
1084 | default: |
1085 | WARN_ON(1); | |
1086 | break; | |
5d1ad7d7 | 1087 | } |
04b8e659 RL |
1088 | |
1089 | if (en) { | |
516c3e38 LB |
1090 | req.basic.conn_state = CONN_STATE_PORT_SECURE; |
1091 | req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER | | |
1092 | EXTRA_INFO_NEW); | |
04b8e659 | 1093 | } else { |
516c3e38 LB |
1094 | req.basic.conn_state = CONN_STATE_DISCONNECT; |
1095 | req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER); | |
04b8e659 RL |
1096 | } |
1097 | ||
a3a2c2e7 | 1098 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE, |
516c3e38 | 1099 | &req, sizeof(req), true); |
04b8e659 RL |
1100 | } |
1101 | ||
1102 | int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif, | |
1103 | int en) | |
1104 | { | |
516c3e38 LB |
1105 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; |
1106 | struct mt76_wcid *wcid = &dev->mt76.global_wcid; | |
5ec87dc8 | 1107 | struct ieee80211_mutable_offsets offs; |
04b8e659 RL |
1108 | struct req { |
1109 | u8 omac_idx; | |
1110 | u8 enable; | |
1111 | u8 wlan_idx; | |
1112 | u8 band_idx; | |
1113 | u8 pkt_type; | |
1114 | u8 need_pre_tbtt_int; | |
1115 | __le16 csa_ie_pos; | |
1116 | __le16 pkt_len; | |
1117 | __le16 tim_ie_pos; | |
1118 | u8 pkt[512]; | |
1119 | u8 csa_cnt; | |
1120 | /* bss color change */ | |
1121 | u8 bcc_cnt; | |
1122 | __le16 bcc_ie_pos; | |
516c3e38 LB |
1123 | } __packed req = { |
1124 | .omac_idx = mvif->omac_idx, | |
1125 | .enable = en, | |
1126 | .wlan_idx = wcid->idx, | |
1127 | .band_idx = mvif->band_idx, | |
516c3e38 | 1128 | }; |
516c3e38 | 1129 | struct sk_buff *skb; |
04b8e659 | 1130 | |
5ec87dc8 | 1131 | skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs); |
04b8e659 RL |
1132 | if (!skb) |
1133 | return -EINVAL; | |
1134 | ||
1135 | if (skb->len > 512 - MT_TXD_SIZE) { | |
1136 | dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); | |
1137 | dev_kfree_skb(skb); | |
1138 | return -EINVAL; | |
1139 | } | |
1140 | ||
1141 | mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL, | |
1142 | 0, NULL); | |
1143 | memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len); | |
04b8e659 | 1144 | req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); |
5ec87dc8 LB |
1145 | req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); |
1146 | if (offs.csa_counter_offs[0]) { | |
1147 | u16 csa_offs; | |
04b8e659 | 1148 | |
5ec87dc8 LB |
1149 | csa_offs = MT_TXD_SIZE + offs.csa_counter_offs[0] - 4; |
1150 | req.csa_ie_pos = cpu_to_le16(csa_offs); | |
1151 | req.csa_cnt = skb->data[offs.csa_counter_offs[0]]; | |
1152 | } | |
9db1aec0 | 1153 | dev_kfree_skb(skb); |
04b8e659 | 1154 | |
a3a2c2e7 | 1155 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD, |
516c3e38 | 1156 | &req, sizeof(req), true); |
04b8e659 RL |
1157 | } |
1158 | ||
61d36824 LB |
1159 | int mt7615_mcu_set_tx_power(struct mt7615_dev *dev) |
1160 | { | |
1161 | int i, ret, n_chains = hweight8(dev->mt76.antenna_mask); | |
1162 | struct cfg80211_chan_def *chandef = &dev->mt76.chandef; | |
16a2f8e2 | 1163 | int freq = chandef->center_freq1, len, target_chains; |
61d36824 | 1164 | u8 *req, *data, *eep = (u8 *)dev->mt76.eeprom.data; |
16a2f8e2 | 1165 | enum nl80211_band band = chandef->chan->band; |
61d36824 | 1166 | struct ieee80211_hw *hw = mt76_hw(dev); |
61d36824 LB |
1167 | struct { |
1168 | u8 center_chan; | |
1169 | u8 dbdc_idx; | |
1170 | u8 band; | |
1171 | u8 rsv; | |
1172 | } __packed req_hdr = { | |
1173 | .center_chan = ieee80211_frequency_to_channel(freq), | |
16a2f8e2 | 1174 | .band = band, |
61d36824 LB |
1175 | }; |
1176 | s8 tx_power; | |
1177 | ||
1178 | len = sizeof(req_hdr) + __MT_EE_MAX - MT_EE_NIC_CONF_0; | |
1179 | req = kzalloc(len, GFP_KERNEL); | |
1180 | if (!req) | |
1181 | return -ENOMEM; | |
1182 | ||
1183 | memcpy(req, &req_hdr, sizeof(req_hdr)); | |
1184 | data = req + sizeof(req_hdr); | |
1185 | memcpy(data, eep + MT_EE_NIC_CONF_0, | |
1186 | __MT_EE_MAX - MT_EE_NIC_CONF_0); | |
1187 | ||
1188 | tx_power = hw->conf.power_level * 2; | |
1189 | switch (n_chains) { | |
1190 | case 4: | |
1191 | tx_power -= 12; | |
1192 | break; | |
1193 | case 3: | |
1194 | tx_power -= 8; | |
1195 | break; | |
1196 | case 2: | |
1197 | tx_power -= 6; | |
1198 | break; | |
1199 | default: | |
1200 | break; | |
1201 | } | |
1202 | tx_power = max_t(s8, tx_power, 0); | |
1203 | dev->mt76.txpower_cur = tx_power; | |
1204 | ||
16a2f8e2 LB |
1205 | target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains; |
1206 | for (i = 0; i < target_chains; i++) { | |
61d36824 LB |
1207 | int index = -MT_EE_NIC_CONF_0; |
1208 | ||
16a2f8e2 | 1209 | ret = mt7615_eeprom_get_power_index(dev, chandef->chan, i); |
61d36824 LB |
1210 | if (ret < 0) |
1211 | goto out; | |
1212 | ||
1213 | index += ret; | |
1214 | data[index] = min_t(u8, data[index], tx_power); | |
1215 | } | |
1216 | ||
1217 | ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL, | |
1218 | req, len, true); | |
1219 | out: | |
1220 | kfree(req); | |
1221 | ||
1222 | return ret; | |
1223 | } | |
1224 | ||
d67a6646 LB |
1225 | int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev, |
1226 | enum mt7615_rdd_cmd cmd, u8 index, | |
1227 | u8 rx_sel, u8 val) | |
1228 | { | |
1229 | struct { | |
1230 | u8 ctrl; | |
1231 | u8 rdd_idx; | |
1232 | u8 rdd_rx_sel; | |
1233 | u8 val; | |
1234 | u8 rsv[4]; | |
1235 | } req = { | |
1236 | .ctrl = cmd, | |
1237 | .rdd_idx = index, | |
1238 | .rdd_rx_sel = rx_sel, | |
1239 | .val = val, | |
1240 | }; | |
1241 | ||
1242 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, | |
1243 | &req, sizeof(req), true); | |
1244 | } | |
1245 | ||
70911d96 LB |
1246 | int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev) |
1247 | { | |
1248 | struct { | |
1249 | u8 pulse_num; | |
1250 | u8 rsv[3]; | |
1251 | struct { | |
1252 | u32 start_time; | |
1253 | u16 width; | |
1254 | s16 power; | |
1255 | } pattern[32]; | |
1256 | } req = { | |
1257 | .pulse_num = dev->radar_pattern.n_pulses, | |
1258 | }; | |
1259 | u32 start_time = ktime_to_ms(ktime_get_boottime()); | |
1260 | int i; | |
1261 | ||
1262 | if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern)) | |
1263 | return -EINVAL; | |
1264 | ||
1265 | /* TODO: add some noise here */ | |
1266 | for (i = 0; i < dev->radar_pattern.n_pulses; i++) { | |
1267 | req.pattern[i].width = dev->radar_pattern.width; | |
1268 | req.pattern[i].power = dev->radar_pattern.power; | |
1269 | req.pattern[i].start_time = start_time + | |
1270 | i * dev->radar_pattern.period; | |
1271 | } | |
1272 | ||
1273 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_PATTERN, | |
1274 | &req, sizeof(req), false); | |
1275 | } | |
1276 | ||
04b8e659 RL |
1277 | int mt7615_mcu_set_channel(struct mt7615_dev *dev) |
1278 | { | |
02fc62e3 LB |
1279 | struct cfg80211_chan_def *chandef = &dev->mt76.chandef; |
1280 | int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; | |
04b8e659 RL |
1281 | struct { |
1282 | u8 control_chan; | |
1283 | u8 center_chan; | |
1284 | u8 bw; | |
1285 | u8 tx_streams; | |
1286 | u8 rx_streams_mask; | |
1287 | u8 switch_reason; | |
1288 | u8 band_idx; | |
1289 | /* for 80+80 only */ | |
1290 | u8 center_chan2; | |
1291 | __le16 cac_case; | |
1292 | u8 channel_band; | |
1293 | u8 rsv0; | |
1294 | __le32 outband_freq; | |
1295 | u8 txpower_drop; | |
1296 | u8 rsv1[3]; | |
1297 | u8 txpower_sku[53]; | |
1298 | u8 rsv2[3]; | |
02fc62e3 LB |
1299 | } req = { |
1300 | .control_chan = chandef->chan->hw_value, | |
1301 | .center_chan = ieee80211_frequency_to_channel(freq1), | |
1302 | .tx_streams = (dev->mt76.chainmask >> 8) & 0xf, | |
1303 | .rx_streams_mask = dev->mt76.antenna_mask, | |
1304 | .center_chan2 = ieee80211_frequency_to_channel(freq2), | |
1305 | }; | |
04b8e659 RL |
1306 | int ret; |
1307 | ||
2b5d1b91 LB |
1308 | if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) |
1309 | req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; | |
1310 | else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && | |
1311 | chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) | |
02fc62e3 LB |
1312 | req.switch_reason = CH_SWITCH_DFS; |
1313 | else | |
1314 | req.switch_reason = CH_SWITCH_NORMAL; | |
04b8e659 RL |
1315 | |
1316 | switch (dev->mt76.chandef.width) { | |
1317 | case NL80211_CHAN_WIDTH_40: | |
1318 | req.bw = CMD_CBW_40MHZ; | |
1319 | break; | |
1320 | case NL80211_CHAN_WIDTH_80: | |
1321 | req.bw = CMD_CBW_80MHZ; | |
1322 | break; | |
1323 | case NL80211_CHAN_WIDTH_80P80: | |
1324 | req.bw = CMD_CBW_8080MHZ; | |
1325 | break; | |
1326 | case NL80211_CHAN_WIDTH_160: | |
1327 | req.bw = CMD_CBW_160MHZ; | |
1328 | break; | |
1329 | case NL80211_CHAN_WIDTH_5: | |
1330 | req.bw = CMD_CBW_5MHZ; | |
1331 | break; | |
1332 | case NL80211_CHAN_WIDTH_10: | |
1333 | req.bw = CMD_CBW_10MHZ; | |
1334 | break; | |
1335 | case NL80211_CHAN_WIDTH_20_NOHT: | |
1336 | case NL80211_CHAN_WIDTH_20: | |
1337 | default: | |
1338 | req.bw = CMD_CBW_20MHZ; | |
02fc62e3 | 1339 | break; |
04b8e659 | 1340 | } |
04b8e659 RL |
1341 | memset(req.txpower_sku, 0x3f, 49); |
1342 | ||
a3a2c2e7 | 1343 | ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, |
516c3e38 | 1344 | &req, sizeof(req), true); |
04b8e659 RL |
1345 | if (ret) |
1346 | return ret; | |
1347 | ||
a3a2c2e7 | 1348 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RX_PATH, |
516c3e38 | 1349 | &req, sizeof(req), true); |
04b8e659 RL |
1350 | } |
1351 | ||
1352 | int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif, | |
1353 | struct ieee80211_sta *sta) | |
1354 | { | |
1355 | struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; | |
1356 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
516c3e38 LB |
1357 | struct wtbl_req_hdr *wtbl_hdr; |
1358 | struct sta_req_hdr *sta_hdr; | |
04b8e659 | 1359 | struct wtbl_raw *wtbl_raw; |
516c3e38 LB |
1360 | struct sta_rec_ht *sta_ht; |
1361 | struct wtbl_ht *wtbl_ht; | |
8e309f7d | 1362 | int buf_len, ret, ntlv = 2; |
04b8e659 RL |
1363 | u32 msk, val = 0; |
1364 | u8 *buf; | |
1365 | ||
1366 | buf = kzalloc(MT7615_WTBL_UPDATE_MAX_SIZE, GFP_KERNEL); | |
1367 | if (!buf) | |
1368 | return -ENOMEM; | |
1369 | ||
516c3e38 LB |
1370 | wtbl_hdr = (struct wtbl_req_hdr *)buf; |
1371 | wtbl_hdr->wlan_idx = msta->wcid.idx; | |
1372 | wtbl_hdr->operation = WTBL_SET; | |
1373 | buf_len = sizeof(*wtbl_hdr); | |
1374 | ||
04b8e659 | 1375 | /* ht basic */ |
516c3e38 | 1376 | wtbl_ht = (struct wtbl_ht *)(buf + buf_len); |
04b8e659 RL |
1377 | wtbl_ht->tag = cpu_to_le16(WTBL_HT); |
1378 | wtbl_ht->len = cpu_to_le16(sizeof(*wtbl_ht)); | |
1379 | wtbl_ht->ht = 1; | |
1380 | wtbl_ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; | |
1381 | wtbl_ht->af = sta->ht_cap.ampdu_factor; | |
1382 | wtbl_ht->mm = sta->ht_cap.ampdu_density; | |
516c3e38 | 1383 | buf_len += sizeof(*wtbl_ht); |
04b8e659 RL |
1384 | |
1385 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) | |
1386 | val |= MT_WTBL_W5_SHORT_GI_20; | |
1387 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | |
1388 | val |= MT_WTBL_W5_SHORT_GI_40; | |
1389 | ||
1390 | /* vht basic */ | |
1391 | if (sta->vht_cap.vht_supported) { | |
1392 | struct wtbl_vht *wtbl_vht; | |
1393 | ||
1394 | wtbl_vht = (struct wtbl_vht *)(buf + buf_len); | |
1395 | buf_len += sizeof(*wtbl_vht); | |
1396 | wtbl_vht->tag = cpu_to_le16(WTBL_VHT); | |
1397 | wtbl_vht->len = cpu_to_le16(sizeof(*wtbl_vht)); | |
1398 | wtbl_vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC; | |
1399 | wtbl_vht->vht = 1; | |
8e309f7d | 1400 | ntlv++; |
04b8e659 RL |
1401 | |
1402 | if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) | |
1403 | val |= MT_WTBL_W5_SHORT_GI_80; | |
1404 | if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) | |
1405 | val |= MT_WTBL_W5_SHORT_GI_160; | |
1406 | } | |
1407 | ||
1408 | /* smps */ | |
1409 | if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) { | |
1410 | struct wtbl_smps *wtbl_smps; | |
1411 | ||
1412 | wtbl_smps = (struct wtbl_smps *)(buf + buf_len); | |
1413 | buf_len += sizeof(*wtbl_smps); | |
1414 | wtbl_smps->tag = cpu_to_le16(WTBL_SMPS); | |
1415 | wtbl_smps->len = cpu_to_le16(sizeof(*wtbl_smps)); | |
1416 | wtbl_smps->smps = 1; | |
8e309f7d | 1417 | ntlv++; |
04b8e659 RL |
1418 | } |
1419 | ||
1420 | /* sgi */ | |
1421 | msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 | | |
1422 | MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160; | |
1423 | ||
1424 | wtbl_raw = (struct wtbl_raw *)(buf + buf_len); | |
1425 | buf_len += sizeof(*wtbl_raw); | |
1426 | wtbl_raw->tag = cpu_to_le16(WTBL_RAW_DATA); | |
1427 | wtbl_raw->len = cpu_to_le16(sizeof(*wtbl_raw)); | |
1428 | wtbl_raw->wtbl_idx = 1; | |
1429 | wtbl_raw->dw = 5; | |
1430 | wtbl_raw->msk = cpu_to_le32(~msk); | |
1431 | wtbl_raw->val = cpu_to_le32(val); | |
1432 | ||
516c3e38 | 1433 | wtbl_hdr->tlv_num = cpu_to_le16(ntlv); |
a3a2c2e7 | 1434 | ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, |
516c3e38 LB |
1435 | buf, buf_len, true); |
1436 | if (ret) | |
1437 | goto out; | |
04b8e659 RL |
1438 | |
1439 | memset(buf, 0, MT7615_WTBL_UPDATE_MAX_SIZE); | |
1440 | ||
516c3e38 LB |
1441 | sta_hdr = (struct sta_req_hdr *)buf; |
1442 | sta_hdr->bss_idx = mvif->idx; | |
1443 | sta_hdr->wlan_idx = msta->wcid.idx; | |
1444 | sta_hdr->is_tlv_append = 1; | |
1445 | ntlv = sta->vht_cap.vht_supported ? 2 : 1; | |
1446 | sta_hdr->tlv_num = cpu_to_le16(ntlv); | |
1447 | sta_hdr->muar_idx = mvif->omac_idx; | |
1448 | buf_len = sizeof(*sta_hdr); | |
1449 | ||
1450 | sta_ht = (struct sta_rec_ht *)(buf + buf_len); | |
1451 | sta_ht->tag = cpu_to_le16(STA_REC_HT); | |
1452 | sta_ht->len = cpu_to_le16(sizeof(*sta_ht)); | |
1453 | sta_ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); | |
1454 | buf_len += sizeof(*sta_ht); | |
04b8e659 RL |
1455 | |
1456 | if (sta->vht_cap.vht_supported) { | |
516c3e38 LB |
1457 | struct sta_rec_vht *sta_vht; |
1458 | ||
1459 | sta_vht = (struct sta_rec_vht *)(buf + buf_len); | |
1460 | buf_len += sizeof(*sta_vht); | |
1461 | sta_vht->tag = cpu_to_le16(STA_REC_VHT); | |
1462 | sta_vht->len = cpu_to_le16(sizeof(*sta_vht)); | |
1463 | sta_vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); | |
d923cf6b LB |
1464 | sta_vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; |
1465 | sta_vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; | |
04b8e659 RL |
1466 | } |
1467 | ||
a3a2c2e7 | 1468 | ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE, |
516c3e38 LB |
1469 | buf, buf_len, true); |
1470 | out: | |
04b8e659 | 1471 | kfree(buf); |
516c3e38 | 1472 | |
04b8e659 RL |
1473 | return ret; |
1474 | } | |
1475 | ||
1476 | int mt7615_mcu_set_tx_ba(struct mt7615_dev *dev, | |
1477 | struct ieee80211_ampdu_params *params, | |
1478 | bool add) | |
1479 | { | |
516c3e38 | 1480 | struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; |
04b8e659 | 1481 | struct mt7615_vif *mvif = msta->vif; |
516c3e38 LB |
1482 | struct { |
1483 | struct wtbl_req_hdr hdr; | |
1484 | struct wtbl_ba ba; | |
1485 | } wtbl_req = { | |
1486 | .hdr = { | |
1487 | .wlan_idx = msta->wcid.idx, | |
1488 | .operation = WTBL_SET, | |
1489 | .tlv_num = cpu_to_le16(1), | |
1490 | }, | |
1491 | .ba = { | |
1492 | .tag = cpu_to_le16(WTBL_BA), | |
1493 | .len = cpu_to_le16(sizeof(struct wtbl_ba)), | |
1494 | .tid = params->tid, | |
1495 | .ba_type = MT_BA_TYPE_ORIGINATOR, | |
1496 | .sn = add ? cpu_to_le16(params->ssn) : 0, | |
1497 | .ba_en = add, | |
1498 | }, | |
1499 | }; | |
1500 | struct { | |
1501 | struct sta_req_hdr hdr; | |
1502 | struct sta_rec_ba ba; | |
1503 | } sta_req = { | |
1504 | .hdr = { | |
1505 | .bss_idx = mvif->idx, | |
1506 | .wlan_idx = msta->wcid.idx, | |
1507 | .tlv_num = cpu_to_le16(1), | |
1508 | .is_tlv_append = 1, | |
1509 | .muar_idx = mvif->omac_idx, | |
1510 | }, | |
1511 | .ba = { | |
1512 | .tag = cpu_to_le16(STA_REC_BA), | |
1513 | .len = cpu_to_le16(sizeof(struct sta_rec_ba)), | |
1514 | .tid = params->tid, | |
1515 | .ba_type = MT_BA_TYPE_ORIGINATOR, | |
1516 | .amsdu = params->amsdu, | |
1517 | .ba_en = add << params->tid, | |
1518 | .ssn = cpu_to_le16(params->ssn), | |
1519 | .winsize = cpu_to_le16(params->buf_size), | |
1520 | }, | |
1521 | }; | |
1522 | int ret; | |
04b8e659 RL |
1523 | |
1524 | if (add) { | |
516c3e38 | 1525 | u8 idx, ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 }; |
04b8e659 RL |
1526 | |
1527 | for (idx = 7; idx > 0; idx--) { | |
516c3e38 | 1528 | if (params->buf_size >= ba_range[idx]) |
04b8e659 RL |
1529 | break; |
1530 | } | |
1531 | ||
516c3e38 | 1532 | wtbl_req.ba.ba_winsize_idx = idx; |
04b8e659 RL |
1533 | } |
1534 | ||
a3a2c2e7 | 1535 | ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, |
516c3e38 | 1536 | &wtbl_req, sizeof(wtbl_req), true); |
04b8e659 RL |
1537 | if (ret) |
1538 | return ret; | |
1539 | ||
a3a2c2e7 | 1540 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE, |
516c3e38 | 1541 | &sta_req, sizeof(sta_req), true); |
04b8e659 RL |
1542 | } |
1543 | ||
1544 | int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev, | |
1545 | struct ieee80211_ampdu_params *params, | |
1546 | bool add) | |
1547 | { | |
516c3e38 | 1548 | struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; |
04b8e659 | 1549 | struct mt7615_vif *mvif = msta->vif; |
516c3e38 LB |
1550 | struct { |
1551 | struct wtbl_req_hdr hdr; | |
1552 | struct wtbl_ba ba; | |
1553 | } wtbl_req = { | |
1554 | .hdr = { | |
1555 | .wlan_idx = msta->wcid.idx, | |
1556 | .operation = WTBL_SET, | |
1557 | .tlv_num = cpu_to_le16(1), | |
1558 | }, | |
1559 | .ba = { | |
1560 | .tag = cpu_to_le16(WTBL_BA), | |
1561 | .len = cpu_to_le16(sizeof(struct wtbl_ba)), | |
1562 | .tid = params->tid, | |
1563 | .ba_type = MT_BA_TYPE_RECIPIENT, | |
1564 | .rst_ba_tid = params->tid, | |
1565 | .rst_ba_sel = RST_BA_MAC_TID_MATCH, | |
1566 | .rst_ba_sb = 1, | |
1567 | }, | |
1568 | }; | |
1569 | struct { | |
1570 | struct sta_req_hdr hdr; | |
1571 | struct sta_rec_ba ba; | |
1572 | } sta_req = { | |
1573 | .hdr = { | |
1574 | .bss_idx = mvif->idx, | |
1575 | .wlan_idx = msta->wcid.idx, | |
1576 | .tlv_num = cpu_to_le16(1), | |
1577 | .is_tlv_append = 1, | |
1578 | .muar_idx = mvif->omac_idx, | |
1579 | }, | |
1580 | .ba = { | |
1581 | .tag = cpu_to_le16(STA_REC_BA), | |
1582 | .len = cpu_to_le16(sizeof(struct sta_rec_ba)), | |
1583 | .tid = params->tid, | |
1584 | .ba_type = MT_BA_TYPE_RECIPIENT, | |
1585 | .amsdu = params->amsdu, | |
1586 | .ba_en = add << params->tid, | |
1587 | .ssn = cpu_to_le16(params->ssn), | |
1588 | .winsize = cpu_to_le16(params->buf_size), | |
1589 | }, | |
1590 | }; | |
1591 | int ret; | |
04b8e659 | 1592 | |
516c3e38 | 1593 | memcpy(wtbl_req.ba.peer_addr, params->sta->addr, ETH_ALEN); |
04b8e659 | 1594 | |
a3a2c2e7 | 1595 | ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE, |
516c3e38 LB |
1596 | &sta_req, sizeof(sta_req), true); |
1597 | if (ret || !add) | |
1598 | return ret; | |
04b8e659 | 1599 | |
a3a2c2e7 | 1600 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, |
516c3e38 | 1601 | &wtbl_req, sizeof(wtbl_req), true); |
04b8e659 | 1602 | } |
0e6a29e4 LB |
1603 | |
1604 | int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index) | |
1605 | { | |
1606 | struct { | |
1607 | u8 action; | |
1608 | u8 rsv[3]; | |
1609 | } req = { | |
1610 | .action = index, | |
1611 | }; | |
1612 | ||
1613 | return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req, | |
1614 | sizeof(req), true); | |
1615 | } |