developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 1 | From e8ef34a080c0c243559a63d029376436ddf11ac8 Mon Sep 17 00:00:00 2001 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 2 | From: mtk20656 <chank.chen@mediatek.com> |
| 3 | Date: Sat, 20 Jan 2024 12:03:24 +0800 |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 4 | Subject: [PATCH 114/116] mtk: wifi: mt76: mt7996: Add connac3 csi feature. |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 5 | |
| 6 | 1. format align to wifi6. |
| 7 | 2. add bw320 support. |
| 8 | 3. add active mode. |
| 9 | |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 10 | Signed-off-by: mtk20656 <chank.chen@mediatek.com> |
| 11 | --- |
| 12 | mt76_connac_mcu.h | 2 + |
| 13 | mt7996/init.c | 22 +++ |
| 14 | mt7996/main.c | 3 + |
| 15 | mt7996/mcu.c | 465 ++++++++++++++++++++++++++++++++++++++++++++++ |
| 16 | mt7996/mcu.h | 105 +++++++++++ |
| 17 | mt7996/mt7996.h | 55 ++++++ |
| 18 | mt7996/vendor.c | 208 +++++++++++++++++++++ |
| 19 | mt7996/vendor.h | 50 +++++ |
| 20 | 8 files changed, 910 insertions(+) |
| 21 | |
| 22 | diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 23 | index 1c8e503..daaf87f 100644 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 24 | --- a/mt76_connac_mcu.h |
| 25 | +++ b/mt76_connac_mcu.h |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 26 | @@ -1053,6 +1053,7 @@ enum { |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 27 | MCU_UNI_EVENT_THERMAL = 0x35, |
| 28 | MCU_UNI_EVENT_NIC_CAPAB = 0x43, |
| 29 | MCU_UNI_EVENT_TESTMODE_CTRL = 0x46, |
| 30 | + MCU_UNI_EVENT_CSI_REPORT = 0x4A, |
| 31 | MCU_UNI_EVENT_WED_RRO = 0x57, |
| 32 | MCU_UNI_EVENT_PER_STA_INFO = 0x6d, |
| 33 | MCU_UNI_EVENT_ALL_STA_INFO = 0x6e, |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 34 | @@ -1290,6 +1291,7 @@ enum { |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 35 | MCU_UNI_CMD_TESTMODE_TRX_PARAM = 0x42, |
| 36 | MCU_UNI_CMD_TESTMODE_CTRL = 0x46, |
| 37 | MCU_UNI_CMD_PRECAL_RESULT = 0x47, |
| 38 | + MCU_UNI_CMD_CSI_CTRL = 0x4A, |
| 39 | MCU_UNI_CMD_THERMAL_CAL = 0x4c, |
| 40 | MCU_UNI_CMD_RRO = 0x57, |
| 41 | MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, |
| 42 | diff --git a/mt7996/init.c b/mt7996/init.c |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 43 | index 3af9d02..ff72aab 100644 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 44 | --- a/mt7996/init.c |
| 45 | +++ b/mt7996/init.c |
| 46 | @@ -806,6 +806,24 @@ error: |
| 47 | return ret; |
| 48 | } |
| 49 | |
| 50 | +#ifdef CONFIG_MTK_VENDOR |
| 51 | +static int mt7996_unregister_csi(struct mt7996_phy *phy) |
| 52 | +{ |
| 53 | + struct csi_data *c, *tmp_c; |
| 54 | + |
| 55 | + spin_lock_bh(&phy->csi.lock); |
| 56 | + phy->csi.enable = 0; |
| 57 | + |
| 58 | + list_for_each_entry_safe(c, tmp_c, &phy->csi.list, node) { |
| 59 | + list_del(&c->node); |
| 60 | + kfree(c); |
| 61 | + } |
| 62 | + spin_unlock_bh(&phy->csi.lock); |
| 63 | + |
| 64 | + return 0; |
| 65 | +} |
| 66 | +#endif |
| 67 | + |
| 68 | static void |
| 69 | mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band) |
| 70 | { |
| 71 | @@ -817,6 +835,10 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band) |
| 72 | /* TODO: FIXME: temp for single wiphy support */ |
| 73 | phy->mt76->hw = phy->mt76->ori_hw; |
| 74 | |
| 75 | +#ifdef CONFIG_MTK_VENDOR |
| 76 | + mt7996_unregister_csi(phy); |
| 77 | +#endif |
| 78 | + |
| 79 | mt7996_unregister_thermal(phy); |
| 80 | |
| 81 | mphy = phy->dev->mt76.phys[band]; |
| 82 | diff --git a/mt7996/main.c b/mt7996/main.c |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 83 | index dcb0b07..35f2495 100644 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 84 | --- a/mt7996/main.c |
| 85 | +++ b/mt7996/main.c |
| 86 | @@ -1292,6 +1292,9 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, |
| 87 | struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); |
| 88 | unsigned long rem = sta->valid_links ?: BIT(0); |
| 89 | |
| 90 | +#ifdef CONFIG_MTK_VENDOR |
| 91 | + mt7996_mcu_set_csi(&dev->phy, 2, 8, 1, 0, sta->addr); |
| 92 | +#endif |
| 93 | mt7996_mac_sta_remove_links(dev, vif, sta, rem); |
| 94 | } |
| 95 | |
| 96 | diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 97 | index 3f51c28..6c9ec31 100644 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 98 | --- a/mt7996/mcu.c |
| 99 | +++ b/mt7996/mcu.c |
| 100 | @@ -653,6 +653,263 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | +static int |
| 105 | +csi_integrate_segment_data(struct mt7996_phy *phy, struct csi_data *csi) |
| 106 | +{ |
| 107 | + struct csi_data *csi_temp = NULL; |
| 108 | + |
| 109 | + if (csi->segment_num == 0 && csi->remain_last == 0) |
| 110 | + return CSI_CHAIN_COMPLETE; |
| 111 | + else if (csi->segment_num == 0 && csi->remain_last == 1) { |
| 112 | + memcpy(&phy->csi.buffered_csi, |
| 113 | + csi, sizeof(struct csi_data)); |
| 114 | + |
| 115 | + return CSI_CHAIN_SEGMENT_FIRST; |
| 116 | + } else if (csi->segment_num != 0) { |
| 117 | + csi_temp = &phy->csi.buffered_csi; |
| 118 | + if (csi->chain_info != csi_temp->chain_info || |
| 119 | + csi->segment_num != (csi_temp->segment_num + 1)) |
| 120 | + return CSI_CHAIN_SEGMENT_ERR; |
| 121 | + |
| 122 | + memcpy(&csi_temp->data_i[csi_temp->data_num], |
| 123 | + csi->data_i, csi->data_num * sizeof(s16)); |
| 124 | + |
| 125 | + memcpy(&csi_temp->data_q[csi_temp->data_num], |
| 126 | + csi->data_q, csi->data_num * sizeof(s16)); |
| 127 | + |
| 128 | + csi_temp->data_num += csi->data_num; |
| 129 | + csi_temp->segment_num = csi->segment_num; |
| 130 | + csi_temp->remain_last = csi->remain_last; |
| 131 | + |
| 132 | + if (csi->remain_last == 0) |
| 133 | + return CSI_CHAIN_SEGMENT_LAST; |
| 134 | + else if (csi->remain_last == 1) |
| 135 | + return CSI_CHAIN_SEGMENT_MIDDLE; |
| 136 | + } |
| 137 | + |
| 138 | + return CSI_CHAIN_ERR; |
| 139 | +} |
| 140 | + |
| 141 | +static int |
| 142 | +mt7996_mcu_csi_report_data(struct mt7996_phy *phy, u8 *tlv_buf, u32 len) |
| 143 | +{ |
| 144 | + int ret, i; |
| 145 | + struct csi_data *current_csi; |
| 146 | + struct csi_data *target_csi; |
| 147 | + struct csi_tlv *tlv_data; |
| 148 | + u8 *buf_tmp; |
| 149 | + u32 rx_info, tx_rx_idx; |
| 150 | + u32 buf_len_last, offset; |
| 151 | + |
| 152 | + buf_tmp = tlv_buf; |
| 153 | + buf_len_last = len; |
| 154 | + offset = sizeof(((struct csi_tlv *)0)->basic); |
| 155 | + |
| 156 | + current_csi = kzalloc(sizeof(*current_csi), GFP_KERNEL); |
| 157 | + if (!current_csi) |
| 158 | + return -ENOMEM; |
| 159 | + |
| 160 | + while (buf_len_last >= offset) { |
| 161 | + u32 tag, len; |
| 162 | + s16 *data_tmp = NULL; |
| 163 | + |
| 164 | + tlv_data = (struct csi_tlv *)buf_tmp; |
| 165 | + tag = le32_to_cpu(tlv_data->basic.tag); |
| 166 | + len = le32_to_cpu(tlv_data->basic.len); |
| 167 | + |
| 168 | + switch (tag) { |
| 169 | + case CSI_EVENT_FW_VER: |
| 170 | + current_csi->fw_ver = le32_to_cpu(tlv_data->info); |
| 171 | + break; |
| 172 | + case CSI_EVENT_CBW: |
| 173 | + current_csi->ch_bw = le32_to_cpu(tlv_data->info); |
| 174 | + break; |
| 175 | + case CSI_EVENT_RSSI: |
| 176 | + current_csi->rssi = le32_to_cpu(tlv_data->info); |
| 177 | + break; |
| 178 | + case CSI_EVENT_SNR: |
| 179 | + current_csi->snr = le32_to_cpu(tlv_data->info); |
| 180 | + break; |
| 181 | + case CSI_EVENT_BAND: |
| 182 | + current_csi->band = le32_to_cpu(tlv_data->info); |
| 183 | + |
| 184 | + if (current_csi->band != phy->mt76->band_idx) { |
| 185 | + kfree(current_csi); |
| 186 | + return -EINVAL; |
| 187 | + } |
| 188 | + |
| 189 | + break; |
| 190 | + case CSI_EVENT_CSI_NUM: |
| 191 | + current_csi->data_num = le32_to_cpu(tlv_data->info); |
| 192 | + |
| 193 | + if (current_csi->data_num > CSI_BW80_DATA_COUNT) { |
| 194 | + kfree(current_csi); |
| 195 | + return -EINVAL; |
| 196 | + } |
| 197 | + |
| 198 | + break; |
| 199 | + case CSI_EVENT_CSI_I_DATA: |
| 200 | + if (len != sizeof(s16) * current_csi->data_num) { |
| 201 | + kfree(current_csi); |
| 202 | + return -EINVAL; |
| 203 | + } |
| 204 | + |
| 205 | + data_tmp = tlv_data->data; |
| 206 | + for (i = 0; i < current_csi->data_num; i++) |
| 207 | + current_csi->data_i[i] = le16_to_cpu(*(data_tmp + i)); |
| 208 | + break; |
| 209 | + case CSI_EVENT_CSI_Q_DATA: |
| 210 | + if (len != sizeof(s16) * current_csi->data_num) { |
| 211 | + kfree(current_csi); |
| 212 | + return -EINVAL; |
| 213 | + } |
| 214 | + |
| 215 | + data_tmp = tlv_data->data; |
| 216 | + for (i = 0; i < current_csi->data_num; i++) |
| 217 | + current_csi->data_q[i] = le16_to_cpu(*(data_tmp + i)); |
| 218 | + break; |
| 219 | + case CSI_EVENT_DBW: |
| 220 | + current_csi->data_bw = le32_to_cpu(tlv_data->info); |
| 221 | + break; |
| 222 | + case CSI_EVENT_CH_IDX: |
| 223 | + current_csi->pri_ch_idx = le32_to_cpu(tlv_data->info); |
| 224 | + break; |
| 225 | + case CSI_EVENT_TA: |
| 226 | + memcpy(current_csi->ta, tlv_data->mac, ETH_ALEN); |
| 227 | + break; |
| 228 | + case CSI_EVENT_EXTRA_INFO: |
| 229 | + current_csi->ext_info = le32_to_cpu(tlv_data->info); |
| 230 | + break; |
| 231 | + case CSI_EVENT_RX_MODE: |
| 232 | + rx_info = le32_to_cpu(tlv_data->info); |
| 233 | + current_csi->rx_mode = u32_get_bits(rx_info, GENMASK(15, 0)); |
| 234 | + current_csi->rx_rate = u32_get_bits(rx_info, GENMASK(31, 16)); |
| 235 | + break; |
| 236 | + case CSI_EVENT_H_IDX: |
| 237 | + current_csi->chain_info = le32_to_cpu(tlv_data->info); |
| 238 | + break; |
| 239 | + case CSI_EVENT_TX_RX_IDX: |
| 240 | + tx_rx_idx = le32_to_cpu(tlv_data->info); |
| 241 | + current_csi->tx_idx = u32_get_bits(tx_rx_idx, GENMASK(31, 16)); |
| 242 | + current_csi->rx_idx = u32_get_bits(tx_rx_idx, GENMASK(15, 0)); |
| 243 | + break; |
| 244 | + case CSI_EVENT_TS: |
| 245 | + current_csi->ts = le32_to_cpu(tlv_data->info); |
| 246 | + |
| 247 | + if (phy->csi.interval && |
| 248 | + current_csi->ts < phy->csi.last_record + phy->csi.interval) { |
| 249 | + kfree(current_csi); |
| 250 | + return 0; |
| 251 | + } |
| 252 | + |
| 253 | + break; |
| 254 | + case CSI_EVENT_PKT_SN: |
| 255 | + current_csi->pkt_sn = le32_to_cpu(tlv_data->info); |
| 256 | + break; |
| 257 | + case CSI_EVENT_BW_SEG: |
| 258 | + current_csi->segment_num = le32_to_cpu(tlv_data->info); |
| 259 | + break; |
| 260 | + case CSI_EVENT_REMAIN_LAST: |
| 261 | + current_csi->remain_last = le32_to_cpu(tlv_data->info); |
| 262 | + break; |
| 263 | + case CSI_EVENT_TR_STREAM: |
| 264 | + current_csi->tr_stream = le32_to_cpu(tlv_data->info); |
| 265 | + break; |
| 266 | + default: |
| 267 | + break; |
| 268 | + }; |
| 269 | + |
| 270 | + buf_len_last -= (offset + len); |
| 271 | + |
| 272 | + if (buf_len_last >= offset) |
| 273 | + buf_tmp += (offset + len); |
| 274 | + } |
| 275 | + |
| 276 | + /* integret the bw80 segment */ |
| 277 | + if (current_csi->ch_bw >= CSI_BW80) { |
| 278 | + ret = csi_integrate_segment_data(phy, current_csi); |
| 279 | + |
| 280 | + switch (ret) { |
| 281 | + case CSI_CHAIN_ERR: |
| 282 | + case CSI_CHAIN_SEGMENT_ERR: |
| 283 | + kfree(current_csi); |
| 284 | + return -EINVAL; |
| 285 | + break; |
| 286 | + case CSI_CHAIN_SEGMENT_FIRST: |
| 287 | + case CSI_CHAIN_SEGMENT_MIDDLE: |
| 288 | + kfree(current_csi); |
| 289 | + return 0; |
| 290 | + break; |
| 291 | + case CSI_CHAIN_COMPLETE: |
| 292 | + target_csi = current_csi; |
| 293 | + break; |
| 294 | + case CSI_CHAIN_SEGMENT_LAST: |
| 295 | + target_csi = current_csi; |
| 296 | + memcpy(target_csi, &phy->csi.buffered_csi, sizeof(struct csi_data)); |
| 297 | + memset(&phy->csi.buffered_csi, 0, sizeof(struct csi_data)); |
| 298 | + break; |
| 299 | + default: |
| 300 | + break; |
| 301 | + } |
| 302 | + } else { |
| 303 | + target_csi = current_csi; |
| 304 | + } |
| 305 | + |
| 306 | + /* put the csi data into list */ |
| 307 | + INIT_LIST_HEAD(&target_csi->node); |
| 308 | + spin_lock_bh(&phy->csi.lock); |
| 309 | + |
| 310 | + if (!phy->csi.enable) { |
| 311 | + kfree(target_csi); |
| 312 | + goto out; |
| 313 | + } |
| 314 | + |
| 315 | + list_add_tail(&target_csi->node, &phy->csi.list); |
| 316 | + phy->csi.count++; |
| 317 | + |
| 318 | + if (phy->csi.count > CSI_MAX_BUF_NUM) { |
| 319 | + struct csi_data *old; |
| 320 | + |
| 321 | + old = list_first_entry(&phy->csi.list, |
| 322 | + struct csi_data, node); |
| 323 | + |
| 324 | + list_del(&old->node); |
| 325 | + kfree(old); |
| 326 | + phy->csi.count--; |
| 327 | + } |
| 328 | + |
| 329 | + if (target_csi->chain_info & BIT(15)) /* last chain */ |
| 330 | + phy->csi.last_record = target_csi->ts; |
| 331 | + |
| 332 | +out: |
| 333 | + spin_unlock_bh(&phy->csi.lock); |
| 334 | + return 0; |
| 335 | +} |
| 336 | + |
| 337 | +void |
| 338 | +mt7996_mcu_csi_report_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| 339 | +{ |
| 340 | + struct mt7996_mcu_csi_event *event; |
| 341 | + struct mt76_phy *mphy; |
| 342 | + struct mt7996_phy *phy; |
| 343 | + |
| 344 | + event = (struct mt7996_mcu_csi_event *)skb->data; |
| 345 | + |
| 346 | + mphy = dev->mt76.phys[event->band_idx]; |
| 347 | + if (!mphy) |
| 348 | + return; |
| 349 | + |
| 350 | + phy = mphy->priv; |
| 351 | + |
| 352 | + switch (le16_to_cpu(event->tag)) { |
| 353 | + case UNI_EVENT_CSI_DATA: |
| 354 | + mt7996_mcu_csi_report_data(phy, event->tlv_buf, le16_to_cpu(event->len) - 4); |
| 355 | + break; |
| 356 | + default: |
| 357 | + break; |
| 358 | + } |
| 359 | +} |
| 360 | + |
| 361 | static void |
| 362 | mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb) |
| 363 | { |
| 364 | @@ -896,6 +1153,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| 365 | case MCU_UNI_EVENT_BF: |
| 366 | mt7996_mcu_rx_bf_event(dev, skb); |
| 367 | break; |
| 368 | +#endif |
| 369 | +#ifdef CONFIG_MTK_VENDOR |
| 370 | + case MCU_UNI_EVENT_CSI_REPORT: |
| 371 | + mt7996_mcu_csi_report_event(dev, skb); |
| 372 | + break; |
| 373 | #endif |
| 374 | default: |
| 375 | break; |
| 376 | @@ -5995,4 +6257,207 @@ void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif) |
| 377 | |
| 378 | mt7996_mcu_add_beacon(hw, &vif->bss_conf, &mvif->deflink, val); |
| 379 | } |
| 380 | + |
| 381 | +static int mt7996_mcu_set_csi_enable(struct mt7996_phy *phy, u16 tag) |
| 382 | +{ |
| 383 | + struct { |
| 384 | + u8 band; |
| 385 | + u8 rsv1[3]; |
| 386 | + |
| 387 | + __le16 tag; |
| 388 | + __le16 len; |
| 389 | + } __packed req = { |
| 390 | + .band = phy->mt76->band_idx, |
| 391 | + .tag = cpu_to_le16(tag), |
| 392 | + .len = cpu_to_le16(sizeof(req) - 4), |
| 393 | + }; |
| 394 | + |
| 395 | + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req, |
| 396 | + sizeof(req), false); |
| 397 | +} |
| 398 | + |
| 399 | +static int mt7996_mcu_set_csi_frame_type(struct mt7996_phy *phy, u16 tag, u8 type_idx, u32 type) |
| 400 | +{ |
| 401 | + struct { |
| 402 | + u8 band; |
| 403 | + u8 rsv1[3]; |
| 404 | + |
| 405 | + __le16 tag; |
| 406 | + __le16 len; |
| 407 | + u8 frame_type_idx; |
| 408 | + u8 frame_type; |
| 409 | + u8 rsv2[2]; |
| 410 | + } __packed req = { |
| 411 | + .band = phy->mt76->band_idx, |
| 412 | + .tag = cpu_to_le16(tag), |
| 413 | + .len = cpu_to_le16(sizeof(req) - 4), |
| 414 | + .frame_type_idx = type_idx, |
| 415 | + .frame_type = type, |
| 416 | + }; |
| 417 | + |
| 418 | + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req, |
| 419 | + sizeof(req), false); |
| 420 | +} |
| 421 | + |
| 422 | +static int mt7996_mcu_set_csi_chain_filter(struct mt7996_phy *phy, u16 tag, u8 func, u32 value) |
| 423 | +{ |
| 424 | + struct { |
| 425 | + u8 band; |
| 426 | + u8 rsv1[3]; |
| 427 | + |
| 428 | + __le16 tag; |
| 429 | + __le16 len; |
| 430 | + u8 function; |
| 431 | + u8 chain_value; |
| 432 | + u8 rsv2[2]; |
| 433 | + } __packed req = { |
| 434 | + .band = phy->mt76->band_idx, |
| 435 | + .tag = cpu_to_le16(tag), |
| 436 | + .len = cpu_to_le16(sizeof(req) - 4), |
| 437 | + .function = func, |
| 438 | + .chain_value = value, |
| 439 | + }; |
| 440 | + |
| 441 | + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req, |
| 442 | + sizeof(req), false); |
| 443 | +} |
| 444 | + |
| 445 | +static int mt7996_mcu_set_csi_sta_filter(struct mt7996_phy *phy, u16 tag, u32 op, u8 *sta_mac) |
| 446 | +{ |
| 447 | + struct { |
| 448 | + u8 band; |
| 449 | + u8 rsv1[3]; |
| 450 | + |
| 451 | + __le16 tag; |
| 452 | + __le16 len; |
| 453 | + u8 operation; |
| 454 | + u8 rsv2[1]; |
| 455 | + u8 mac[6]; |
| 456 | + } __packed req = { |
| 457 | + .band = phy->mt76->band_idx, |
| 458 | + .tag = cpu_to_le16(tag), |
| 459 | + .len = cpu_to_le16(sizeof(req) - 4), |
| 460 | + .operation = op, |
| 461 | + }; |
| 462 | + |
| 463 | + memcpy(req.mac, sta_mac, ETH_ALEN); |
| 464 | + |
| 465 | + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req, |
| 466 | + sizeof(req), false); |
| 467 | +} |
| 468 | + |
| 469 | +static int mt7996_mcu_set_csi_active_mode(struct mt7996_phy *phy, u16 tag, |
| 470 | + u32 interval, u8 frame_idx, u8 subframe_idx, u32 bitmap) |
| 471 | +{ |
| 472 | + struct { |
| 473 | + u8 band; |
| 474 | + u8 rsv1[3]; |
| 475 | + |
| 476 | + __le16 tag; |
| 477 | + __le16 len; |
| 478 | + __le16 interval; /* uint: ms */ |
| 479 | + u8 frame_type_idx; |
| 480 | + u8 subframe_type_idx; |
| 481 | + __le32 bitmap; /* sta wcid bitmap */ |
| 482 | + u8 rsv2[4]; |
| 483 | + } __packed req = { |
| 484 | + .band = phy->mt76->band_idx, |
| 485 | + .tag = cpu_to_le16(tag), |
| 486 | + .len = cpu_to_le16(sizeof(req) - 4), |
| 487 | + .interval = cpu_to_le16(interval), |
| 488 | + .frame_type_idx = frame_idx, |
| 489 | + .subframe_type_idx = subframe_idx, |
| 490 | + .bitmap = cpu_to_le32(bitmap), |
| 491 | + }; |
| 492 | + |
| 493 | + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(CSI_CTRL), &req, |
| 494 | + sizeof(req), false); |
| 495 | +} |
| 496 | + |
| 497 | +void mt7996_csi_wcid_bitmap_update(void *data, struct ieee80211_sta *sta) |
| 498 | +{ |
| 499 | + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; |
| 500 | + struct mt7996_phy *phy = msta->vif->deflink.phy; |
| 501 | + struct csi_bitmap_info_update *sta_info = (struct csi_bitmap_info_update *)data; |
| 502 | + u16 wcid = 0; |
| 503 | + |
| 504 | +#define CSI_ACTIVE_MODE_ADD 1 |
| 505 | +#define CSI_ACTIVE_MODE_REMOVE 0 |
| 506 | + |
| 507 | + if (!memcmp(sta_info->addr, sta->addr, ETH_ALEN)) { |
| 508 | + wcid = msta->deflink.wcid.idx; |
| 509 | + |
| 510 | + /* active mode: only support station with wcid less than 32 */ |
| 511 | + if (wcid > 32) |
| 512 | + return; |
| 513 | + |
| 514 | + if (sta_info->action == CSI_ACTIVE_MODE_ADD) |
| 515 | + phy->csi.active_bitmap |= BIT(wcid); |
| 516 | + else if (sta_info->action == CSI_ACTIVE_MODE_REMOVE) |
| 517 | + phy->csi.active_bitmap &= ~(BIT(wcid)); |
| 518 | + } |
| 519 | +} |
| 520 | + |
| 521 | +int mt7996_mcu_set_csi(struct mt7996_phy *phy, u8 mode, |
| 522 | + u8 cfg, u8 v1, u32 v2, u8 *mac_addr) |
| 523 | +{ |
| 524 | + switch (mode) { |
| 525 | + case CSI_CONTROL_MODE_STOP: |
| 526 | + return mt7996_mcu_set_csi_enable(phy, UNI_CMD_CSI_STOP); |
| 527 | + case CSI_CONTROL_MODE_START: |
| 528 | + return mt7996_mcu_set_csi_enable(phy, UNI_CMD_CSI_START); |
| 529 | + case CSI_CONTROL_MODE_SET: |
| 530 | + switch (cfg) { |
| 531 | + case CSI_CONFIG_FRAME_TYPE: |
| 532 | + if (v2 > 255) |
| 533 | + return -EINVAL; |
| 534 | + |
| 535 | + return mt7996_mcu_set_csi_frame_type(phy, |
| 536 | + UNI_CMD_CSI_SET_FRAME_TYPE, v1, v2); |
| 537 | + case CSI_CONFIG_CHAIN_FILTER: |
| 538 | + if (v2 > 255) |
| 539 | + return -EINVAL; |
| 540 | + |
| 541 | + return mt7996_mcu_set_csi_chain_filter(phy, |
| 542 | + UNI_CMD_CSI_SET_CHAIN_FILTER, v1, v2); |
| 543 | + case CSI_CONFIG_STA_FILTER: |
| 544 | + if (!is_valid_ether_addr(mac_addr)) |
| 545 | + return -EINVAL; |
| 546 | + |
| 547 | + if (v2 > 255) |
| 548 | + return -EINVAL; |
| 549 | + |
| 550 | + return mt7996_mcu_set_csi_sta_filter(phy, |
| 551 | + UNI_CMD_CSI_SET_STA_FILTER, v2, mac_addr); |
| 552 | + case CSI_CONFIG_ACTIVE_MODE: |
| 553 | + if (is_valid_ether_addr(mac_addr)) { |
| 554 | + struct csi_bitmap_info_update sta_info; |
| 555 | + |
| 556 | + if (v2 > 255) |
| 557 | + return -EINVAL; |
| 558 | + |
| 559 | + memcpy(sta_info.addr, mac_addr, ETH_ALEN); |
| 560 | + sta_info.action = v2; |
| 561 | + |
| 562 | + ieee80211_iterate_stations_atomic(phy->mt76->hw, |
| 563 | + mt7996_csi_wcid_bitmap_update, &sta_info); |
| 564 | + return 0; |
| 565 | + } else { |
| 566 | + u8 frame_type = v1 & 0x3; |
| 567 | + u8 frame_subtype = (v1 & 0x3c) >> 2; |
| 568 | + |
| 569 | + /* active mode: max interval is 3000ms */ |
| 570 | + if (v2 > 3000) |
| 571 | + return -EINVAL; |
| 572 | + |
| 573 | + return mt7996_mcu_set_csi_active_mode(phy, UNI_CMD_CSI_SET_ACTIVE_MODE, |
| 574 | + v2, frame_type, frame_subtype, phy->csi.active_bitmap); |
| 575 | + } |
| 576 | + default: |
| 577 | + return -EINVAL; |
| 578 | + } |
| 579 | + default: |
| 580 | + return -EINVAL; |
| 581 | + } |
| 582 | +} |
| 583 | #endif |
| 584 | diff --git a/mt7996/mcu.h b/mt7996/mcu.h |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 585 | index a1ac18f..dc93fab 100644 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 586 | --- a/mt7996/mcu.h |
| 587 | +++ b/mt7996/mcu.h |
| 588 | @@ -1159,4 +1159,109 @@ struct fixed_rate_table_ctrl { |
| 589 | u8 _rsv2; |
| 590 | } __packed; |
| 591 | |
| 592 | +#ifdef CONFIG_MTK_VENDOR |
| 593 | +struct mt7996_mcu_csi_event { |
| 594 | + struct mt7996_mcu_rxd rxd; |
| 595 | + |
| 596 | + u8 band_idx; |
| 597 | + u8 _rsv[3]; |
| 598 | + |
| 599 | + __le16 tag; |
| 600 | + __le16 len; |
| 601 | + u8 tlv_buf[0]; |
| 602 | +}; |
| 603 | + |
| 604 | +enum UNI_EVENT_CSI_TAG_T { |
| 605 | + UNI_EVENT_CSI_DATA = 0, |
| 606 | + UNI_EVENT_CSI_MAX_NUM |
| 607 | +}; |
| 608 | + |
| 609 | +struct csi_tlv { |
| 610 | + struct { |
| 611 | + __le32 tag; |
| 612 | + __le32 len; |
| 613 | + } basic; |
| 614 | + union { |
| 615 | + u8 mac[ETH_ALEN]; |
| 616 | + __le32 info; |
| 617 | + s16 data[0]; |
| 618 | + }; |
| 619 | +} __packed; |
| 620 | + |
| 621 | +struct csi_bitmap_info_update { |
| 622 | + u8 action; |
| 623 | + u8 addr[ETH_ALEN]; |
| 624 | +}; |
| 625 | + |
| 626 | +#define CSI_MAX_BUF_NUM 3000 |
| 627 | + |
| 628 | +enum CSI_EVENT_TLV_TAG { |
| 629 | + CSI_EVENT_FW_VER, |
| 630 | + CSI_EVENT_CBW, |
| 631 | + CSI_EVENT_RSSI, |
| 632 | + CSI_EVENT_SNR, |
| 633 | + CSI_EVENT_BAND, |
| 634 | + CSI_EVENT_CSI_NUM, |
| 635 | + CSI_EVENT_CSI_I_DATA, |
| 636 | + CSI_EVENT_CSI_Q_DATA, |
| 637 | + CSI_EVENT_DBW, |
| 638 | + CSI_EVENT_CH_IDX, |
| 639 | + CSI_EVENT_TA, |
| 640 | + CSI_EVENT_EXTRA_INFO, |
| 641 | + CSI_EVENT_RX_MODE, |
| 642 | + CSI_EVENT_RSVD1, |
| 643 | + CSI_EVENT_RSVD2, |
| 644 | + CSI_EVENT_RSVD3, |
| 645 | + CSI_EVENT_RSVD4, |
| 646 | + CSI_EVENT_H_IDX, |
| 647 | + CSI_EVENT_TX_RX_IDX, |
| 648 | + CSI_EVENT_TS, |
| 649 | + CSI_EVENT_PKT_SN, |
| 650 | + CSI_EVENT_BW_SEG, |
| 651 | + CSI_EVENT_REMAIN_LAST, |
| 652 | + CSI_EVENT_TR_STREAM, |
| 653 | + CSI_EVENT_TLV_TAG_NUM, |
| 654 | +}; |
| 655 | + |
| 656 | +enum CSI_CHAIN_TYPE { |
| 657 | + CSI_CHAIN_ERR, |
| 658 | + CSI_CHAIN_COMPLETE, |
| 659 | + CSI_CHAIN_SEGMENT_FIRST, |
| 660 | + CSI_CHAIN_SEGMENT_MIDDLE, |
| 661 | + CSI_CHAIN_SEGMENT_LAST, |
| 662 | + CSI_CHAIN_SEGMENT_ERR, |
| 663 | +}; |
| 664 | + |
| 665 | +enum CSI_CONTROL_MODE_T { |
| 666 | + CSI_CONTROL_MODE_STOP, |
| 667 | + CSI_CONTROL_MODE_START, |
| 668 | + CSI_CONTROL_MODE_SET, |
| 669 | + CSI_CONTROL_MODE_NUM |
| 670 | +}; |
| 671 | + |
| 672 | +enum CSI_CONFIG_ITEM_T { |
| 673 | + CSI_CONFIG_RSVD1, |
| 674 | + CSI_CONFIG_WF, |
| 675 | + CSI_CONFIG_RSVD2, |
| 676 | + CSI_CONFIG_FRAME_TYPE, |
| 677 | + CSI_CONFIG_TX_PATH, |
| 678 | + CSI_CONFIG_OUTPUT_FORMAT, |
| 679 | + CSI_CONFIG_INFO, |
| 680 | + CSI_CONFIG_CHAIN_FILTER, |
| 681 | + CSI_CONFIG_STA_FILTER, |
| 682 | + CSI_CONFIG_ACTIVE_MODE, |
| 683 | + CSI_CONFIG_ITEM_NUM |
| 684 | +}; |
| 685 | + |
| 686 | +/* CSI config Tag */ |
| 687 | +enum UNI_CMD_CSI_TAG_T { |
| 688 | + UNI_CMD_CSI_STOP = 0, |
| 689 | + UNI_CMD_CSI_START = 1, |
| 690 | + UNI_CMD_CSI_SET_FRAME_TYPE = 2, |
| 691 | + UNI_CMD_CSI_SET_CHAIN_FILTER = 3, |
| 692 | + UNI_CMD_CSI_SET_STA_FILTER = 4, |
| 693 | + UNI_CMD_CSI_SET_ACTIVE_MODE = 5, |
| 694 | +}; |
| 695 | +#endif |
| 696 | + |
| 697 | #endif |
| 698 | diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 699 | index 0412d73..0d537fb 100644 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 700 | --- a/mt7996/mt7996.h |
| 701 | +++ b/mt7996/mt7996.h |
| 702 | @@ -438,6 +438,47 @@ struct mt7996_air_monitor_ctrl { |
| 703 | struct mt7996_air_monitor_group group[MT7996_AIR_MONITOR_MAX_GROUP]; |
| 704 | struct mt7996_air_monitor_entry entry[MT7996_AIR_MONITOR_MAX_ENTRY]; |
| 705 | }; |
| 706 | + |
| 707 | +enum { |
| 708 | + CSI_BW20, |
| 709 | + CSI_BW40, |
| 710 | + CSI_BW80, |
| 711 | + CSI_BW160, |
| 712 | + CSI_BW320 |
| 713 | +}; |
| 714 | + |
| 715 | +#define CSI_BW20_DATA_COUNT 64 |
| 716 | +#define CSI_BW40_DATA_COUNT 128 |
| 717 | +#define CSI_BW80_DATA_COUNT 256 |
| 718 | +#define CSI_BW160_DATA_COUNT 512 |
| 719 | +#define CSI_BW320_DATA_COUNT 1024 |
| 720 | + |
| 721 | +struct csi_data { |
| 722 | + u8 fw_ver; |
| 723 | + u8 ch_bw; |
| 724 | + u16 data_num; |
| 725 | + s16 data_i[CSI_BW320_DATA_COUNT]; |
| 726 | + s16 data_q[CSI_BW320_DATA_COUNT]; |
| 727 | + u8 band; |
| 728 | + s8 rssi; |
| 729 | + u8 snr; |
| 730 | + u32 ts; |
| 731 | + u8 data_bw; |
| 732 | + u8 pri_ch_idx; |
| 733 | + u8 ta[ETH_ALEN]; |
| 734 | + u32 ext_info; |
| 735 | + u16 rx_mode; |
| 736 | + u16 rx_rate; |
| 737 | + u32 chain_info; |
| 738 | + u16 tx_idx; |
| 739 | + u16 rx_idx; |
| 740 | + u32 segment_num; |
| 741 | + u8 remain_last; |
| 742 | + u16 pkt_sn; |
| 743 | + u8 tr_stream; |
| 744 | + |
| 745 | + struct list_head node; |
| 746 | +}; |
| 747 | #endif |
| 748 | |
| 749 | struct mt7996_rro_ba_session { |
| 750 | @@ -534,6 +575,18 @@ struct mt7996_phy { |
| 751 | u8 rts_bw_sig; |
| 752 | spinlock_t amnt_lock; |
| 753 | struct mt7996_air_monitor_ctrl amnt_ctrl; |
| 754 | + |
| 755 | + struct { |
| 756 | + struct list_head list; |
| 757 | + spinlock_t lock; |
| 758 | + u32 count; |
| 759 | + bool enable; |
| 760 | + |
| 761 | + struct csi_data buffered_csi; |
| 762 | + u32 active_bitmap; |
| 763 | + u32 interval; |
| 764 | + u32 last_record; |
| 765 | + } csi; |
| 766 | #endif |
| 767 | #ifdef CONFIG_MTK_DEBUG |
| 768 | bool sr_enable:1; |
| 769 | @@ -1166,6 +1219,8 @@ void mt7996_mcu_set_mimo(struct mt7996_phy *phy); |
| 770 | int mt7996_set_muru_cfg(struct mt7996_phy *phy, u8 action, u8 val); |
| 771 | int mt7996_mcu_set_muru_cfg(struct mt7996_phy *phy, void *data); |
| 772 | void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif); |
| 773 | +int mt7996_mcu_set_csi(struct mt7996_phy *phy, u8 mode, |
| 774 | + u8 cfg, u8 v1, u32 v2, u8 *mac_addr); |
| 775 | #endif |
| 776 | |
| 777 | int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable); |
| 778 | diff --git a/mt7996/vendor.c b/mt7996/vendor.c |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 779 | index 64ef551..07c0c36 100644 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 780 | --- a/mt7996/vendor.c |
| 781 | +++ b/mt7996/vendor.c |
| 782 | @@ -119,6 +119,18 @@ beacon_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BEACON_CTRL] = { |
| 783 | [MTK_VENDOR_ATTR_BEACON_CTRL_MODE] = { .type = NLA_U8 }, |
| 784 | }; |
| 785 | |
| 786 | +static const struct nla_policy |
| 787 | +csi_ctrl_policy[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = { |
| 788 | + [MTK_VENDOR_ATTR_CSI_CTRL_CFG] = {.type = NLA_NESTED }, |
| 789 | + [MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE] = { .type = NLA_U8 }, |
| 790 | + [MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE] = { .type = NLA_U8 }, |
| 791 | + [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1] = { .type = NLA_U8 }, |
| 792 | + [MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2] = { .type = NLA_U32 }, |
| 793 | + [MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR] = { .type = NLA_NESTED }, |
| 794 | + [MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM] = { .type = NLA_U16 }, |
| 795 | + [MTK_VENDOR_ATTR_CSI_CTRL_DATA] = { .type = NLA_NESTED }, |
| 796 | +}; |
| 797 | + |
| 798 | struct mt7996_amnt_data { |
| 799 | u8 idx; |
| 800 | u8 addr[ETH_ALEN]; |
| 801 | @@ -1000,7 +1012,188 @@ static int mt7996_vendor_beacon_ctrl(struct wiphy *wiphy, |
| 802 | |
| 803 | return 0; |
| 804 | } |
| 805 | +static int mt7996_vendor_csi_ctrl(struct wiphy *wiphy, |
| 806 | + struct wireless_dev *wdev, |
| 807 | + const void *data, |
| 808 | + int data_len) |
| 809 | +{ |
| 810 | + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); |
| 811 | + struct mt7996_phy *phy = mt7996_hw_phy(hw); |
| 812 | + struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_CSI_CTRL]; |
| 813 | + int err; |
| 814 | + |
| 815 | + err = nla_parse(tb, MTK_VENDOR_ATTR_CSI_CTRL_MAX, data, data_len, |
| 816 | + csi_ctrl_policy, NULL); |
| 817 | + if (err) |
| 818 | + return err; |
| 819 | + |
| 820 | + if (tb[MTK_VENDOR_ATTR_CSI_CTRL_CFG]) { |
| 821 | + u8 mode = 0, type = 0, v1 = 0; |
| 822 | + u32 v2 = 0; |
| 823 | + u8 mac_addr[ETH_ALEN] = {}; |
| 824 | + struct nlattr *cur; |
| 825 | + int rem; |
| 826 | + |
| 827 | + nla_for_each_nested(cur, tb[MTK_VENDOR_ATTR_CSI_CTRL_CFG], rem) { |
| 828 | + switch (nla_type(cur)) { |
| 829 | + case MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE: |
| 830 | + mode = nla_get_u8(cur); |
| 831 | + break; |
| 832 | + case MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE: |
| 833 | + type = nla_get_u8(cur); |
| 834 | + break; |
| 835 | + case MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1: |
| 836 | + v1 = nla_get_u8(cur); |
| 837 | + break; |
| 838 | + case MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2: |
| 839 | + v2 = nla_get_u32(cur); |
| 840 | + break; |
| 841 | + default: |
| 842 | + return -EINVAL; |
| 843 | + }; |
| 844 | + } |
| 845 | + |
| 846 | + if (tb[MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR]) { |
| 847 | + u8 idx = 0; |
| 848 | + |
| 849 | + nla_for_each_nested(cur, tb[MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR], rem) { |
| 850 | + mac_addr[idx++] = nla_get_u8(cur); |
| 851 | + } |
| 852 | + } |
| 853 | + |
| 854 | + err = mt7996_mcu_set_csi(phy, mode, type, v1, v2, mac_addr); |
| 855 | + if (err < 0) |
| 856 | + return err; |
| 857 | + |
| 858 | + spin_lock_bh(&phy->csi.lock); |
| 859 | |
| 860 | + phy->csi.enable = !!mode; |
| 861 | + |
| 862 | + /* clean up old csi stats */ |
| 863 | + if ((mode == CSI_CONTROL_MODE_STOP || mode == CSI_CONTROL_MODE_SET) |
| 864 | + && !list_empty(&phy->csi.list)) { |
| 865 | + struct csi_data *c, *tmp_c; |
| 866 | + |
| 867 | + list_for_each_entry_safe(c, tmp_c, &phy->csi.list, node) { |
| 868 | + list_del(&c->node); |
| 869 | + kfree(c); |
| 870 | + phy->csi.count--; |
| 871 | + } |
| 872 | + } else if (mode == CSI_CONTROL_MODE_START) { |
| 873 | + phy->csi.last_record = 0; |
| 874 | + } |
| 875 | + |
| 876 | + spin_unlock_bh(&phy->csi.lock); |
| 877 | + |
| 878 | + if (mode == CSI_CONTROL_MODE_SET && type == CSI_CONFIG_STA_FILTER && v1 == 2) |
| 879 | + phy->csi.interval = v2; |
| 880 | + } |
| 881 | + |
| 882 | + return 0; |
| 883 | +} |
| 884 | + |
| 885 | +static int |
| 886 | +mt7996_vendor_csi_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 887 | + struct sk_buff *skb, const void *data, int data_len, |
| 888 | + unsigned long *storage) |
| 889 | +{ |
| 890 | +#define RESERVED_SET BIT(31) |
| 891 | + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); |
| 892 | + struct mt7996_phy *phy = mt7996_hw_phy(hw); |
| 893 | + struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = {0}; |
| 894 | + int err = 0; |
| 895 | + |
| 896 | + if (*storage & RESERVED_SET) { |
| 897 | + if ((*storage & GENMASK(15, 0)) == 0) |
| 898 | + return -ENOENT; |
| 899 | + (*storage)--; |
| 900 | + } |
| 901 | + |
| 902 | + if (data) { |
| 903 | + err = nla_parse(tb, MTK_VENDOR_ATTR_CSI_CTRL_MAX, data, data_len, |
| 904 | + csi_ctrl_policy, NULL); |
| 905 | + if (err) |
| 906 | + return err; |
| 907 | + } |
| 908 | + |
| 909 | + if (!(*storage & RESERVED_SET) && tb[MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM]) { |
| 910 | + *storage = nla_get_u16(tb[MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM]); |
| 911 | + *storage |= RESERVED_SET; |
| 912 | + } |
| 913 | + |
| 914 | + spin_lock_bh(&phy->csi.lock); |
| 915 | + |
| 916 | + if (!list_empty(&phy->csi.list)) { |
| 917 | + struct csi_data *csi; |
| 918 | + void *a, *b; |
| 919 | + int i; |
| 920 | + |
| 921 | + csi = list_first_entry(&phy->csi.list, struct csi_data, node); |
| 922 | + |
| 923 | + a = nla_nest_start(skb, MTK_VENDOR_ATTR_CSI_CTRL_DATA); |
| 924 | + if (!a) |
| 925 | + goto out; |
| 926 | + |
| 927 | + if (nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_VER, 1) || |
| 928 | + nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_RSSI, csi->rssi) || |
| 929 | + nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_SNR, csi->snr) || |
| 930 | + nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_BW, csi->data_bw) || |
| 931 | + nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_CH_IDX, csi->pri_ch_idx) || |
| 932 | + nla_put_u8(skb, MTK_VENDOR_ATTR_CSI_DATA_MODE, csi->rx_mode)) |
| 933 | + goto out; |
| 934 | + |
| 935 | + if (nla_put_u16(skb, MTK_VENDOR_ATTR_CSI_DATA_TX_ANT, csi->tx_idx) || |
| 936 | + nla_put_u16(skb, MTK_VENDOR_ATTR_CSI_DATA_RX_ANT, csi->rx_idx)) |
| 937 | + goto out; |
| 938 | + |
| 939 | + if (nla_put_u32(skb, MTK_VENDOR_ATTR_CSI_DATA_INFO, csi->ext_info) || |
| 940 | + nla_put_u32(skb, MTK_VENDOR_ATTR_CSI_DATA_CHAIN_INFO, csi->chain_info) || |
| 941 | + nla_put_u32(skb, MTK_VENDOR_ATTR_CSI_DATA_TS, csi->ts)) |
| 942 | + goto out; |
| 943 | + |
| 944 | + b = nla_nest_start(skb, MTK_VENDOR_ATTR_CSI_DATA_TA); |
| 945 | + if (!b) |
| 946 | + goto out; |
| 947 | + |
| 948 | + for (i = 0; i < ARRAY_SIZE(csi->ta); i++) |
| 949 | + if (nla_put_u8(skb, i, csi->ta[i])) |
| 950 | + goto out; |
| 951 | + nla_nest_end(skb, b); |
| 952 | + |
| 953 | + if (nla_put_u32(skb, MTK_VENDOR_ATTR_CSI_DATA_NUM, csi->data_num)) |
| 954 | + goto out; |
| 955 | + |
| 956 | + b = nla_nest_start(skb, MTK_VENDOR_ATTR_CSI_DATA_I); |
| 957 | + if (!b) |
| 958 | + goto out; |
| 959 | + |
| 960 | + for (i = 0; i < csi->data_num; i++) |
| 961 | + if (nla_put_u16(skb, i, csi->data_i[i])) |
| 962 | + goto out; |
| 963 | + nla_nest_end(skb, b); |
| 964 | + |
| 965 | + b = nla_nest_start(skb, MTK_VENDOR_ATTR_CSI_DATA_Q); |
| 966 | + if (!b) |
| 967 | + goto out; |
| 968 | + |
| 969 | + for (i = 0; i < csi->data_num; i++) |
| 970 | + if (nla_put_u16(skb, i, csi->data_q[i])) |
| 971 | + goto out; |
| 972 | + nla_nest_end(skb, b); |
| 973 | + |
| 974 | + nla_nest_end(skb, a); |
| 975 | + |
| 976 | + list_del(&csi->node); |
| 977 | + kfree(csi); |
| 978 | + phy->csi.count--; |
| 979 | + |
| 980 | + err = phy->csi.count; |
| 981 | + } |
| 982 | +out: |
| 983 | + spin_unlock_bh(&phy->csi.lock); |
| 984 | + |
| 985 | + return err; |
| 986 | +} |
| 987 | |
| 988 | static const struct wiphy_vendor_command mt7996_vendor_commands[] = { |
| 989 | { |
| 990 | @@ -1129,6 +1322,18 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = { |
| 991 | .policy = beacon_ctrl_policy, |
| 992 | .maxattr = MTK_VENDOR_ATTR_BEACON_CTRL_MAX, |
| 993 | }, |
| 994 | + { |
| 995 | + .info = { |
| 996 | + .vendor_id = MTK_NL80211_VENDOR_ID, |
| 997 | + .subcmd = MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL, |
| 998 | + }, |
| 999 | + .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | |
| 1000 | + WIPHY_VENDOR_CMD_NEED_RUNNING, |
| 1001 | + .doit = mt7996_vendor_csi_ctrl, |
| 1002 | + .dumpit = mt7996_vendor_csi_ctrl_dump, |
| 1003 | + .policy = csi_ctrl_policy, |
| 1004 | + .maxattr = MTK_VENDOR_ATTR_CSI_CTRL_MAX, |
| 1005 | + }, |
| 1006 | }; |
| 1007 | |
| 1008 | void mt7996_vendor_register(struct mt7996_phy *phy) |
| 1009 | @@ -1136,6 +1341,9 @@ void mt7996_vendor_register(struct mt7996_phy *phy) |
| 1010 | phy->mt76->hw->wiphy->vendor_commands = mt7996_vendor_commands; |
| 1011 | phy->mt76->hw->wiphy->n_vendor_commands = ARRAY_SIZE(mt7996_vendor_commands); |
| 1012 | |
| 1013 | + INIT_LIST_HEAD(&phy->csi.list); |
| 1014 | + spin_lock_init(&phy->csi.lock); |
| 1015 | + |
| 1016 | spin_lock_init(&phy->amnt_lock); |
| 1017 | } |
| 1018 | #endif |
| 1019 | diff --git a/mt7996/vendor.h b/mt7996/vendor.h |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 1020 | index 3234677..abe3fde 100644 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 1021 | --- a/mt7996/vendor.h |
| 1022 | +++ b/mt7996/vendor.h |
| 1023 | @@ -7,6 +7,7 @@ |
| 1024 | |
| 1025 | enum mtk_nl80211_vendor_subcmds { |
| 1026 | MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae, |
| 1027 | + MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL = 0xc2, |
| 1028 | MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL = 0xc3, |
| 1029 | MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL = 0xc4, |
| 1030 | MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5, |
| 1031 | @@ -240,6 +241,55 @@ enum mtk_vendor_attr_beacon_ctrl { |
| 1032 | NUM_MTK_VENDOR_ATTRS_BEACON_CTRL - 1 |
| 1033 | }; |
| 1034 | |
| 1035 | +enum mtk_vendor_attr_csi_ctrl { |
| 1036 | + MTK_VENDOR_ATTR_CSI_CTRL_UNSPEC, |
| 1037 | + |
| 1038 | + MTK_VENDOR_ATTR_CSI_CTRL_CFG, |
| 1039 | + MTK_VENDOR_ATTR_CSI_CTRL_CFG_MODE, |
| 1040 | + MTK_VENDOR_ATTR_CSI_CTRL_CFG_TYPE, |
| 1041 | + MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL1, |
| 1042 | + MTK_VENDOR_ATTR_CSI_CTRL_CFG_VAL2, |
| 1043 | + MTK_VENDOR_ATTR_CSI_CTRL_MAC_ADDR, |
| 1044 | + |
| 1045 | + MTK_VENDOR_ATTR_CSI_CTRL_DUMP_NUM, |
| 1046 | + |
| 1047 | + MTK_VENDOR_ATTR_CSI_CTRL_DATA, |
| 1048 | + |
| 1049 | + /* keep last */ |
| 1050 | + NUM_MTK_VENDOR_ATTRS_CSI_CTRL, |
| 1051 | + MTK_VENDOR_ATTR_CSI_CTRL_MAX = |
| 1052 | + NUM_MTK_VENDOR_ATTRS_CSI_CTRL - 1 |
| 1053 | +}; |
| 1054 | + |
| 1055 | +enum mtk_vendor_attr_csi_data { |
| 1056 | + MTK_VENDOR_ATTR_CSI_DATA_UNSPEC, |
| 1057 | + MTK_VENDOR_ATTR_CSI_DATA_PAD, |
| 1058 | + |
| 1059 | + MTK_VENDOR_ATTR_CSI_DATA_VER, |
| 1060 | + MTK_VENDOR_ATTR_CSI_DATA_TS, |
| 1061 | + MTK_VENDOR_ATTR_CSI_DATA_RSSI, |
| 1062 | + MTK_VENDOR_ATTR_CSI_DATA_SNR, |
| 1063 | + MTK_VENDOR_ATTR_CSI_DATA_BW, |
| 1064 | + MTK_VENDOR_ATTR_CSI_DATA_CH_IDX, |
| 1065 | + MTK_VENDOR_ATTR_CSI_DATA_TA, |
| 1066 | + MTK_VENDOR_ATTR_CSI_DATA_NUM, |
| 1067 | + MTK_VENDOR_ATTR_CSI_DATA_I, |
| 1068 | + MTK_VENDOR_ATTR_CSI_DATA_Q, |
| 1069 | + MTK_VENDOR_ATTR_CSI_DATA_INFO, |
| 1070 | + MTK_VENDOR_ATTR_CSI_DATA_RSVD1, |
| 1071 | + MTK_VENDOR_ATTR_CSI_DATA_RSVD2, |
| 1072 | + MTK_VENDOR_ATTR_CSI_DATA_RSVD3, |
| 1073 | + MTK_VENDOR_ATTR_CSI_DATA_RSVD4, |
| 1074 | + MTK_VENDOR_ATTR_CSI_DATA_TX_ANT, |
| 1075 | + MTK_VENDOR_ATTR_CSI_DATA_RX_ANT, |
| 1076 | + MTK_VENDOR_ATTR_CSI_DATA_MODE, |
| 1077 | + MTK_VENDOR_ATTR_CSI_DATA_CHAIN_INFO, |
| 1078 | + |
| 1079 | + /* keep last */ |
| 1080 | + NUM_MTK_VENDOR_ATTRS_CSI_DATA, |
| 1081 | + MTK_VENDOR_ATTR_CSI_DATA_MAX = |
| 1082 | + NUM_MTK_VENDOR_ATTRS_CSI_DATA - 1 |
| 1083 | +}; |
| 1084 | #endif |
| 1085 | |
| 1086 | #endif |
| 1087 | -- |
developer | 9237f44 | 2024-06-14 17:13:04 +0800 | [diff] [blame^] | 1088 | 2.18.0 |
developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 1089 | |