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