Kalle Valo says: ==================== wireless-drivers-next patches for 4.10 Major changes: rsi * filter rx frames * configure tx power * make it possible to select antenna * support 802.11d brcmfmac * cleanup of scheduled scan code * support for bcm43341 chipset with different chip id * support rev6 of PCIe device interface ath10k * add spectral scan support for QCA6174 and QCA9377 families * show used tx bitrate with 10.4 firmware wil6210 * add power save mode support * add abort scan functionality * add support settings retry limit for short frames bcma * add Dell Inspiron 3148 ====================
Unified · Split
| @@ -295,6 +295,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = { · 294 unmodified lines | ||
| 295 | 295 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, |
| 296 | 296 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) }, |
| 297 | 297 | { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) }, |
| 298 | + { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0018) }, | |
| 298 | 299 | { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) }, |
| 299 | 300 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) }, |
| 300 | 301 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, |
| @@ -326,6 +326,7 @@ static const char *const ath10k_core_fw_feature_str[] = { · 325 unmodified lines | ||
| 326 | 326 | [ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl", |
| 327 | 327 | [ATH10K_FW_FEATURE_BTCOEX_PARAM] = "btcoex-param", |
| 328 | 328 | [ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR] = "skip-null-func-war", |
| 329 | + [ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast", | |
| 329 | 330 | }; |
| 330 | 331 | |
| 331 | 332 | static unsigned int ath10k_core_get_fw_feature_str(char *buf, |
| @@ -1536,7 +1537,7 @@ static void ath10k_core_restart(struct work_struct *work) · 1204 unmodified lines | ||
| 1536 | 1537 | switch (ar->state) { |
| 1537 | 1538 | case ATH10K_STATE_ON: |
| 1538 | 1539 | ar->state = ATH10K_STATE_RESTARTING; |
| 1539 | − ath10k_hif_stop(ar); | |
| 1540 | + ath10k_halt(ar); | |
| 1540 | 1541 | ath10k_scan_finish(ar); |
| 1541 | 1542 | ieee80211_restart_hw(ar->hw); |
| 1542 | 1543 | break; |
| @@ -1857,7 +1858,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, · 314 unmodified lines | ||
| 1857 | 1858 | goto err_wmi_detach; |
| 1858 | 1859 | } |
| 1859 | 1860 | |
| 1860 | − status = ath10k_htt_tx_alloc(&ar->htt); | |
| 1861 | + status = ath10k_htt_tx_start(&ar->htt); | |
| 1861 | 1862 | if (status) { |
| 1862 | 1863 | ath10k_err(ar, "failed to alloc htt tx: %d\n", status); |
| 1863 | 1864 | goto err_wmi_detach; |
| @@ -2052,7 +2053,7 @@ void ath10k_core_stop(struct ath10k *ar) · 188 unmodified lines | ||
| 2052 | 2053 | ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); |
| 2053 | 2054 | |
| 2054 | 2055 | ath10k_hif_stop(ar); |
| 2055 | − ath10k_htt_tx_free(&ar->htt); | |
| 2056 | + ath10k_htt_tx_stop(&ar->htt); | |
| 2056 | 2057 | ath10k_htt_rx_free(&ar->htt); |
| 2057 | 2058 | ath10k_wmi_detach(ar); |
| 2058 | 2059 | } |
| @@ -2385,6 +2386,7 @@ void ath10k_core_destroy(struct ath10k *ar) · 326 unmodified lines | ||
| 2385 | 2386 | destroy_workqueue(ar->workqueue_aux); |
| 2386 | 2387 | |
| 2387 | 2388 | ath10k_debug_destroy(ar); |
| 2389 | + ath10k_htt_tx_destroy(&ar->htt); | |
| 2388 | 2390 | ath10k_wmi_free_host_mem(ar); |
| 2389 | 2391 | ath10k_mac_destroy(ar); |
| 2390 | 2392 | } |
| @@ -337,6 +337,7 @@ struct ath10k_sta { · 336 unmodified lines | ||
| 337 | 337 | u32 nss; |
| 338 | 338 | u32 smps; |
| 339 | 339 | u16 peer_id; |
| 340 | + struct rate_info txrate; | |
| 340 | 341 | |
| 341 | 342 | struct work_struct update_wk; |
| 342 | 343 | |
| @@ -562,6 +563,13 @@ enum ath10k_fw_features { · 219 unmodified lines | ||
| 562 | 563 | */ |
| 563 | 564 | ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR = 15, |
| 564 | 565 | |
| 566 | + /* Firmware allow other BSS mesh broadcast/multicast frames without | |
| 567 | + * creating monitor interface. Appropriate rxfilters are programmed for | |
| 568 | + * mesh vdev by firmware itself. This feature flags will be used for | |
| 569 | + * not creating monitor vdev while configuring mesh node. | |
| 570 | + */ | |
| 571 | + ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST = 16, | |
| 572 | + | |
| 565 | 573 | /* keep last */ |
| 566 | 574 | ATH10K_FW_FEATURE_COUNT, |
| 567 | 575 | }; |
| @@ -693,6 +701,21 @@ struct ath10k_fw_components { · 125 unmodified lines | ||
| 693 | 701 | struct ath10k_fw_file fw_file; |
| 694 | 702 | }; |
| 695 | 703 | |
| 704 | +struct ath10k_per_peer_tx_stats { | |
| 705 | + u32 succ_bytes; | |
| 706 | + u32 retry_bytes; | |
| 707 | + u32 failed_bytes; | |
| 708 | + u8 ratecode; | |
| 709 | + u8 flags; | |
| 710 | + u16 peer_id; | |
| 711 | + u16 succ_pkts; | |
| 712 | + u16 retry_pkts; | |
| 713 | + u16 failed_pkts; | |
| 714 | + u16 duration; | |
| 715 | + u32 reserved1; | |
| 716 | + u32 reserved2; | |
| 717 | +}; | |
| 718 | + | |
| 696 | 719 | struct ath10k { |
| 697 | 720 | struct ath_common ath_common; |
| 698 | 721 | struct ieee80211_hw *hw; |
| @@ -906,6 +929,7 @@ struct ath10k { · 207 unmodified lines | ||
| 906 | 929 | |
| 907 | 930 | struct ath10k_thermal thermal; |
| 908 | 931 | struct ath10k_wow wow; |
| 932 | + struct ath10k_per_peer_tx_stats peer_tx_stats; | |
| 909 | 933 | |
| 910 | 934 | /* NAPI */ |
| 911 | 935 | struct net_device napi_dev; |
| @@ -77,6 +77,19 @@ void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 76 unmodified lines | ||
| 77 | 77 | |
| 78 | 78 | sinfo->rx_duration = arsta->rx_duration; |
| 79 | 79 | sinfo->filled |= 1ULL << NL80211_STA_INFO_RX_DURATION; |
| 80 | + | |
| 81 | + if (!arsta->txrate.legacy && !arsta->txrate.nss) | |
| 82 | + return; | |
| 83 | + | |
| 84 | + if (arsta->txrate.legacy) { | |
| 85 | + sinfo->txrate.legacy = arsta->txrate.legacy; | |
| 86 | + } else { | |
| 87 | + sinfo->txrate.mcs = arsta->txrate.mcs; | |
| 88 | + sinfo->txrate.nss = arsta->txrate.nss; | |
| 89 | + sinfo->txrate.bw = arsta->txrate.bw; | |
| 90 | + } | |
| 91 | + sinfo->txrate.flags = arsta->txrate.flags; | |
| 92 | + sinfo->filled |= 1ULL << NL80211_STA_INFO_TX_BITRATE; | |
| 80 | 93 | } |
| 81 | 94 | |
| 82 | 95 | static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, |
| @@ -137,6 +137,8 @@ static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = { · 136 unmodified lines | ||
| 137 | 137 | HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, |
| 138 | 138 | [HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] = |
| 139 | 139 | HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND, |
| 140 | + [HTT_10_4_T2H_MSG_TYPE_PEER_STATS] = | |
| 141 | + HTT_T2H_MSG_TYPE_PEER_STATS, | |
| 140 | 142 | }; |
| 141 | 143 | |
| 142 | 144 | int ath10k_htt_connect(struct ath10k_htt *htt) |
| @@ -419,6 +419,7 @@ enum htt_10_4_t2h_msg_type { · 418 unmodified lines | ||
| 419 | 419 | HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18, |
| 420 | 420 | /* 0x19 to 0x2f are reserved */ |
| 421 | 421 | HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND = 0x30, |
| 422 | + HTT_10_4_T2H_MSG_TYPE_PEER_STATS = 0x31, | |
| 422 | 423 | /* keep this last */ |
| 423 | 424 | HTT_10_4_T2H_NUM_MSGS |
| 424 | 425 | }; |
| @@ -453,6 +454,7 @@ enum htt_t2h_msg_type { · 28 unmodified lines | ||
| 453 | 454 | HTT_T2H_MSG_TYPE_TX_FETCH_IND, |
| 454 | 455 | HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM, |
| 455 | 456 | HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND, |
| 457 | + HTT_T2H_MSG_TYPE_PEER_STATS, | |
| 456 | 458 | /* keep this last */ |
| 457 | 459 | HTT_T2H_NUM_MSGS |
| 458 | 460 | }; |
| @@ -1470,6 +1472,28 @@ struct htt_channel_change { · 1011 unmodified lines | ||
| 1470 | 1472 | __le32 phymode; |
| 1471 | 1473 | } __packed; |
| 1472 | 1474 | |
| 1475 | +struct htt_per_peer_tx_stats_ind { | |
| 1476 | + __le32 succ_bytes; | |
| 1477 | + __le32 retry_bytes; | |
| 1478 | + __le32 failed_bytes; | |
| 1479 | + u8 ratecode; | |
| 1480 | + u8 flags; | |
| 1481 | + __le16 peer_id; | |
| 1482 | + __le16 succ_pkts; | |
| 1483 | + __le16 retry_pkts; | |
| 1484 | + __le16 failed_pkts; | |
| 1485 | + __le16 tx_duration; | |
| 1486 | + __le32 reserved1; | |
| 1487 | + __le32 reserved2; | |
| 1488 | +} __packed; | |
| 1489 | + | |
| 1490 | +struct htt_peer_tx_stats { | |
| 1491 | + u8 num_ppdu; | |
| 1492 | + u8 ppdu_len; | |
| 1493 | + u8 version; | |
| 1494 | + u8 payload[0]; | |
| 1495 | +} __packed; | |
| 1496 | + | |
| 1473 | 1497 | union htt_rx_pn_t { |
| 1474 | 1498 | /* WEP: 24-bit PN */ |
| 1475 | 1499 | u32 pn24; |
| @@ -1521,6 +1545,7 @@ struct htt_resp { · 45 unmodified lines | ||
| 1521 | 1545 | struct htt_tx_fetch_confirm tx_fetch_confirm; |
| 1522 | 1546 | struct htt_tx_mode_switch_ind tx_mode_switch_ind; |
| 1523 | 1547 | struct htt_channel_change chan_change; |
| 1548 | + struct htt_peer_tx_stats peer_tx_stats; | |
| 1524 | 1549 | }; |
| 1525 | 1550 | } __packed; |
| 1526 | 1551 | |
| @@ -1692,6 +1717,8 @@ struct ath10k_htt { · 165 unmodified lines | ||
| 1692 | 1717 | enum htt_tx_mode_switch_mode mode; |
| 1693 | 1718 | enum htt_q_depth_type type; |
| 1694 | 1719 | } tx_q_state; |
| 1720 | + | |
| 1721 | + bool tx_mem_allocated; | |
| 1695 | 1722 | }; |
| 1696 | 1723 | |
| 1697 | 1724 | #define RX_HTT_HDR_STATUS_LEN 64 |
| @@ -1754,7 +1781,9 @@ int ath10k_htt_connect(struct ath10k_htt *htt); · 56 unmodified lines | ||
| 1754 | 1781 | int ath10k_htt_init(struct ath10k *ar); |
| 1755 | 1782 | int ath10k_htt_setup(struct ath10k_htt *htt); |
| 1756 | 1783 | |
| 1757 | −int ath10k_htt_tx_alloc(struct ath10k_htt *htt); | |
| 1784 | +int ath10k_htt_tx_start(struct ath10k_htt *htt); | |
| 1785 | +void ath10k_htt_tx_stop(struct ath10k_htt *htt); | |
| 1786 | +void ath10k_htt_tx_destroy(struct ath10k_htt *htt); | |
| 1758 | 1787 | void ath10k_htt_tx_free(struct ath10k_htt *htt); |
| 1759 | 1788 | |
| 1760 | 1789 | int ath10k_htt_rx_alloc(struct ath10k_htt *htt); |
| @@ -2194,6 +2194,128 @@ void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) · 2193 unmodified lines | ||
| 2194 | 2194 | dev_kfree_skb_any(skb); |
| 2195 | 2195 | } |
| 2196 | 2196 | |
| 2197 | +static inline bool is_valid_legacy_rate(u8 rate) | |
| 2198 | +{ | |
| 2199 | + static const u8 legacy_rates[] = {1, 2, 5, 11, 6, 9, 12, | |
| 2200 | + 18, 24, 36, 48, 54}; | |
| 2201 | + int i; | |
| 2202 | + | |
| 2203 | + for (i = 0; i < ARRAY_SIZE(legacy_rates); i++) { | |
| 2204 | + if (rate == legacy_rates[i]) | |
| 2205 | + return true; | |
| 2206 | + } | |
| 2207 | + | |
| 2208 | + return false; | |
| 2209 | +} | |
| 2210 | + | |
| 2211 | +static void | |
| 2212 | +ath10k_update_per_peer_tx_stats(struct ath10k *ar, | |
| 2213 | + struct ieee80211_sta *sta, | |
| 2214 | + struct ath10k_per_peer_tx_stats *peer_stats) | |
| 2215 | +{ | |
| 2216 | + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; | |
| 2217 | + u8 rate = 0, sgi; | |
| 2218 | + struct rate_info txrate; | |
| 2219 | + | |
| 2220 | + lockdep_assert_held(&ar->data_lock); | |
| 2221 | + | |
| 2222 | + txrate.flags = ATH10K_HW_PREAMBLE(peer_stats->ratecode); | |
| 2223 | + txrate.bw = ATH10K_HW_BW(peer_stats->flags); | |
| 2224 | + txrate.nss = ATH10K_HW_NSS(peer_stats->ratecode); | |
| 2225 | + txrate.mcs = ATH10K_HW_MCS_RATE(peer_stats->ratecode); | |
| 2226 | + sgi = ATH10K_HW_GI(peer_stats->flags); | |
| 2227 | + | |
| 2228 | + if (((txrate.flags == WMI_RATE_PREAMBLE_HT) || | |
| 2229 | + (txrate.flags == WMI_RATE_PREAMBLE_VHT)) && txrate.mcs > 9) { | |
| 2230 | + ath10k_warn(ar, "Invalid mcs %hhd peer stats", txrate.mcs); | |
| 2231 | + return; | |
| 2232 | + } | |
| 2233 | + | |
| 2234 | + if (txrate.flags == WMI_RATE_PREAMBLE_CCK || | |
| 2235 | + txrate.flags == WMI_RATE_PREAMBLE_OFDM) { | |
| 2236 | + rate = ATH10K_HW_LEGACY_RATE(peer_stats->ratecode); | |
| 2237 | + | |
| 2238 | + if (!is_valid_legacy_rate(rate)) { | |
| 2239 | + ath10k_warn(ar, "Invalid legacy rate %hhd peer stats", | |
| 2240 | + rate); | |
| 2241 | + return; | |
| 2242 | + } | |
| 2243 | + | |
| 2244 | + /* This is hacky, FW sends CCK rate 5.5Mbps as 6 */ | |
| 2245 | + rate *= 10; | |
| 2246 | + if (rate == 60 && txrate.flags == WMI_RATE_PREAMBLE_CCK) | |
| 2247 | + rate = rate - 5; | |
| 2248 | + arsta->txrate.legacy = rate * 10; | |
| 2249 | + } else if (txrate.flags == WMI_RATE_PREAMBLE_HT) { | |
| 2250 | + arsta->txrate.flags = RATE_INFO_FLAGS_MCS; | |
| 2251 | + arsta->txrate.mcs = txrate.mcs; | |
| 2252 | + } else { | |
| 2253 | + arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; | |
| 2254 | + arsta->txrate.mcs = txrate.mcs; | |
| 2255 | + } | |
| 2256 | + | |
| 2257 | + if (sgi) | |
| 2258 | + arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | |
| 2259 | + | |
| 2260 | + arsta->txrate.nss = txrate.nss; | |
| 2261 | + arsta->txrate.bw = txrate.bw + RATE_INFO_BW_20; | |
| 2262 | +} | |
| 2263 | + | |
| 2264 | +static void ath10k_htt_fetch_peer_stats(struct ath10k *ar, | |
| 2265 | + struct sk_buff *skb) | |
| 2266 | +{ | |
| 2267 | + struct htt_resp *resp = (struct htt_resp *)skb->data; | |
| 2268 | + struct ath10k_per_peer_tx_stats *p_tx_stats = &ar->peer_tx_stats; | |
| 2269 | + struct htt_per_peer_tx_stats_ind *tx_stats; | |
| 2270 | + struct ieee80211_sta *sta; | |
| 2271 | + struct ath10k_peer *peer; | |
| 2272 | + int peer_id, i; | |
| 2273 | + u8 ppdu_len, num_ppdu; | |
| 2274 | + | |
| 2275 | + num_ppdu = resp->peer_tx_stats.num_ppdu; | |
| 2276 | + ppdu_len = resp->peer_tx_stats.ppdu_len * sizeof(__le32); | |
| 2277 | + | |
| 2278 | + if (skb->len < sizeof(struct htt_resp_hdr) + num_ppdu * ppdu_len) { | |
| 2279 | + ath10k_warn(ar, "Invalid peer stats buf length %d\n", skb->len); | |
| 2280 | + return; | |
| 2281 | + } | |
| 2282 | + | |
| 2283 | + tx_stats = (struct htt_per_peer_tx_stats_ind *) | |
| 2284 | + (resp->peer_tx_stats.payload); | |
| 2285 | + peer_id = __le16_to_cpu(tx_stats->peer_id); | |
| 2286 | + | |
| 2287 | + rcu_read_lock(); | |
| 2288 | + spin_lock_bh(&ar->data_lock); | |
| 2289 | + peer = ath10k_peer_find_by_id(ar, peer_id); | |
| 2290 | + if (!peer) { | |
| 2291 | + ath10k_warn(ar, "Invalid peer id %d peer stats buffer\n", | |
| 2292 | + peer_id); | |
| 2293 | + goto out; | |
| 2294 | + } | |
| 2295 | + | |
| 2296 | + sta = peer->sta; | |
| 2297 | + for (i = 0; i < num_ppdu; i++) { | |
| 2298 | + tx_stats = (struct htt_per_peer_tx_stats_ind *) | |
| 2299 | + (resp->peer_tx_stats.payload + i * ppdu_len); | |
| 2300 | + | |
| 2301 | + p_tx_stats->succ_bytes = __le32_to_cpu(tx_stats->succ_bytes); | |
| 2302 | + p_tx_stats->retry_bytes = __le32_to_cpu(tx_stats->retry_bytes); | |
| 2303 | + p_tx_stats->failed_bytes = | |
| 2304 | + __le32_to_cpu(tx_stats->failed_bytes); | |
| 2305 | + p_tx_stats->ratecode = tx_stats->ratecode; | |
| 2306 | + p_tx_stats->flags = tx_stats->flags; | |
| 2307 | + p_tx_stats->succ_pkts = __le16_to_cpu(tx_stats->succ_pkts); | |
| 2308 | + p_tx_stats->retry_pkts = __le16_to_cpu(tx_stats->retry_pkts); | |
| 2309 | + p_tx_stats->failed_pkts = __le16_to_cpu(tx_stats->failed_pkts); | |
| 2310 | + | |
| 2311 | + ath10k_update_per_peer_tx_stats(ar, sta, p_tx_stats); | |
| 2312 | + } | |
| 2313 | + | |
| 2314 | +out: | |
| 2315 | + spin_unlock_bh(&ar->data_lock); | |
| 2316 | + rcu_read_unlock(); | |
| 2317 | +} | |
| 2318 | + | |
| 2197 | 2319 | bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) |
| 2198 | 2320 | { |
| 2199 | 2321 | struct ath10k_htt *htt = &ar->htt; |
| @@ -2354,6 +2476,9 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) · 154 unmodified lines | ||
| 2354 | 2476 | case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND: |
| 2355 | 2477 | ath10k_htt_rx_tx_mode_switch_ind(ar, skb); |
| 2356 | 2478 | break; |
| 2479 | + case HTT_T2H_MSG_TYPE_PEER_STATS: | |
| 2480 | + ath10k_htt_fetch_peer_stats(ar, skb); | |
| 2481 | + break; | |
| 2357 | 2482 | case HTT_T2H_MSG_TYPE_EN_STATS: |
| 2358 | 2483 | default: |
| 2359 | 2484 | ath10k_warn(ar, "htt event (%d) not handled\n", |
| @@ -350,21 +350,15 @@ static int ath10k_htt_tx_alloc_txdone_fifo(struct ath10k_htt *htt) · 349 unmodified lines | ||
| 350 | 350 | return ret; |
| 351 | 351 | } |
| 352 | 352 | |
| 353 | −int ath10k_htt_tx_alloc(struct ath10k_htt *htt) | |
| 353 | +static int ath10k_htt_tx_alloc_buf(struct ath10k_htt *htt) | |
| 354 | 354 | { |
| 355 | 355 | struct ath10k *ar = htt->ar; |
| 356 | 356 | int ret; |
| 357 | 357 | |
| 358 | − ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", | |
| 359 | − htt->max_num_pending_tx); | |
| 360 | − | |
| 361 | − spin_lock_init(&htt->tx_lock); | |
| 362 | − idr_init(&htt->pending_tx); | |
| 363 | − | |
| 364 | 358 | ret = ath10k_htt_tx_alloc_cont_txbuf(htt); |
| 365 | 359 | if (ret) { |
| 366 | 360 | ath10k_err(ar, "failed to alloc cont tx buffer: %d\n", ret); |
| 367 | − goto free_idr_pending_tx; | |
| 361 | + return ret; | |
| 368 | 362 | } |
| 369 | 363 | |
| 370 | 364 | ret = ath10k_htt_tx_alloc_cont_frag_desc(htt); |
| @@ -396,6 +390,31 @@ free_frag_desc: · 25 unmodified lines | ||
| 396 | 390 | free_txbuf: |
| 397 | 391 | ath10k_htt_tx_free_cont_txbuf(htt); |
| 398 | 392 | |
| 393 | + return ret; | |
| 394 | +} | |
| 395 | + | |
| 396 | +int ath10k_htt_tx_start(struct ath10k_htt *htt) | |
| 397 | +{ | |
| 398 | + struct ath10k *ar = htt->ar; | |
| 399 | + int ret; | |
| 400 | + | |
| 401 | + ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", | |
| 402 | + htt->max_num_pending_tx); | |
| 403 | + | |
| 404 | + spin_lock_init(&htt->tx_lock); | |
| 405 | + idr_init(&htt->pending_tx); | |
| 406 | + | |
| 407 | + if (htt->tx_mem_allocated) | |
| 408 | + return 0; | |
| 409 | + | |
| 410 | + ret = ath10k_htt_tx_alloc_buf(htt); | |
| 411 | + if (ret) | |
| 412 | + goto free_idr_pending_tx; | |
| 413 | + | |
| 414 | + htt->tx_mem_allocated = true; | |
| 415 | + | |
| 416 | + return 0; | |
| 417 | + | |
| 399 | 418 | free_idr_pending_tx: |
| 400 | 419 | idr_destroy(&htt->pending_tx); |
| 401 | 420 | |
| @@ -418,15 +437,28 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) · 16 unmodified lines | ||
| 418 | 437 | return 0; |
| 419 | 438 | } |
| 420 | 439 | |
| 421 | −void ath10k_htt_tx_free(struct ath10k_htt *htt) | |
| 440 | +void ath10k_htt_tx_destroy(struct ath10k_htt *htt) | |
| 422 | 441 | { |
| 423 | − idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); | |
| 424 | − idr_destroy(&htt->pending_tx); | |
| 442 | + if (!htt->tx_mem_allocated) | |
| 443 | + return; | |
| 425 | 444 | |
| 426 | 445 | ath10k_htt_tx_free_cont_txbuf(htt); |
| 427 | 446 | ath10k_htt_tx_free_txq(htt); |
| 428 | 447 | ath10k_htt_tx_free_cont_frag_desc(htt); |
| 429 | 448 | ath10k_htt_tx_free_txdone_fifo(htt); |
| 449 | + htt->tx_mem_allocated = false; | |
| 450 | +} | |
| 451 | + | |
| 452 | +void ath10k_htt_tx_stop(struct ath10k_htt *htt) | |
| 453 | +{ | |
| 454 | + idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); | |
| 455 | + idr_destroy(&htt->pending_tx); | |
| 456 | +} | |
| 457 | + | |
| 458 | +void ath10k_htt_tx_free(struct ath10k_htt *htt) | |
| 459 | +{ | |
| 460 | + ath10k_htt_tx_stop(htt); | |
| 461 | + ath10k_htt_tx_destroy(htt); | |
| 430 | 462 | } |
| 431 | 463 | |
| 432 | 464 | void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) |
| @@ -1167,7 +1167,9 @@ static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar) · 1166 unmodified lines | ||
| 1167 | 1167 | return false; |
| 1168 | 1168 | |
| 1169 | 1169 | return ar->monitor || |
| 1170 | − ar->filter_flags & FIF_OTHER_BSS || | |
| 1170 | + (!test_bit(ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST, | |
| 1171 | + ar->running_fw->fw_file.fw_features) && | |
| 1172 | + (ar->filter_flags & FIF_OTHER_BSS)) || | |
| 1171 | 1173 | test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); |
| 1172 | 1174 | } |
| 1173 | 1175 | |
| @@ -4449,7 +4451,6 @@ static int ath10k_start(struct ieee80211_hw *hw) · 3275 unmodified lines | ||
| 4449 | 4451 | ar->state = ATH10K_STATE_ON; |
| 4450 | 4452 | break; |
| 4451 | 4453 | case ATH10K_STATE_RESTARTING: |
| 4452 | − ath10k_halt(ar); | |
| 4453 | 4454 | ar->state = ATH10K_STATE_RESTARTED; |
| 4454 | 4455 | break; |
| 4455 | 4456 | case ATH10K_STATE_ON: |
| @@ -6976,40 +6977,28 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, · 2520 unmodified lines | ||
| 6976 | 6977 | ieee80211_queue_work(hw, &arsta->update_wk); |
| 6977 | 6978 | } |
| 6978 | 6979 | |
| 6979 | −static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |
| 6980 | −{ | |
| 6981 | − /* | |
| 6982 | − * FIXME: Return 0 for time being. Need to figure out whether FW | |
| 6983 | − * has the API to fetch 64-bit local TSF | |
| 6984 | − */ | |
| 6985 | − | |
| 6986 | − return 0; | |
| 6987 | −} | |
| 6988 | − | |
| 6989 | −static void ath10k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |
| 6990 | − u64 tsf) | |
| 6980 | +static void ath10k_offset_tsf(struct ieee80211_hw *hw, | |
| 6981 | + struct ieee80211_vif *vif, s64 tsf_offset) | |
| 6991 | 6982 | { |
| 6992 | 6983 | struct ath10k *ar = hw->priv; |
| 6993 | 6984 | struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); |
| 6994 | − u32 tsf_offset, vdev_param = ar->wmi.vdev_param->set_tsf; | |
| 6985 | + u32 offset, vdev_param; | |
| 6995 | 6986 | int ret; |
| 6996 | 6987 | |
| 6997 | − /* Workaround: | |
| 6998 | − * | |
| 6999 | − * Given tsf argument is entire TSF value, but firmware accepts | |
| 7000 | − * only TSF offset to current TSF. | |
| 7001 | − * | |
| 7002 | − * get_tsf function is used to get offset value, however since | |
| 7003 | − * ath10k_get_tsf is not implemented properly, it will return 0 always. | |
| 7004 | − * Luckily all the caller functions to set_tsf, as of now, also rely on | |
| 7005 | − * get_tsf function to get entire tsf value such get_tsf() + tsf_delta, | |
| 7006 | − * final tsf offset value to firmware will be arithmetically correct. | |
| 7007 | − */ | |
| 7008 | − tsf_offset = tsf - ath10k_get_tsf(hw, vif); | |
| 6988 | + if (tsf_offset < 0) { | |
| 6989 | + vdev_param = ar->wmi.vdev_param->dec_tsf; | |
| 6990 | + offset = -tsf_offset; | |
| 6991 | + } else { | |
| 6992 | + vdev_param = ar->wmi.vdev_param->inc_tsf; | |
| 6993 | + offset = tsf_offset; | |
| 6994 | + } | |
| 6995 | + | |
| 7009 | 6996 | ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, |
| 7010 | − vdev_param, tsf_offset); | |
| 6997 | + vdev_param, offset); | |
| 6998 | + | |
| 7011 | 6999 | if (ret && ret != -EOPNOTSUPP) |
| 7012 | − ath10k_warn(ar, "failed to set tsf offset: %d\n", ret); | |
| 7000 | + ath10k_warn(ar, "failed to set tsf offset %d cmd %d: %d\n", | |
| 7001 | + offset, vdev_param, ret); | |
| 7013 | 7002 | } |
| 7014 | 7003 | |
| 7015 | 7004 | static int ath10k_ampdu_action(struct ieee80211_hw *hw, |
| @@ -7474,8 +7463,7 @@ static const struct ieee80211_ops ath10k_ops = { · 458 unmodified lines | ||
| 7474 | 7463 | .get_survey = ath10k_get_survey, |
| 7475 | 7464 | .set_bitrate_mask = ath10k_mac_op_set_bitrate_mask, |
| 7476 | 7465 | .sta_rc_update = ath10k_sta_rc_update, |
| 7477 | − .get_tsf = ath10k_get_tsf, | |
| 7478 | − .set_tsf = ath10k_set_tsf, | |
| 7466 | + .offset_tsf = ath10k_offset_tsf, | |
| 7479 | 7467 | .ampdu_action = ath10k_ampdu_action, |
| 7480 | 7468 | .get_et_sset_count = ath10k_debug_get_et_sset_count, |
| 7481 | 7469 | .get_et_stats = ath10k_debug_get_et_stats, |
| @@ -8006,6 +7994,7 @@ int ath10k_mac_register(struct ath10k *ar) · 524 unmodified lines | ||
| 8006 | 7994 | ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); |
| 8007 | 7995 | ieee80211_hw_set(ar->hw, QUEUE_CONTROL); |
| 8008 | 7996 | ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); |
| 7997 | + ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); | |
| 8009 | 7998 | |
| 8010 | 7999 | if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) |
| 8011 | 8000 | ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); |
| @@ -660,6 +660,9 @@ ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, · 659 unmodified lines | ||
| 660 | 660 | struct sk_buff *skb; |
| 661 | 661 | u32 cmd_id; |
| 662 | 662 | |
| 663 | + if (!ar->wmi.ops->gen_vdev_spectral_conf) | |
| 664 | + return -EOPNOTSUPP; | |
| 665 | + | |
| 663 | 666 | skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg); |
| 664 | 667 | if (IS_ERR(skb)) |
| 665 | 668 | return PTR_ERR(skb); |
| @@ -675,6 +678,9 @@ ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, · 9 unmodified lines | ||
| 675 | 678 | struct sk_buff *skb; |
| 676 | 679 | u32 cmd_id; |
| 677 | 680 | |
| 681 | + if (!ar->wmi.ops->gen_vdev_spectral_enable) | |
| 682 | + return -EOPNOTSUPP; | |
| 683 | + | |
| 678 | 684 | skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger, |
| 679 | 685 | enable); |
| 680 | 686 | if (IS_ERR(skb)) |
| @@ -1313,8 +1313,8 @@ ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar, · 1312 unmodified lines | ||
| 1313 | 1313 | cmd->regd = __cpu_to_le32(rd); |
| 1314 | 1314 | cmd->regd_2ghz = __cpu_to_le32(rd2g); |
| 1315 | 1315 | cmd->regd_5ghz = __cpu_to_le32(rd5g); |
| 1316 | − cmd->conform_limit_2ghz = __cpu_to_le32(rd2g); | |
| 1317 | − cmd->conform_limit_5ghz = __cpu_to_le32(rd5g); | |
| 1316 | + cmd->conform_limit_2ghz = __cpu_to_le32(ctl2g); | |
| 1317 | + cmd->conform_limit_5ghz = __cpu_to_le32(ctl5g); | |
| 1318 | 1318 | |
| 1319 | 1319 | ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set rd\n"); |
| 1320 | 1320 | return skb; |
| @@ -3136,6 +3136,76 @@ ath10k_wmi_tlv_op_gen_echo(struct ath10k *ar, u32 value) · 1815 unmodified lines | ||
| 3136 | 3136 | return skb; |
| 3137 | 3137 | } |
| 3138 | 3138 | |
| 3139 | +static struct sk_buff * | |
| 3140 | +ath10k_wmi_tlv_op_gen_vdev_spectral_conf(struct ath10k *ar, | |
| 3141 | + const struct wmi_vdev_spectral_conf_arg *arg) | |
| 3142 | +{ | |
| 3143 | + struct wmi_vdev_spectral_conf_cmd *cmd; | |
| 3144 | + struct sk_buff *skb; | |
| 3145 | + struct wmi_tlv *tlv; | |
| 3146 | + void *ptr; | |
| 3147 | + size_t len; | |
| 3148 | + | |
| 3149 | + len = sizeof(*tlv) + sizeof(*cmd); | |
| 3150 | + skb = ath10k_wmi_alloc_skb(ar, len); | |
| 3151 | + if (!skb) | |
| 3152 | + return ERR_PTR(-ENOMEM); | |
| 3153 | + | |
| 3154 | + ptr = (void *)skb->data; | |
| 3155 | + tlv = ptr; | |
| 3156 | + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_CONFIGURE_CMD); | |
| 3157 | + tlv->len = __cpu_to_le16(sizeof(*cmd)); | |
| 3158 | + cmd = (void *)tlv->value; | |
| 3159 | + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); | |
| 3160 | + cmd->scan_count = __cpu_to_le32(arg->scan_count); | |
| 3161 | + cmd->scan_period = __cpu_to_le32(arg->scan_period); | |
| 3162 | + cmd->scan_priority = __cpu_to_le32(arg->scan_priority); | |
| 3163 | + cmd->scan_fft_size = __cpu_to_le32(arg->scan_fft_size); | |
| 3164 | + cmd->scan_gc_ena = __cpu_to_le32(arg->scan_gc_ena); | |
| 3165 | + cmd->scan_restart_ena = __cpu_to_le32(arg->scan_restart_ena); | |
| 3166 | + cmd->scan_noise_floor_ref = __cpu_to_le32(arg->scan_noise_floor_ref); | |
| 3167 | + cmd->scan_init_delay = __cpu_to_le32(arg->scan_init_delay); | |
| 3168 | + cmd->scan_nb_tone_thr = __cpu_to_le32(arg->scan_nb_tone_thr); | |
| 3169 | + cmd->scan_str_bin_thr = __cpu_to_le32(arg->scan_str_bin_thr); | |
| 3170 | + cmd->scan_wb_rpt_mode = __cpu_to_le32(arg->scan_wb_rpt_mode); | |
| 3171 | + cmd->scan_rssi_rpt_mode = __cpu_to_le32(arg->scan_rssi_rpt_mode); | |
| 3172 | + cmd->scan_rssi_thr = __cpu_to_le32(arg->scan_rssi_thr); | |
| 3173 | + cmd->scan_pwr_format = __cpu_to_le32(arg->scan_pwr_format); | |
| 3174 | + cmd->scan_rpt_mode = __cpu_to_le32(arg->scan_rpt_mode); | |
| 3175 | + cmd->scan_bin_scale = __cpu_to_le32(arg->scan_bin_scale); | |
| 3176 | + cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj); | |
| 3177 | + cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask); | |
| 3178 | + | |
| 3179 | + return skb; | |
| 3180 | +} | |
| 3181 | + | |
| 3182 | +static struct sk_buff * | |
| 3183 | +ath10k_wmi_tlv_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, | |
| 3184 | + u32 trigger, u32 enable) | |
| 3185 | +{ | |
| 3186 | + struct wmi_vdev_spectral_enable_cmd *cmd; | |
| 3187 | + struct sk_buff *skb; | |
| 3188 | + struct wmi_tlv *tlv; | |
| 3189 | + void *ptr; | |
| 3190 | + size_t len; | |
| 3191 | + | |
| 3192 | + len = sizeof(*tlv) + sizeof(*cmd); | |
| 3193 | + skb = ath10k_wmi_alloc_skb(ar, len); | |
| 3194 | + if (!skb) | |
| 3195 | + return ERR_PTR(-ENOMEM); | |
| 3196 | + | |
| 3197 | + ptr = (void *)skb->data; | |
| 3198 | + tlv = ptr; | |
| 3199 | + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_ENABLE_CMD); | |
| 3200 | + tlv->len = __cpu_to_le16(sizeof(*cmd)); | |
| 3201 | + cmd = (void *)tlv->value; | |
| 3202 | + cmd->vdev_id = __cpu_to_le32(vdev_id); | |
| 3203 | + cmd->trigger_cmd = __cpu_to_le32(trigger); | |
| 3204 | + cmd->enable_cmd = __cpu_to_le32(enable); | |
| 3205 | + | |
| 3206 | + return skb; | |
| 3207 | +} | |
| 3208 | + | |
| 3139 | 3209 | /****************/ |
| 3140 | 3210 | /* TLV mappings */ |
| 3141 | 3211 | /****************/ |
| @@ -3464,7 +3534,6 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { · 322 unmodified lines | ||
| 3464 | 3534 | .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, |
| 3465 | 3535 | .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, |
| 3466 | 3536 | .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, |
| 3467 | − .set_tsf = WMI_VDEV_PARAM_UNSUPPORTED, | |
| 3468 | 3537 | }; |
| 3469 | 3538 | |
| 3470 | 3539 | static const struct wmi_ops wmi_tlv_ops = { |
| @@ -3542,6 +3611,8 @@ static const struct wmi_ops wmi_tlv_ops = { · 71 unmodified lines | ||
| 3542 | 3611 | .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, |
| 3543 | 3612 | .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, |
| 3544 | 3613 | .gen_echo = ath10k_wmi_tlv_op_gen_echo, |
| 3614 | + .gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf, | |
| 3615 | + .gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable, | |
| 3545 | 3616 | }; |
| 3546 | 3617 | |
| 3547 | 3618 | static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = { |
| @@ -785,7 +785,6 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = { · 784 unmodified lines | ||
| 785 | 785 | .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, |
| 786 | 786 | .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, |
| 787 | 787 | .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, |
| 788 | − .set_tsf = WMI_VDEV_PARAM_UNSUPPORTED, | |
| 789 | 788 | }; |
| 790 | 789 | |
| 791 | 790 | /* 10.X WMI VDEV param map */ |
| @@ -861,7 +860,6 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { · 69 unmodified lines | ||
| 861 | 860 | .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, |
| 862 | 861 | .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, |
| 863 | 862 | .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, |
| 864 | − .set_tsf = WMI_VDEV_PARAM_UNSUPPORTED, | |
| 865 | 863 | }; |
| 866 | 864 | |
| 867 | 865 | static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { |
| @@ -936,7 +934,6 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { · 68 unmodified lines | ||
| 936 | 934 | .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, |
| 937 | 935 | .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, |
| 938 | 936 | .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, |
| 939 | − .set_tsf = WMI_10X_VDEV_PARAM_TSF_INCREMENT, | |
| 940 | 937 | }; |
| 941 | 938 | |
| 942 | 939 | static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { |
| @@ -1012,7 +1009,8 @@ static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { · 69 unmodified lines | ||
| 1012 | 1009 | .meru_vc = WMI_10_4_VDEV_PARAM_MERU_VC, |
| 1013 | 1010 | .rx_decap_type = WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, |
| 1014 | 1011 | .bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, |
| 1015 | − .set_tsf = WMI_10_4_VDEV_PARAM_TSF_INCREMENT, | |
| 1012 | + .inc_tsf = WMI_10_4_VDEV_PARAM_TSF_INCREMENT, | |
| 1013 | + .dec_tsf = WMI_10_4_VDEV_PARAM_TSF_DECREMENT, | |
| 1016 | 1014 | }; |
| 1017 | 1015 | |
| 1018 | 1016 | static struct wmi_pdev_param_map wmi_pdev_param_map = { |
| @@ -4489,7 +4487,7 @@ static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id, · 3470 unmodified lines | ||
| 4489 | 4487 | if (!num_units) |
| 4490 | 4488 | return -ENOMEM; |
| 4491 | 4489 | |
| 4492 | − paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_TO_DEVICE); | |
| 4490 | + paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_BIDIRECTIONAL); | |
| 4493 | 4491 | if (dma_mapping_error(ar->dev, paddr)) { |
| 4494 | 4492 | kfree(vaddr); |
| 4495 | 4493 | return -ENOMEM; |
| @@ -4603,9 +4603,17 @@ enum wmi_rate_preamble { · 4602 unmodified lines | ||
| 4603 | 4603 | |
| 4604 | 4604 | #define ATH10K_HW_NSS(rate) (1 + (((rate) >> 4) & 0x3)) |
| 4605 | 4605 | #define ATH10K_HW_PREAMBLE(rate) (((rate) >> 6) & 0x3) |
| 4606 | −#define ATH10K_HW_RATECODE(rate, nss, preamble) \ | |
| 4606 | +#define ATH10K_HW_MCS_RATE(rate) ((rate) & 0xf) | |
| 4607 | +#define ATH10K_HW_LEGACY_RATE(rate) ((rate) & 0x3f) | |
| 4608 | +#define ATH10K_HW_BW(flags) (((flags) >> 3) & 0x3) | |
| 4609 | +#define ATH10K_HW_GI(flags) (((flags) >> 5) & 0x1) | |
| 4610 | +#define ATH10K_HW_RATECODE(rate, nss, preamble) \ | |
| 4607 | 4611 | (((preamble) << 6) | ((nss) << 4) | (rate)) |
| 4608 | 4612 | |
| 4613 | +#define VHT_MCS_NUM 10 | |
| 4614 | +#define VHT_BW_NUM 4 | |
| 4615 | +#define VHT_NSS_NUM 4 | |
| 4616 | + | |
| 4609 | 4617 | /* Value to disable fixed rate setting */ |
| 4610 | 4618 | #define WMI_FIXED_RATE_NONE (0xff) |
| 4611 | 4619 | |
| @@ -4676,7 +4684,8 @@ struct wmi_vdev_param_map { · 64 unmodified lines | ||
| 4676 | 4684 | u32 meru_vc; |
| 4677 | 4685 | u32 rx_decap_type; |
| 4678 | 4686 | u32 bw_nss_ratemask; |
| 4679 | − u32 set_tsf; | |
| 4687 | + u32 inc_tsf; | |
| 4688 | + u32 dec_tsf; | |
| 4680 | 4689 | }; |
| 4681 | 4690 | |
| 4682 | 4691 | #define WMI_VDEV_PARAM_UNSUPPORTED 0 |
| @@ -5009,6 +5018,11 @@ enum wmi_10_4_vdev_param { · 326 unmodified lines | ||
| 5009 | 5018 | WMI_10_4_VDEV_PARAM_STA_KICKOUT, |
| 5010 | 5019 | WMI_10_4_VDEV_PARAM_CAPABILITIES, |
| 5011 | 5020 | WMI_10_4_VDEV_PARAM_TSF_INCREMENT, |
| 5021 | + WMI_10_4_VDEV_PARAM_RX_FILTER, | |
| 5022 | + WMI_10_4_VDEV_PARAM_MGMT_TX_POWER, | |
| 5023 | + WMI_10_4_VDEV_PARAM_ATF_SSID_SCHED_POLICY, | |
| 5024 | + WMI_10_4_VDEV_PARAM_DISABLE_DYN_BW_RTS, | |
| 5025 | + WMI_10_4_VDEV_PARAM_TSF_DECREMENT, | |
| 5012 | 5026 | }; |
| 5013 | 5027 | |
| 5014 | 5028 | #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) |
| @@ -66,7 +66,6 @@ · 65 unmodified lines | ||
| 66 | 66 | |
| 67 | 67 | #include <linux/seq_file.h> |
| 68 | 68 | #include <linux/list.h> |
| 69 | −#include <linux/vmalloc.h> | |
| 70 | 69 | #include "debug.h" |
| 71 | 70 | #include "ath5k.h" |
| 72 | 71 | #include "reg.h" |
| @@ -62,7 +62,7 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) · 61 unmodified lines | ||
| 62 | 62 | return false; |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | −static struct ath_bus_ops ath_ahb_bus_ops = { | |
| 65 | +static const struct ath_bus_ops ath_ahb_bus_ops = { | |
| 66 | 66 | .ath_bus_type = ATH_AHB, |
| 67 | 67 | .read_cachesize = ath_ahb_read_cachesize, |
| 68 | 68 | .eeprom_read = ath_ahb_eeprom_read, |
| @@ -528,6 +528,9 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h · 527 unmodified lines | ||
| 528 | 528 | if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) |
| 529 | 529 | return 0; |
| 530 | 530 | |
| 531 | + if (!spec_priv->rfs_chan_spec_scan) | |
| 532 | + return 1; | |
| 533 | + | |
| 531 | 534 | /* Output buffers are full, no need to process anything |
| 532 | 535 | * since there is no space to put the result anyway |
| 533 | 536 | */ |
| @@ -1072,7 +1075,7 @@ static struct rchan_callbacks rfs_spec_scan_cb = { · 538 unmodified lines | ||
| 1072 | 1075 | |
| 1073 | 1076 | void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv) |
| 1074 | 1077 | { |
| 1075 | − if (IS_ENABLED(CONFIG_ATH9K_DEBUGFS)) { | |
| 1078 | + if (IS_ENABLED(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) { | |
| 1076 | 1079 | relay_close(spec_priv->rfs_chan_spec_scan); |
| 1077 | 1080 | spec_priv->rfs_chan_spec_scan = NULL; |
| 1078 | 1081 | } |
| @@ -1086,6 +1089,9 @@ void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, · 7 unmodified lines | ||
| 1086 | 1089 | debugfs_phy, |
| 1087 | 1090 | 1024, 256, &rfs_spec_scan_cb, |
| 1088 | 1091 | NULL); |
| 1092 | + if (!spec_priv->rfs_chan_spec_scan) | |
| 1093 | + return; | |
| 1094 | + | |
| 1089 | 1095 | debugfs_create_file("spectral_scan_ctl", |
| 1090 | 1096 | S_IRUSR | S_IWUSR, |
| 1091 | 1097 | debugfs_phy, spec_priv, |
| @@ -997,7 +997,8 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) · 996 unmodified lines | ||
| 997 | 997 | err = usb_control_msg(hif_dev->udev, |
| 998 | 998 | usb_sndctrlpipe(hif_dev->udev, 0), |
| 999 | 999 | FIRMWARE_DOWNLOAD, 0x40 | USB_DIR_OUT, |
| 1000 | − addr >> 8, 0, buf, transfer, HZ); | |
| 1000 | + addr >> 8, 0, buf, transfer, | |
| 1001 | + USB_MSG_TIMEOUT); | |
| 1001 | 1002 | if (err < 0) { |
| 1002 | 1003 | kfree(buf); |
| 1003 | 1004 | return err; |
| @@ -1020,7 +1021,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) · 16 unmodified lines | ||
| 1020 | 1021 | err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0), |
| 1021 | 1022 | FIRMWARE_DOWNLOAD_COMP, |
| 1022 | 1023 | 0x40 | USB_DIR_OUT, |
| 1023 | − firm_offset >> 8, 0, NULL, 0, HZ); | |
| 1024 | + firm_offset >> 8, 0, NULL, 0, USB_MSG_TIMEOUT); | |
| 1024 | 1025 | if (err) |
| 1025 | 1026 | return -EIO; |
| 1026 | 1027 | |
| @@ -1249,7 +1250,7 @@ static int send_eject_command(struct usb_interface *interface) · 222 unmodified lines | ||
| 1249 | 1250 | |
| 1250 | 1251 | dev_info(&udev->dev, "Ejecting storage device...\n"); |
| 1251 | 1252 | r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep), |
| 1252 | − cmd, 31, NULL, 2000); | |
| 1253 | + cmd, 31, NULL, 2 * USB_MSG_TIMEOUT); | |
| 1253 | 1254 | kfree(cmd); |
| 1254 | 1255 | if (r) |
| 1255 | 1256 | return r; |
| @@ -1314,7 +1315,7 @@ static void ath9k_hif_usb_reboot(struct usb_device *udev) · 58 unmodified lines | ||
| 1314 | 1315 | return; |
| 1315 | 1316 | |
| 1316 | 1317 | ret = usb_interrupt_msg(udev, usb_sndintpipe(udev, USB_REG_OUT_PIPE), |
| 1317 | − buf, 4, NULL, HZ); | |
| 1318 | + buf, 4, NULL, USB_MSG_TIMEOUT); | |
| 1318 | 1319 | if (ret) |
| 1319 | 1320 | dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n"); |
| 1320 | 1321 | |
| @@ -71,6 +71,8 @@ extern int htc_use_dev_fw; · 70 unmodified lines | ||
| 71 | 71 | #define USB_REG_IN_PIPE 3 |
| 72 | 72 | #define USB_REG_OUT_PIPE 4 |
| 73 | 73 | |
| 74 | +#define USB_MSG_TIMEOUT 1000 /* (ms) */ | |
| 75 | + | |
| 74 | 76 | #define HIF_USB_MAX_RXPIPES 2 |
| 75 | 77 | #define HIF_USB_MAX_TXPIPES 4 |
| 76 | 78 | |
| @@ -2792,7 +2792,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) · 2791 unmodified lines | ||
| 2792 | 2792 | WARN_ON(1); |
| 2793 | 2793 | } |
| 2794 | 2794 | |
| 2795 | − return val; | |
| 2795 | + return !!val; | |
| 2796 | 2796 | } |
| 2797 | 2797 | EXPORT_SYMBOL(ath9k_hw_gpio_get); |
| 2798 | 2798 | |
| @@ -867,10 +867,21 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, · 866 unmodified lines | ||
| 867 | 867 | * can be dropped. |
| 868 | 868 | */ |
| 869 | 869 | if (rx_stats->rs_status & ATH9K_RXERR_PHY) { |
| 870 | − ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime); | |
| 871 | − if (ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats, rx_status->mactime)) | |
| 870 | + /* | |
| 871 | + * DFS and spectral are mutually exclusive | |
| 872 | + * | |
| 873 | + * Since some chips use PHYERR_RADAR as indication for both, we | |
| 874 | + * need to double check which feature is enabled to prevent | |
| 875 | + * feeding spectral or dfs-detector with wrong frames. | |
| 876 | + */ | |
| 877 | + if (hw->conf.radar_enabled) { | |
| 878 | + ath9k_dfs_process_phyerr(sc, hdr, rx_stats, | |
| 879 | + rx_status->mactime); | |
| 880 | + } else if (sc->spec_priv.spectral_mode != SPECTRAL_DISABLED && | |
| 881 | + ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats, | |
| 882 | + rx_status->mactime)) { | |
| 872 | 883 | RX_STAT_INC(rx_spectral); |
| 873 | − | |
| 884 | + } | |
| 874 | 885 | return -EINVAL; |
| 875 | 886 | } |
| 876 | 887 | |
| @@ -354,14 +354,6 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, · 353 unmodified lines | ||
| 354 | 354 | wil_dbg_misc(wil, "%s(), wdev=0x%p iftype=%d\n", |
| 355 | 355 | __func__, wdev, wdev->iftype); |
| 356 | 356 | |
| 357 | − mutex_lock(&wil->p2p_wdev_mutex); | |
| 358 | − if (wil->scan_request) { | |
| 359 | − wil_err(wil, "Already scanning\n"); | |
| 360 | − mutex_unlock(&wil->p2p_wdev_mutex); | |
| 361 | − return -EAGAIN; | |
| 362 | − } | |
| 363 | − mutex_unlock(&wil->p2p_wdev_mutex); | |
| 364 | − | |
| 365 | 357 | /* check we are client side */ |
| 366 | 358 | switch (wdev->iftype) { |
| 367 | 359 | case NL80211_IFTYPE_STATION: |
| @@ -378,12 +370,24 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, · 10 unmodified lines | ||
| 378 | 370 | return -EBUSY; |
| 379 | 371 | } |
| 380 | 372 | |
| 373 | + mutex_lock(&wil->mutex); | |
| 374 | + | |
| 375 | + mutex_lock(&wil->p2p_wdev_mutex); | |
| 376 | + if (wil->scan_request || wil->p2p.discovery_started) { | |
| 377 | + wil_err(wil, "Already scanning\n"); | |
| 378 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 379 | + rc = -EAGAIN; | |
| 380 | + goto out; | |
| 381 | + } | |
| 382 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 383 | + | |
| 381 | 384 | /* social scan on P2P_DEVICE is handled as p2p search */ |
| 382 | 385 | if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE && |
| 383 | 386 | wil_p2p_is_social_scan(request)) { |
| 384 | 387 | if (!wil->p2p.p2p_dev_started) { |
| 385 | 388 | wil_err(wil, "P2P search requested on stopped P2P device\n"); |
| 386 | − return -EIO; | |
| 389 | + rc = -EIO; | |
| 390 | + goto out; | |
| 387 | 391 | } |
| 388 | 392 | wil->scan_request = request; |
| 389 | 393 | wil->radio_wdev = wdev; |
| @@ -392,7 +396,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, · 2 unmodified lines | ||
| 392 | 396 | wil->radio_wdev = wil_to_wdev(wil); |
| 393 | 397 | wil->scan_request = NULL; |
| 394 | 398 | } |
| 395 | − return rc; | |
| 399 | + goto out; | |
| 396 | 400 | } |
| 397 | 401 | |
| 398 | 402 | (void)wil_p2p_stop_discovery(wil); |
| @@ -415,7 +419,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, · 16 unmodified lines | ||
| 415 | 419 | |
| 416 | 420 | if (rc) { |
| 417 | 421 | wil_err(wil, "set SSID for scan request failed: %d\n", rc); |
| 418 | − return rc; | |
| 422 | + goto out; | |
| 419 | 423 | } |
| 420 | 424 | |
| 421 | 425 | wil->scan_request = request; |
| @@ -448,7 +452,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, · 26 unmodified lines | ||
| 448 | 452 | |
| 449 | 453 | rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); |
| 450 | 454 | if (rc) |
| 451 | − goto out; | |
| 455 | + goto out_restore; | |
| 452 | 456 | |
| 453 | 457 | if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) { |
| 454 | 458 | cmd.cmd.discovery_mode = 1; |
| @@ -459,16 +463,45 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, · 4 unmodified lines | ||
| 459 | 463 | rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + |
| 460 | 464 | cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); |
| 461 | 465 | |
| 462 | −out: | |
| 466 | +out_restore: | |
| 463 | 467 | if (rc) { |
| 464 | 468 | del_timer_sync(&wil->scan_timer); |
| 465 | 469 | wil->radio_wdev = wil_to_wdev(wil); |
| 466 | 470 | wil->scan_request = NULL; |
| 467 | 471 | } |
| 468 | − | |
| 472 | +out: | |
| 473 | + mutex_unlock(&wil->mutex); | |
| 469 | 474 | return rc; |
| 470 | 475 | } |
| 471 | 476 | |
| 477 | +static void wil_cfg80211_abort_scan(struct wiphy *wiphy, | |
| 478 | + struct wireless_dev *wdev) | |
| 479 | +{ | |
| 480 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 481 | + | |
| 482 | + wil_dbg_misc(wil, "wdev=0x%p iftype=%d\n", wdev, wdev->iftype); | |
| 483 | + | |
| 484 | + mutex_lock(&wil->mutex); | |
| 485 | + mutex_lock(&wil->p2p_wdev_mutex); | |
| 486 | + | |
| 487 | + if (!wil->scan_request) | |
| 488 | + goto out; | |
| 489 | + | |
| 490 | + if (wdev != wil->scan_request->wdev) { | |
| 491 | + wil_dbg_misc(wil, "abort scan was called on the wrong iface\n"); | |
| 492 | + goto out; | |
| 493 | + } | |
| 494 | + | |
| 495 | + if (wil->radio_wdev == wil->p2p_wdev) | |
| 496 | + wil_p2p_stop_radio_operations(wil); | |
| 497 | + else | |
| 498 | + wil_abort_scan(wil, true); | |
| 499 | + | |
| 500 | +out: | |
| 501 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 502 | + mutex_unlock(&wil->mutex); | |
| 503 | +} | |
| 504 | + | |
| 472 | 505 | static void wil_print_crypto(struct wil6210_priv *wil, |
| 473 | 506 | struct cfg80211_crypto_settings *c) |
| 474 | 507 | { |
| @@ -674,6 +707,26 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, · 199 unmodified lines | ||
| 674 | 707 | return rc; |
| 675 | 708 | } |
| 676 | 709 | |
| 710 | +static int wil_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |
| 711 | +{ | |
| 712 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 713 | + int rc; | |
| 714 | + | |
| 715 | + /* these parameters are explicitly not supported */ | |
| 716 | + if (changed & (WIPHY_PARAM_RETRY_LONG | | |
| 717 | + WIPHY_PARAM_FRAG_THRESHOLD | | |
| 718 | + WIPHY_PARAM_RTS_THRESHOLD)) | |
| 719 | + return -ENOTSUPP; | |
| 720 | + | |
| 721 | + if (changed & WIPHY_PARAM_RETRY_SHORT) { | |
| 722 | + rc = wmi_set_mgmt_retry(wil, wiphy->retry_short); | |
| 723 | + if (rc) | |
| 724 | + return rc; | |
| 725 | + } | |
| 726 | + | |
| 727 | + return 0; | |
| 728 | +} | |
| 729 | + | |
| 677 | 730 | int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 678 | 731 | struct cfg80211_mgmt_tx_params *params, |
| 679 | 732 | u64 *cookie) |
| @@ -940,16 +993,8 @@ static int wil_remain_on_channel(struct wiphy *wiphy, · 260 unmodified lines | ||
| 940 | 993 | wil_dbg_misc(wil, "%s() center_freq=%d, duration=%d iftype=%d\n", |
| 941 | 994 | __func__, chan->center_freq, duration, wdev->iftype); |
| 942 | 995 | |
| 943 | − rc = wil_p2p_listen(wil, duration, chan, cookie); | |
| 944 | − if (rc) | |
| 945 | − return rc; | |
| 946 | − | |
| 947 | − wil->radio_wdev = wdev; | |
| 948 | − | |
| 949 | − cfg80211_ready_on_channel(wdev, *cookie, chan, duration, | |
| 950 | − GFP_KERNEL); | |
| 951 | − | |
| 952 | − return 0; | |
| 996 | + rc = wil_p2p_listen(wil, wdev, duration, chan, cookie); | |
| 997 | + return rc; | |
| 953 | 998 | } |
| 954 | 999 | |
| 955 | 1000 | static int wil_cancel_remain_on_channel(struct wiphy *wiphy, |
| @@ -1419,17 +1464,49 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy, · 463 unmodified lines | ||
| 1419 | 1464 | |
| 1420 | 1465 | wil_dbg_misc(wil, "%s: entered\n", __func__); |
| 1421 | 1466 | mutex_lock(&wil->mutex); |
| 1467 | + mutex_lock(&wil->p2p_wdev_mutex); | |
| 1422 | 1468 | wil_p2p_stop_radio_operations(wil); |
| 1423 | 1469 | p2p->p2p_dev_started = 0; |
| 1470 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 1424 | 1471 | mutex_unlock(&wil->mutex); |
| 1425 | 1472 | } |
| 1426 | 1473 | |
| 1474 | +static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, | |
| 1475 | + struct net_device *dev, | |
| 1476 | + bool enabled, int timeout) | |
| 1477 | +{ | |
| 1478 | + struct wil6210_priv *wil = wiphy_to_wil(wiphy); | |
| 1479 | + enum wmi_ps_profile_type ps_profile; | |
| 1480 | + int rc; | |
| 1481 | + | |
| 1482 | + if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) { | |
| 1483 | + wil_err(wil, "set_power_mgmt not supported\n"); | |
| 1484 | + return -EOPNOTSUPP; | |
| 1485 | + } | |
| 1486 | + | |
| 1487 | + wil_dbg_misc(wil, "enabled=%d, timeout=%d\n", | |
| 1488 | + enabled, timeout); | |
| 1489 | + | |
| 1490 | + if (enabled) | |
| 1491 | + ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT; | |
| 1492 | + else | |
| 1493 | + ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED; | |
| 1494 | + | |
| 1495 | + rc = wmi_ps_dev_profile_cfg(wil, ps_profile); | |
| 1496 | + if (rc) | |
| 1497 | + wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc); | |
| 1498 | + | |
| 1499 | + return rc; | |
| 1500 | +} | |
| 1501 | + | |
| 1427 | 1502 | static struct cfg80211_ops wil_cfg80211_ops = { |
| 1428 | 1503 | .add_virtual_intf = wil_cfg80211_add_iface, |
| 1429 | 1504 | .del_virtual_intf = wil_cfg80211_del_iface, |
| 1430 | 1505 | .scan = wil_cfg80211_scan, |
| 1506 | + .abort_scan = wil_cfg80211_abort_scan, | |
| 1431 | 1507 | .connect = wil_cfg80211_connect, |
| 1432 | 1508 | .disconnect = wil_cfg80211_disconnect, |
| 1509 | + .set_wiphy_params = wil_cfg80211_set_wiphy_params, | |
| 1433 | 1510 | .change_virtual_intf = wil_cfg80211_change_iface, |
| 1434 | 1511 | .get_station = wil_cfg80211_get_station, |
| 1435 | 1512 | .dump_station = wil_cfg80211_dump_station, |
| @@ -1450,6 +1527,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { · 14 unmodified lines | ||
| 1450 | 1527 | /* P2P device */ |
| 1451 | 1528 | .start_p2p_device = wil_cfg80211_start_p2p_device, |
| 1452 | 1529 | .stop_p2p_device = wil_cfg80211_stop_p2p_device, |
| 1530 | + .set_power_mgmt = wil_cfg80211_set_power_mgmt, | |
| 1453 | 1531 | }; |
| 1454 | 1532 | |
| 1455 | 1533 | static void wil_wiphy_init(struct wiphy *wiphy) |
| @@ -1466,7 +1544,8 @@ static void wil_wiphy_init(struct wiphy *wiphy) · 10 unmodified lines | ||
| 1466 | 1544 | BIT(NL80211_IFTYPE_MONITOR); |
| 1467 | 1545 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | |
| 1468 | 1546 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | |
| 1469 | − WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | |
| 1547 | + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | | |
| 1548 | + WIPHY_FLAG_PS_ON_BY_DEFAULT; | |
| 1470 | 1549 | dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n", |
| 1471 | 1550 | __func__, wiphy->flags); |
| 1472 | 1551 | wiphy->probe_resp_offload = |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #include "boot_loader.h" |
| 25 | 25 | |
| 26 | 26 | #define WAIT_FOR_HALP_VOTE_MS 100 |
| 27 | +#define WAIT_FOR_SCAN_ABORT_MS 1000 | |
| 27 | 28 | |
| 28 | 29 | bool debug_fw; /* = false; */ |
| 29 | 30 | module_param(debug_fw, bool, S_IRUGO); |
| @@ -213,7 +214,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) · 183 unmodified lines | ||
| 213 | 214 | memset(&sta->stats, 0, sizeof(sta->stats)); |
| 214 | 215 | } |
| 215 | 216 | |
| 216 | −static bool wil_ap_is_connected(struct wil6210_priv *wil) | |
| 217 | +static bool wil_is_connected(struct wil6210_priv *wil) | |
| 217 | 218 | { |
| 218 | 219 | int i; |
| 219 | 220 | |
| @@ -267,7 +268,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, · 47 unmodified lines | ||
| 267 | 268 | case NL80211_IFTYPE_STATION: |
| 268 | 269 | case NL80211_IFTYPE_P2P_CLIENT: |
| 269 | 270 | wil_bcast_fini(wil); |
| 270 | − netif_tx_stop_all_queues(ndev); | |
| 271 | + wil_update_net_queues_bh(wil, NULL, true); | |
| 271 | 272 | netif_carrier_off(ndev); |
| 272 | 273 | |
| 273 | 274 | if (test_bit(wil_status_fwconnected, wil->status)) { |
| @@ -283,8 +284,12 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, · 9 unmodified lines | ||
| 283 | 284 | break; |
| 284 | 285 | case NL80211_IFTYPE_AP: |
| 285 | 286 | case NL80211_IFTYPE_P2P_GO: |
| 286 | − if (!wil_ap_is_connected(wil)) | |
| 287 | + if (!wil_is_connected(wil)) { | |
| 288 | + wil_update_net_queues_bh(wil, NULL, true); | |
| 287 | 289 | clear_bit(wil_status_fwconnected, wil->status); |
| 290 | + } else { | |
| 291 | + wil_update_net_queues_bh(wil, NULL, false); | |
| 292 | + } | |
| 288 | 293 | break; |
| 289 | 294 | default: |
| 290 | 295 | break; |
| @@ -384,18 +389,19 @@ static void wil_fw_error_worker(struct work_struct *work) · 93 unmodified lines | ||
| 384 | 389 | |
| 385 | 390 | wil->last_fw_recovery = jiffies; |
| 386 | 391 | |
| 392 | + wil_info(wil, "fw error recovery requested (try %d)...\n", | |
| 393 | + wil->recovery_count); | |
| 394 | + if (!no_fw_recovery) | |
| 395 | + wil->recovery_state = fw_recovery_running; | |
| 396 | + if (wil_wait_for_recovery(wil) != 0) | |
| 397 | + return; | |
| 398 | + | |
| 387 | 399 | mutex_lock(&wil->mutex); |
| 388 | 400 | switch (wdev->iftype) { |
| 389 | 401 | case NL80211_IFTYPE_STATION: |
| 390 | 402 | case NL80211_IFTYPE_P2P_CLIENT: |
| 391 | 403 | case NL80211_IFTYPE_MONITOR: |
| 392 | − wil_info(wil, "fw error recovery requested (try %d)...\n", | |
| 393 | − wil->recovery_count); | |
| 394 | − if (!no_fw_recovery) | |
| 395 | − wil->recovery_state = fw_recovery_running; | |
| 396 | − if (0 != wil_wait_for_recovery(wil)) | |
| 397 | − break; | |
| 398 | − | |
| 404 | + /* silent recovery, upper layers will see disconnect */ | |
| 399 | 405 | __wil_down(wil); |
| 400 | 406 | __wil_up(wil); |
| 401 | 407 | break; |
| @@ -512,10 +518,13 @@ int wil_priv_init(struct wil6210_priv *wil) · 110 unmodified lines | ||
| 512 | 518 | INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); |
| 513 | 519 | INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); |
| 514 | 520 | INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); |
| 521 | + INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work); | |
| 515 | 522 | |
| 516 | 523 | INIT_LIST_HEAD(&wil->pending_wmi_ev); |
| 517 | 524 | INIT_LIST_HEAD(&wil->probe_client_pending); |
| 518 | 525 | spin_lock_init(&wil->wmi_ev_lock); |
| 526 | + spin_lock_init(&wil->net_queue_lock); | |
| 527 | + wil->net_queue_stopped = 1; | |
| 519 | 528 | init_waitqueue_head(&wil->wq); |
| 520 | 529 | |
| 521 | 530 | wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); |
| @@ -571,6 +580,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) · 49 unmodified lines | ||
| 571 | 580 | cancel_work_sync(&wil->disconnect_worker); |
| 572 | 581 | cancel_work_sync(&wil->fw_error_worker); |
| 573 | 582 | cancel_work_sync(&wil->p2p.discovery_expired_work); |
| 583 | + cancel_work_sync(&wil->p2p.delayed_listen_work); | |
| 574 | 584 | mutex_lock(&wil->mutex); |
| 575 | 585 | wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); |
| 576 | 586 | mutex_unlock(&wil->mutex); |
| @@ -685,6 +695,19 @@ static int wil_target_reset(struct wil6210_priv *wil) · 108 unmodified lines | ||
| 685 | 695 | return 0; |
| 686 | 696 | } |
| 687 | 697 | |
| 698 | +static void wil_collect_fw_info(struct wil6210_priv *wil) | |
| 699 | +{ | |
| 700 | + struct wiphy *wiphy = wil_to_wiphy(wil); | |
| 701 | + u8 retry_short; | |
| 702 | + int rc; | |
| 703 | + | |
| 704 | + rc = wmi_get_mgmt_retry(wil, &retry_short); | |
| 705 | + if (!rc) { | |
| 706 | + wiphy->retry_short = retry_short; | |
| 707 | + wil_dbg_misc(wil, "FW retry_short: %d\n", retry_short); | |
| 708 | + } | |
| 709 | +} | |
| 710 | + | |
| 688 | 711 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) |
| 689 | 712 | { |
| 690 | 713 | le32_to_cpus(&r->base); |
| @@ -801,6 +824,34 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) · 110 unmodified lines | ||
| 801 | 824 | return 0; |
| 802 | 825 | } |
| 803 | 826 | |
| 827 | +void wil_abort_scan(struct wil6210_priv *wil, bool sync) | |
| 828 | +{ | |
| 829 | + int rc; | |
| 830 | + struct cfg80211_scan_info info = { | |
| 831 | + .aborted = true, | |
| 832 | + }; | |
| 833 | + | |
| 834 | + lockdep_assert_held(&wil->p2p_wdev_mutex); | |
| 835 | + | |
| 836 | + if (!wil->scan_request) | |
| 837 | + return; | |
| 838 | + | |
| 839 | + wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request); | |
| 840 | + del_timer_sync(&wil->scan_timer); | |
| 841 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 842 | + rc = wmi_abort_scan(wil); | |
| 843 | + if (!rc && sync) | |
| 844 | + wait_event_interruptible_timeout(wil->wq, !wil->scan_request, | |
| 845 | + msecs_to_jiffies( | |
| 846 | + WAIT_FOR_SCAN_ABORT_MS)); | |
| 847 | + | |
| 848 | + mutex_lock(&wil->p2p_wdev_mutex); | |
| 849 | + if (wil->scan_request) { | |
| 850 | + cfg80211_scan_done(wil->scan_request, &info); | |
| 851 | + wil->scan_request = NULL; | |
| 852 | + } | |
| 853 | +} | |
| 854 | + | |
| 804 | 855 | /* |
| 805 | 856 | * We reset all the structures, and we reset the UMAC. |
| 806 | 857 | * After calling this routine, you're expected to reload |
| @@ -853,17 +904,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) · 46 unmodified lines | ||
| 853 | 904 | mutex_unlock(&wil->wmi_mutex); |
| 854 | 905 | |
| 855 | 906 | mutex_lock(&wil->p2p_wdev_mutex); |
| 856 | − if (wil->scan_request) { | |
| 857 | − struct cfg80211_scan_info info = { | |
| 858 | − .aborted = true, | |
| 859 | − }; | |
| 860 | − | |
| 861 | − wil_dbg_misc(wil, "Abort scan_request 0x%p\n", | |
| 862 | − wil->scan_request); | |
| 863 | − del_timer_sync(&wil->scan_timer); | |
| 864 | − cfg80211_scan_done(wil->scan_request, &info); | |
| 865 | − wil->scan_request = NULL; | |
| 866 | − } | |
| 907 | + wil_abort_scan(wil, false); | |
| 867 | 908 | mutex_unlock(&wil->p2p_wdev_mutex); |
| 868 | 909 | |
| 869 | 910 | wil_mask_irq(wil); |
| @@ -940,6 +981,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) · 70 unmodified lines | ||
| 940 | 981 | return rc; |
| 941 | 982 | } |
| 942 | 983 | |
| 984 | + wil_collect_fw_info(wil); | |
| 985 | + | |
| 943 | 986 | if (wil->platform_ops.notify) { |
| 944 | 987 | rc = wil->platform_ops.notify(wil->platform_handle, |
| 945 | 988 | WIL_PLATFORM_EVT_FW_RDY); |
| @@ -1056,20 +1099,9 @@ int __wil_down(struct wil6210_priv *wil) · 110 unmodified lines | ||
| 1056 | 1099 | } |
| 1057 | 1100 | wil_enable_irq(wil); |
| 1058 | 1101 | |
| 1059 | − wil_p2p_stop_radio_operations(wil); | |
| 1060 | − | |
| 1061 | 1102 | mutex_lock(&wil->p2p_wdev_mutex); |
| 1062 | − if (wil->scan_request) { | |
| 1063 | − struct cfg80211_scan_info info = { | |
| 1064 | − .aborted = true, | |
| 1065 | − }; | |
| 1066 | − | |
| 1067 | − wil_dbg_misc(wil, "Abort scan_request 0x%p\n", | |
| 1068 | − wil->scan_request); | |
| 1069 | − del_timer_sync(&wil->scan_timer); | |
| 1070 | − cfg80211_scan_done(wil->scan_request, &info); | |
| 1071 | − wil->scan_request = NULL; | |
| 1072 | − } | |
| 1103 | + wil_p2p_stop_radio_operations(wil); | |
| 1104 | + wil_abort_scan(wil, false); | |
| 1073 | 1105 | mutex_unlock(&wil->p2p_wdev_mutex); |
| 1074 | 1106 | |
| 1075 | 1107 | wil_reset(wil, false); |
| @@ -214,7 +214,7 @@ int wil_if_add(struct wil6210_priv *wil) · 213 unmodified lines | ||
| 214 | 214 | netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, |
| 215 | 215 | WIL6210_NAPI_BUDGET); |
| 216 | 216 | |
| 217 | − netif_tx_stop_all_queues(ndev); | |
| 217 | + wil_update_net_queues_bh(wil, NULL, true); | |
| 218 | 218 | |
| 219 | 219 | rc = register_netdev(ndev); |
| 220 | 220 | if (rc < 0) { |
| @@ -22,6 +22,43 @@ · 21 unmodified lines | ||
| 22 | 22 | #define P2P_SEARCH_DURATION_MS 500 |
| 23 | 23 | #define P2P_DEFAULT_BI 100 |
| 24 | 24 | |
| 25 | +static int wil_p2p_start_listen(struct wil6210_priv *wil) | |
| 26 | +{ | |
| 27 | + struct wil_p2p_info *p2p = &wil->p2p; | |
| 28 | + u8 channel = p2p->listen_chan.hw_value; | |
| 29 | + int rc; | |
| 30 | + | |
| 31 | + lockdep_assert_held(&wil->mutex); | |
| 32 | + | |
| 33 | + rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI); | |
| 34 | + if (rc) { | |
| 35 | + wil_err(wil, "wmi_p2p_cfg failed\n"); | |
| 36 | + goto out; | |
| 37 | + } | |
| 38 | + | |
| 39 | + rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); | |
| 40 | + if (rc) { | |
| 41 | + wil_err(wil, "wmi_set_ssid failed\n"); | |
| 42 | + goto out_stop; | |
| 43 | + } | |
| 44 | + | |
| 45 | + rc = wmi_start_listen(wil); | |
| 46 | + if (rc) { | |
| 47 | + wil_err(wil, "wmi_start_listen failed\n"); | |
| 48 | + goto out_stop; | |
| 49 | + } | |
| 50 | + | |
| 51 | + INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired); | |
| 52 | + mod_timer(&p2p->discovery_timer, | |
| 53 | + jiffies + msecs_to_jiffies(p2p->listen_duration)); | |
| 54 | +out_stop: | |
| 55 | + if (rc) | |
| 56 | + wmi_stop_discovery(wil); | |
| 57 | + | |
| 58 | +out: | |
| 59 | + return rc; | |
| 60 | +} | |
| 61 | + | |
| 25 | 62 | bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request) |
| 26 | 63 | { |
| 27 | 64 | return (request->n_channels == 1) && |
| @@ -46,7 +83,7 @@ int wil_p2p_search(struct wil6210_priv *wil, · 18 unmodified lines | ||
| 46 | 83 | wil_dbg_misc(wil, "%s: channel %d\n", |
| 47 | 84 | __func__, P2P_DMG_SOCIAL_CHANNEL); |
| 48 | 85 | |
| 49 | − mutex_lock(&wil->mutex); | |
| 86 | + lockdep_assert_held(&wil->mutex); | |
| 50 | 87 | |
| 51 | 88 | if (p2p->discovery_started) { |
| 52 | 89 | wil_err(wil, "%s: search failed. discovery already ongoing\n", |
| @@ -103,22 +140,19 @@ out_stop: · 50 unmodified lines | ||
| 103 | 140 | wmi_stop_discovery(wil); |
| 104 | 141 | |
| 105 | 142 | out: |
| 106 | − mutex_unlock(&wil->mutex); | |
| 107 | 143 | return rc; |
| 108 | 144 | } |
| 109 | 145 | |
| 110 | −int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, | |
| 111 | − struct ieee80211_channel *chan, u64 *cookie) | |
| 146 | +int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, | |
| 147 | + unsigned int duration, struct ieee80211_channel *chan, | |
| 148 | + u64 *cookie) | |
| 112 | 149 | { |
| 113 | 150 | struct wil_p2p_info *p2p = &wil->p2p; |
| 114 | − u8 channel = P2P_DMG_SOCIAL_CHANNEL; | |
| 115 | 151 | int rc; |
| 116 | 152 | |
| 117 | 153 | if (!chan) |
| 118 | 154 | return -EINVAL; |
| 119 | 155 | |
| 120 | − channel = chan->hw_value; | |
| 121 | − | |
| 122 | 156 | wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration); |
| 123 | 157 | |
| 124 | 158 | mutex_lock(&wil->mutex); |
| @@ -129,35 +163,30 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, · 4 unmodified lines | ||
| 129 | 163 | goto out; |
| 130 | 164 | } |
| 131 | 165 | |
| 132 | − rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI); | |
| 133 | − if (rc) { | |
| 134 | − wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__); | |
| 135 | − goto out; | |
| 136 | − } | |
| 137 | − | |
| 138 | − rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); | |
| 139 | − if (rc) { | |
| 140 | − wil_err(wil, "%s: wmi_set_ssid failed\n", __func__); | |
| 141 | − goto out_stop; | |
| 142 | − } | |
| 166 | + memcpy(&p2p->listen_chan, chan, sizeof(*chan)); | |
| 167 | + *cookie = ++p2p->cookie; | |
| 168 | + p2p->listen_duration = duration; | |
| 143 | 169 | |
| 144 | − rc = wmi_start_listen(wil); | |
| 145 | − if (rc) { | |
| 146 | − wil_err(wil, "%s: wmi_start_listen failed\n", __func__); | |
| 147 | − goto out_stop; | |
| 170 | + mutex_lock(&wil->p2p_wdev_mutex); | |
| 171 | + if (wil->scan_request) { | |
| 172 | + wil_dbg_misc(wil, "Delaying p2p listen until scan done\n"); | |
| 173 | + p2p->pending_listen_wdev = wdev; | |
| 174 | + p2p->discovery_started = 1; | |
| 175 | + rc = 0; | |
| 176 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 177 | + goto out; | |
| 148 | 178 | } |
| 179 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 149 | 180 | |
| 150 | − memcpy(&p2p->listen_chan, chan, sizeof(*chan)); | |
| 151 | − *cookie = ++p2p->cookie; | |
| 181 | + rc = wil_p2p_start_listen(wil); | |
| 182 | + if (rc) | |
| 183 | + goto out; | |
| 152 | 184 | |
| 153 | 185 | p2p->discovery_started = 1; |
| 154 | − INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired); | |
| 155 | − mod_timer(&p2p->discovery_timer, | |
| 156 | − jiffies + msecs_to_jiffies(duration)); | |
| 186 | + wil->radio_wdev = wdev; | |
| 157 | 187 | |
| 158 | −out_stop: | |
| 159 | − if (rc) | |
| 160 | − wmi_stop_discovery(wil); | |
| 188 | + cfg80211_ready_on_channel(wdev, *cookie, chan, duration, | |
| 189 | + GFP_KERNEL); | |
| 161 | 190 | |
| 162 | 191 | out: |
| 163 | 192 | mutex_unlock(&wil->mutex); |
| @@ -170,9 +199,14 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil) · 6 unmodified lines | ||
| 170 | 199 | u8 started = p2p->discovery_started; |
| 171 | 200 | |
| 172 | 201 | if (p2p->discovery_started) { |
| 173 | − del_timer_sync(&p2p->discovery_timer); | |
| 202 | + if (p2p->pending_listen_wdev) { | |
| 203 | + /* discovery not really started, only pending */ | |
| 204 | + p2p->pending_listen_wdev = NULL; | |
| 205 | + } else { | |
| 206 | + del_timer_sync(&p2p->discovery_timer); | |
| 207 | + wmi_stop_discovery(wil); | |
| 208 | + } | |
| 174 | 209 | p2p->discovery_started = 0; |
| 175 | − wmi_stop_discovery(wil); | |
| 176 | 210 | } |
| 177 | 211 | |
| 178 | 212 | return started; |
| @@ -257,13 +291,59 @@ void wil_p2p_search_expired(struct work_struct *work) · 78 unmodified lines | ||
| 257 | 291 | }; |
| 258 | 292 | |
| 259 | 293 | mutex_lock(&wil->p2p_wdev_mutex); |
| 260 | − cfg80211_scan_done(wil->scan_request, &info); | |
| 261 | − wil->scan_request = NULL; | |
| 262 | − wil->radio_wdev = wil->wdev; | |
| 294 | + if (wil->scan_request) { | |
| 295 | + cfg80211_scan_done(wil->scan_request, &info); | |
| 296 | + wil->scan_request = NULL; | |
| 297 | + wil->radio_wdev = wil->wdev; | |
| 298 | + } | |
| 263 | 299 | mutex_unlock(&wil->p2p_wdev_mutex); |
| 264 | 300 | } |
| 265 | 301 | } |
| 266 | 302 | |
| 303 | +void wil_p2p_delayed_listen_work(struct work_struct *work) | |
| 304 | +{ | |
| 305 | + struct wil_p2p_info *p2p = container_of(work, | |
| 306 | + struct wil_p2p_info, delayed_listen_work); | |
| 307 | + struct wil6210_priv *wil = container_of(p2p, | |
| 308 | + struct wil6210_priv, p2p); | |
| 309 | + int rc; | |
| 310 | + | |
| 311 | + mutex_lock(&wil->mutex); | |
| 312 | + | |
| 313 | + wil_dbg_misc(wil, "Checking delayed p2p listen\n"); | |
| 314 | + if (!p2p->discovery_started || !p2p->pending_listen_wdev) | |
| 315 | + goto out; | |
| 316 | + | |
| 317 | + mutex_lock(&wil->p2p_wdev_mutex); | |
| 318 | + if (wil->scan_request) { | |
| 319 | + /* another scan started, wait again... */ | |
| 320 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 321 | + goto out; | |
| 322 | + } | |
| 323 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 324 | + | |
| 325 | + rc = wil_p2p_start_listen(wil); | |
| 326 | + | |
| 327 | + mutex_lock(&wil->p2p_wdev_mutex); | |
| 328 | + if (rc) { | |
| 329 | + cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev, | |
| 330 | + p2p->cookie, | |
| 331 | + &p2p->listen_chan, | |
| 332 | + GFP_KERNEL); | |
| 333 | + wil->radio_wdev = wil->wdev; | |
| 334 | + } else { | |
| 335 | + cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie, | |
| 336 | + &p2p->listen_chan, | |
| 337 | + p2p->listen_duration, GFP_KERNEL); | |
| 338 | + wil->radio_wdev = p2p->pending_listen_wdev; | |
| 339 | + } | |
| 340 | + p2p->pending_listen_wdev = NULL; | |
| 341 | + mutex_unlock(&wil->p2p_wdev_mutex); | |
| 342 | + | |
| 343 | +out: | |
| 344 | + mutex_unlock(&wil->mutex); | |
| 345 | +} | |
| 346 | + | |
| 267 | 347 | void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) |
| 268 | 348 | { |
| 269 | 349 | struct wil_p2p_info *p2p = &wil->p2p; |
| @@ -272,8 +352,7 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) · 2 unmodified lines | ||
| 272 | 352 | }; |
| 273 | 353 | |
| 274 | 354 | lockdep_assert_held(&wil->mutex); |
| 275 | − | |
| 276 | − mutex_lock(&wil->p2p_wdev_mutex); | |
| 355 | + lockdep_assert_held(&wil->p2p_wdev_mutex); | |
| 277 | 356 | |
| 278 | 357 | if (wil->radio_wdev != wil->p2p_wdev) |
| 279 | 358 | goto out; |
| @@ -281,10 +360,8 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) · 1 unmodified line | ||
| 281 | 360 | if (!p2p->discovery_started) { |
| 282 | 361 | /* Regular scan on the p2p device */ |
| 283 | 362 | if (wil->scan_request && |
| 284 | − wil->scan_request->wdev == wil->p2p_wdev) { | |
| 285 | − cfg80211_scan_done(wil->scan_request, &info); | |
| 286 | − wil->scan_request = NULL; | |
| 287 | − } | |
| 363 | + wil->scan_request->wdev == wil->p2p_wdev) | |
| 364 | + wil_abort_scan(wil, true); | |
| 288 | 365 | goto out; |
| 289 | 366 | } |
| 290 | 367 | |
| @@ -307,5 +384,4 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) · 16 unmodified lines | ||
| 307 | 384 | |
| 308 | 385 | out: |
| 309 | 386 | wil->radio_wdev = wil->wdev; |
| 310 | − mutex_unlock(&wil->p2p_wdev_mutex); | |
| 311 | 387 | } |
| @@ -54,6 +54,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, · 53 unmodified lines | ||
| 54 | 54 | struct pmc_ctx *pmc = &wil->pmc; |
| 55 | 55 | struct device *dev = wil_to_dev(wil); |
| 56 | 56 | struct wmi_pmc_cmd pmc_cmd = {0}; |
| 57 | + int last_cmd_err = -ENOMEM; | |
| 57 | 58 | |
| 58 | 59 | mutex_lock(&pmc->lock); |
| 59 | 60 | |
| @@ -62,6 +63,29 @@ void wil_pmc_alloc(struct wil6210_priv *wil, · 2 unmodified lines | ||
| 62 | 63 | wil_err(wil, "%s: ERROR pmc is already allocated\n", __func__); |
| 63 | 64 | goto no_release_err; |
| 64 | 65 | } |
| 66 | + if ((num_descriptors <= 0) || (descriptor_size <= 0)) { | |
| 67 | + wil_err(wil, | |
| 68 | + "Invalid params num_descriptors(%d), descriptor_size(%d)\n", | |
| 69 | + num_descriptors, descriptor_size); | |
| 70 | + last_cmd_err = -EINVAL; | |
| 71 | + goto no_release_err; | |
| 72 | + } | |
| 73 | + | |
| 74 | + if (num_descriptors > (1 << WIL_RING_SIZE_ORDER_MAX)) { | |
| 75 | + wil_err(wil, | |
| 76 | + "num_descriptors(%d) exceeds max ring size %d\n", | |
| 77 | + num_descriptors, 1 << WIL_RING_SIZE_ORDER_MAX); | |
| 78 | + last_cmd_err = -EINVAL; | |
| 79 | + goto no_release_err; | |
| 80 | + } | |
| 81 | + | |
| 82 | + if (num_descriptors > INT_MAX / descriptor_size) { | |
| 83 | + wil_err(wil, | |
| 84 | + "Overflow in num_descriptors(%d)*descriptor_size(%d)\n", | |
| 85 | + num_descriptors, descriptor_size); | |
| 86 | + last_cmd_err = -EINVAL; | |
| 87 | + goto no_release_err; | |
| 88 | + } | |
| 65 | 89 | |
| 66 | 90 | pmc->num_descriptors = num_descriptors; |
| 67 | 91 | pmc->descriptor_size = descriptor_size; |
| @@ -189,7 +213,7 @@ release_pmc_skb_list: · 121 unmodified lines | ||
| 189 | 213 | pmc->descriptors = NULL; |
| 190 | 214 | |
| 191 | 215 | no_release_err: |
| 192 | − pmc->last_cmd_status = -ENOMEM; | |
| 216 | + pmc->last_cmd_status = last_cmd_err; | |
| 193 | 217 | mutex_unlock(&pmc->lock); |
| 194 | 218 | } |
| 195 | 219 | |
| @@ -295,7 +319,7 @@ ssize_t wil_pmc_read(struct file *filp, char __user *buf, size_t count, · 99 unmodified lines | ||
| 295 | 319 | size_t retval = 0; |
| 296 | 320 | unsigned long long idx; |
| 297 | 321 | loff_t offset; |
| 298 | − size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors; | |
| 322 | + size_t pmc_size; | |
| 299 | 323 | |
| 300 | 324 | mutex_lock(&pmc->lock); |
| 301 | 325 | |
| @@ -306,6 +330,8 @@ ssize_t wil_pmc_read(struct file *filp, char __user *buf, size_t count, · 4 unmodified lines | ||
| 306 | 330 | return -EPERM; |
| 307 | 331 | } |
| 308 | 332 | |
| 333 | + pmc_size = pmc->descriptor_size * pmc->num_descriptors; | |
| 334 | + | |
| 309 | 335 | wil_dbg_misc(wil, |
| 310 | 336 | "%s: size %u, pos %lld\n", |
| 311 | 337 | __func__, (unsigned)count, *f_pos); |
| @@ -345,7 +371,18 @@ loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence) · 33 unmodified lines | ||
| 345 | 371 | loff_t newpos; |
| 346 | 372 | struct wil6210_priv *wil = filp->private_data; |
| 347 | 373 | struct pmc_ctx *pmc = &wil->pmc; |
| 348 | − size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors; | |
| 374 | + size_t pmc_size; | |
| 375 | + | |
| 376 | + mutex_lock(&pmc->lock); | |
| 377 | + | |
| 378 | + if (!wil_is_pmc_allocated(pmc)) { | |
| 379 | + wil_err(wil, "error, pmc is not allocated!\n"); | |
| 380 | + pmc->last_cmd_status = -EPERM; | |
| 381 | + mutex_unlock(&pmc->lock); | |
| 382 | + return -EPERM; | |
| 383 | + } | |
| 384 | + | |
| 385 | + pmc_size = pmc->descriptor_size * pmc->num_descriptors; | |
| 349 | 386 | |
| 350 | 387 | switch (whence) { |
| 351 | 388 | case 0: /* SEEK_SET */ |
| @@ -361,15 +398,21 @@ loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence) · 9 unmodified lines | ||
| 361 | 398 | break; |
| 362 | 399 | |
| 363 | 400 | default: /* can't happen */ |
| 364 | − return -EINVAL; | |
| 401 | + newpos = -EINVAL; | |
| 402 | + goto out; | |
| 365 | 403 | } |
| 366 | 404 | |
| 367 | − if (newpos < 0) | |
| 368 | − return -EINVAL; | |
| 405 | + if (newpos < 0) { | |
| 406 | + newpos = -EINVAL; | |
| 407 | + goto out; | |
| 408 | + } | |
| 369 | 409 | if (newpos > pmc_size) |
| 370 | 410 | newpos = pmc_size; |
| 371 | 411 | |
| 372 | 412 | filp->f_pos = newpos; |
| 373 | 413 | |
| 414 | +out: | |
| 415 | + mutex_unlock(&pmc->lock); | |
| 416 | + | |
| 374 | 417 | return newpos; |
| 375 | 418 | } |
| @@ -88,6 +88,18 @@ static inline int wil_vring_wmark_high(struct vring *vring) · 87 unmodified lines | ||
| 88 | 88 | return vring->size/4; |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | +/* returns true if num avail descriptors is lower than wmark_low */ | |
| 92 | +static inline int wil_vring_avail_low(struct vring *vring) | |
| 93 | +{ | |
| 94 | + return wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring); | |
| 95 | +} | |
| 96 | + | |
| 97 | +/* returns true if num avail descriptors is higher than wmark_high */ | |
| 98 | +static inline int wil_vring_avail_high(struct vring *vring) | |
| 99 | +{ | |
| 100 | + return wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring); | |
| 101 | +} | |
| 102 | + | |
| 91 | 103 | /* wil_val_in_range - check if value in [min,max) */ |
| 92 | 104 | static inline bool wil_val_in_range(int val, int min, int max) |
| 93 | 105 | { |
| @@ -1780,6 +1792,89 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, · 1686 unmodified lines | ||
| 1780 | 1792 | return rc; |
| 1781 | 1793 | } |
| 1782 | 1794 | |
| 1795 | +/** | |
| 1796 | + * Check status of tx vrings and stop/wake net queues if needed | |
| 1797 | + * | |
| 1798 | + * This function does one of two checks: | |
| 1799 | + * In case check_stop is true, will check if net queues need to be stopped. If | |
| 1800 | + * the conditions for stopping are met, netif_tx_stop_all_queues() is called. | |
| 1801 | + * In case check_stop is false, will check if net queues need to be waked. If | |
| 1802 | + * the conditions for waking are met, netif_tx_wake_all_queues() is called. | |
| 1803 | + * vring is the vring which is currently being modified by either adding | |
| 1804 | + * descriptors (tx) into it or removing descriptors (tx complete) from it. Can | |
| 1805 | + * be null when irrelevant (e.g. connect/disconnect events). | |
| 1806 | + * | |
| 1807 | + * The implementation is to stop net queues if modified vring has low | |
| 1808 | + * descriptor availability. Wake if all vrings are not in low descriptor | |
| 1809 | + * availability and modified vring has high descriptor availability. | |
| 1810 | + */ | |
| 1811 | +static inline void __wil_update_net_queues(struct wil6210_priv *wil, | |
| 1812 | + struct vring *vring, | |
| 1813 | + bool check_stop) | |
| 1814 | +{ | |
| 1815 | + int i; | |
| 1816 | + | |
| 1817 | + if (vring) | |
| 1818 | + wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d", | |
| 1819 | + (int)(vring - wil->vring_tx), check_stop, | |
| 1820 | + wil->net_queue_stopped); | |
| 1821 | + else | |
| 1822 | + wil_dbg_txrx(wil, "check_stop=%d, stopped=%d", | |
| 1823 | + check_stop, wil->net_queue_stopped); | |
| 1824 | + | |
| 1825 | + if (check_stop == wil->net_queue_stopped) | |
| 1826 | + /* net queues already in desired state */ | |
| 1827 | + return; | |
| 1828 | + | |
| 1829 | + if (check_stop) { | |
| 1830 | + if (!vring || unlikely(wil_vring_avail_low(vring))) { | |
| 1831 | + /* not enough room in the vring */ | |
| 1832 | + netif_tx_stop_all_queues(wil_to_ndev(wil)); | |
| 1833 | + wil->net_queue_stopped = true; | |
| 1834 | + wil_dbg_txrx(wil, "netif_tx_stop called\n"); | |
| 1835 | + } | |
| 1836 | + return; | |
| 1837 | + } | |
| 1838 | + | |
| 1839 | + /* check wake */ | |
| 1840 | + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { | |
| 1841 | + struct vring *cur_vring = &wil->vring_tx[i]; | |
| 1842 | + struct vring_tx_data *txdata = &wil->vring_tx_data[i]; | |
| 1843 | + | |
| 1844 | + if (!cur_vring->va || !txdata->enabled || cur_vring == vring) | |
| 1845 | + continue; | |
| 1846 | + | |
| 1847 | + if (wil_vring_avail_low(cur_vring)) { | |
| 1848 | + wil_dbg_txrx(wil, "vring %d full, can't wake\n", | |
| 1849 | + (int)(cur_vring - wil->vring_tx)); | |
| 1850 | + return; | |
| 1851 | + } | |
| 1852 | + } | |
| 1853 | + | |
| 1854 | + if (!vring || wil_vring_avail_high(vring)) { | |
| 1855 | + /* enough room in the vring */ | |
| 1856 | + wil_dbg_txrx(wil, "calling netif_tx_wake\n"); | |
| 1857 | + netif_tx_wake_all_queues(wil_to_ndev(wil)); | |
| 1858 | + wil->net_queue_stopped = false; | |
| 1859 | + } | |
| 1860 | +} | |
| 1861 | + | |
| 1862 | +void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring, | |
| 1863 | + bool check_stop) | |
| 1864 | +{ | |
| 1865 | + spin_lock(&wil->net_queue_lock); | |
| 1866 | + __wil_update_net_queues(wil, vring, check_stop); | |
| 1867 | + spin_unlock(&wil->net_queue_lock); | |
| 1868 | +} | |
| 1869 | + | |
| 1870 | +void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring, | |
| 1871 | + bool check_stop) | |
| 1872 | +{ | |
| 1873 | + spin_lock_bh(&wil->net_queue_lock); | |
| 1874 | + __wil_update_net_queues(wil, vring, check_stop); | |
| 1875 | + spin_unlock_bh(&wil->net_queue_lock); | |
| 1876 | +} | |
| 1877 | + | |
| 1783 | 1878 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
| 1784 | 1879 | { |
| 1785 | 1880 | struct wil6210_priv *wil = ndev_to_wil(ndev); |
| @@ -1822,14 +1917,10 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) · 36 unmodified lines | ||
| 1822 | 1917 | /* set up vring entry */ |
| 1823 | 1918 | rc = wil_tx_vring(wil, vring, skb); |
| 1824 | 1919 | |
| 1825 | − /* do we still have enough room in the vring? */ | |
| 1826 | − if (unlikely(wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring))) { | |
| 1827 | − netif_tx_stop_all_queues(wil_to_ndev(wil)); | |
| 1828 | − wil_dbg_txrx(wil, "netif_tx_stop : ring full\n"); | |
| 1829 | − } | |
| 1830 | − | |
| 1831 | 1920 | switch (rc) { |
| 1832 | 1921 | case 0: |
| 1922 | + /* shall we stop net queues? */ | |
| 1923 | + wil_update_net_queues_bh(wil, vring, true); | |
| 1833 | 1924 | /* statistics will be updated on the tx_complete */ |
| 1834 | 1925 | dev_kfree_skb_any(skb); |
| 1835 | 1926 | return NETDEV_TX_OK; |
| @@ -1978,10 +2069,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) · 142 unmodified lines | ||
| 1978 | 2069 | txdata->last_idle = get_cycles(); |
| 1979 | 2070 | } |
| 1980 | 2071 | |
| 1981 | − if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) { | |
| 1982 | − wil_dbg_txrx(wil, "netif_tx_wake : ring not full\n"); | |
| 1983 | − netif_tx_wake_all_queues(wil_to_ndev(wil)); | |
| 1984 | − } | |
| 2072 | + /* shall we wake net queues? */ | |
| 2073 | + if (done) | |
| 2074 | + wil_update_net_queues(wil, vring, false); | |
| 1985 | 2075 | |
| 1986 | 2076 | return done; |
| 1987 | 2077 | } |
| @@ -276,10 +276,11 @@ struct fw_map { · 275 unmodified lines | ||
| 276 | 276 | u32 to; /* linker address - to, exclusive */ |
| 277 | 277 | u32 host; /* PCI/Host address - BAR0 + 0x880000 */ |
| 278 | 278 | const char *name; /* for debugfs */ |
| 279 | + bool fw; /* true if FW mapping, false if UCODE mapping */ | |
| 279 | 280 | }; |
| 280 | 281 | |
| 281 | 282 | /* array size should be in sync with actual definition in the wmi.c */ |
| 282 | −extern const struct fw_map fw_mapping[8]; | |
| 283 | +extern const struct fw_map fw_mapping[10]; | |
| 283 | 284 | |
| 284 | 285 | /** |
| 285 | 286 | * mk_cidxtid - construct @cidxtid field |
| @@ -461,8 +462,11 @@ struct wil_p2p_info { · 175 unmodified lines | ||
| 461 | 462 | u8 discovery_started; |
| 462 | 463 | u8 p2p_dev_started; |
| 463 | 464 | u64 cookie; |
| 465 | + struct wireless_dev *pending_listen_wdev; | |
| 466 | + unsigned int listen_duration; | |
| 464 | 467 | struct timer_list discovery_timer; /* listen/search duration */ |
| 465 | 468 | struct work_struct discovery_expired_work; /* listen/search expire */ |
| 469 | + struct work_struct delayed_listen_work; /* listen after scan done */ | |
| 466 | 470 | }; |
| 467 | 471 | |
| 468 | 472 | enum wil_sta_status { |
| @@ -624,6 +628,8 @@ struct wil6210_priv { · 155 unmodified lines | ||
| 624 | 628 | * - consumed in thread by wmi_event_worker |
| 625 | 629 | */ |
| 626 | 630 | spinlock_t wmi_ev_lock; |
| 631 | + spinlock_t net_queue_lock; /* guarding stop/wake netif queue */ | |
| 632 | + int net_queue_stopped; /* netif_tx_stop_all_queues invoked */ | |
| 627 | 633 | struct napi_struct napi_rx; |
| 628 | 634 | struct napi_struct napi_tx; |
| 629 | 635 | /* keep alive */ |
| @@ -817,6 +823,10 @@ int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason); · 187 unmodified lines | ||
| 817 | 823 | int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason); |
| 818 | 824 | int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, |
| 819 | 825 | u16 status, bool amsdu, u16 agg_wsize, u16 timeout); |
| 826 | +int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, | |
| 827 | + enum wmi_ps_profile_type ps_profile); | |
| 828 | +int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short); | |
| 829 | +int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short); | |
| 820 | 830 | int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, |
| 821 | 831 | u8 dialog_token, __le16 ba_param_set, |
| 822 | 832 | __le16 ba_timeout, __le16 ba_seq_ctrl); |
| @@ -837,13 +847,15 @@ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request); · 14 unmodified lines | ||
| 837 | 847 | void wil_p2p_discovery_timer_fn(ulong x); |
| 838 | 848 | int wil_p2p_search(struct wil6210_priv *wil, |
| 839 | 849 | struct cfg80211_scan_request *request); |
| 840 | −int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, | |
| 841 | − struct ieee80211_channel *chan, u64 *cookie); | |
| 850 | +int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, | |
| 851 | + unsigned int duration, struct ieee80211_channel *chan, | |
| 852 | + u64 *cookie); | |
| 842 | 853 | u8 wil_p2p_stop_discovery(struct wil6210_priv *wil); |
| 843 | 854 | int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie); |
| 844 | 855 | void wil_p2p_listen_expired(struct work_struct *work); |
| 845 | 856 | void wil_p2p_search_expired(struct work_struct *work); |
| 846 | 857 | void wil_p2p_stop_radio_operations(struct wil6210_priv *wil); |
| 858 | +void wil_p2p_delayed_listen_work(struct work_struct *work); | |
| 847 | 859 | |
| 848 | 860 | /* WMI for P2P */ |
| 849 | 861 | int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi); |
| @@ -869,6 +881,9 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, · 19 unmodified lines | ||
| 869 | 881 | u8 chan, u8 hidden_ssid, u8 is_go); |
| 870 | 882 | int wmi_pcp_stop(struct wil6210_priv *wil); |
| 871 | 883 | int wmi_led_cfg(struct wil6210_priv *wil, bool enable); |
| 884 | +int wmi_abort_scan(struct wil6210_priv *wil); | |
| 885 | +void wil_abort_scan(struct wil6210_priv *wil, bool sync); | |
| 886 | + | |
| 872 | 887 | void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, |
| 873 | 888 | u16 reason_code, bool from_event); |
| 874 | 889 | void wil_probe_client_flush(struct wil6210_priv *wil); |
| @@ -886,6 +901,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size); · 11 unmodified lines | ||
| 886 | 901 | int wil_bcast_init(struct wil6210_priv *wil); |
| 887 | 902 | void wil_bcast_fini(struct wil6210_priv *wil); |
| 888 | 903 | |
| 904 | +void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring, | |
| 905 | + bool should_stop); | |
| 906 | +void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring, | |
| 907 | + bool check_stop); | |
| 889 | 908 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); |
| 890 | 909 | int wil_tx_complete(struct wil6210_priv *wil, int ringid); |
| 891 | 910 | void wil6210_unmask_irq_tx(struct wil6210_priv *wil); |
| @@ -36,6 +36,9 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil, · 35 unmodified lines | ||
| 36 | 36 | for (i = 1; i < ARRAY_SIZE(fw_mapping); i++) { |
| 37 | 37 | map = &fw_mapping[i]; |
| 38 | 38 | |
| 39 | + if (!map->fw) | |
| 40 | + continue; | |
| 41 | + | |
| 39 | 42 | if (map->host < host_min) |
| 40 | 43 | host_min = map->host; |
| 41 | 44 | |
| @@ -73,6 +76,9 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) · 31 unmodified lines | ||
| 73 | 76 | for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { |
| 74 | 77 | map = &fw_mapping[i]; |
| 75 | 78 | |
| 79 | + if (!map->fw) | |
| 80 | + continue; | |
| 81 | + | |
| 76 | 82 | data = (void * __force)wil->csr + HOSTADDR(map->host); |
| 77 | 83 | len = map->to - map->from; |
| 78 | 84 | offset = map->host - host_min; |
| @@ -84,19 +84,29 @@ MODULE_PARM_DESC(led_id, · 83 unmodified lines | ||
| 84 | 84 | * array size should be in sync with the declaration in the wil6210.h |
| 85 | 85 | */ |
| 86 | 86 | const struct fw_map fw_mapping[] = { |
| 87 | − {0x000000, 0x040000, 0x8c0000, "fw_code"}, /* FW code RAM 256k */ | |
| 88 | − {0x800000, 0x808000, 0x900000, "fw_data"}, /* FW data RAM 32k */ | |
| 89 | − {0x840000, 0x860000, 0x908000, "fw_peri"}, /* periph. data RAM 128k */ | |
| 90 | − {0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */ | |
| 91 | − {0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */ | |
| 92 | − {0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */ | |
| 93 | − {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext"}, /* mac_ext_rgf 512b */ | |
| 94 | − {0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */ | |
| 95 | − /* | |
| 96 | − * 920000..930000 ucode code RAM | |
| 97 | − * 930000..932000 ucode data RAM | |
| 98 | − * 932000..949000 back-door debug data | |
| 87 | + /* FW code RAM 256k */ | |
| 88 | + {0x000000, 0x040000, 0x8c0000, "fw_code", true}, | |
| 89 | + /* FW data RAM 32k */ | |
| 90 | + {0x800000, 0x808000, 0x900000, "fw_data", true}, | |
| 91 | + /* periph data 128k */ | |
| 92 | + {0x840000, 0x860000, 0x908000, "fw_peri", true}, | |
| 93 | + /* various RGF 40k */ | |
| 94 | + {0x880000, 0x88a000, 0x880000, "rgf", true}, | |
| 95 | + /* AGC table 4k */ | |
| 96 | + {0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true}, | |
| 97 | + /* Pcie_ext_rgf 4k */ | |
| 98 | + {0x88b000, 0x88c000, 0x88b000, "rgf_ext", true}, | |
| 99 | + /* mac_ext_rgf 512b */ | |
| 100 | + {0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true}, | |
| 101 | + /* upper area 548k */ | |
| 102 | + {0x8c0000, 0x949000, 0x8c0000, "upper", true}, | |
| 103 | + /* UCODE areas - accessible by debugfs blobs but not by | |
| 104 | + * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas! | |
| 99 | 105 | */ |
| 106 | + /* ucode code RAM 128k */ | |
| 107 | + {0x000000, 0x020000, 0x920000, "uc_code", false}, | |
| 108 | + /* ucode data RAM 16k */ | |
| 109 | + {0x800000, 0x804000, 0x940000, "uc_data", false}, | |
| 100 | 110 | }; |
| 101 | 111 | |
| 102 | 112 | struct blink_on_off_time led_blink_time[] = { |
| @@ -108,7 +118,7 @@ struct blink_on_off_time led_blink_time[] = { · 5 unmodified lines | ||
| 108 | 118 | u8 led_polarity = LED_POLARITY_LOW_ACTIVE; |
| 109 | 119 | |
| 110 | 120 | /** |
| 111 | − * return AHB address for given firmware/ucode internal (linker) address | |
| 121 | + * return AHB address for given firmware internal (linker) address | |
| 112 | 122 | * @x - internal address |
| 113 | 123 | * If address have no valid AHB mapping, return 0 |
| 114 | 124 | */ |
| @@ -117,7 +127,8 @@ static u32 wmi_addr_remap(u32 x) · 2 unmodified lines | ||
| 117 | 127 | uint i; |
| 118 | 128 | |
| 119 | 129 | for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { |
| 120 | − if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)) | |
| 130 | + if (fw_mapping[i].fw && | |
| 131 | + ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))) | |
| 121 | 132 | return x + fw_mapping[i].host - fw_mapping[i].from; |
| 122 | 133 | } |
| 123 | 134 | |
| @@ -427,18 +438,24 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, · 303 unmodified lines | ||
| 427 | 438 | mutex_lock(&wil->p2p_wdev_mutex); |
| 428 | 439 | if (wil->scan_request) { |
| 429 | 440 | struct wmi_scan_complete_event *data = d; |
| 441 | + int status = le32_to_cpu(data->status); | |
| 430 | 442 | struct cfg80211_scan_info info = { |
| 431 | − .aborted = (data->status != WMI_SCAN_SUCCESS), | |
| 443 | + .aborted = ((status != WMI_SCAN_SUCCESS) && | |
| 444 | + (status != WMI_SCAN_ABORT_REJECTED)), | |
| 432 | 445 | }; |
| 433 | 446 | |
| 434 | − wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); | |
| 447 | + wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status); | |
| 435 | 448 | wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n", |
| 436 | 449 | wil->scan_request, info.aborted); |
| 437 | − | |
| 438 | 450 | del_timer_sync(&wil->scan_timer); |
| 439 | 451 | cfg80211_scan_done(wil->scan_request, &info); |
| 440 | 452 | wil->radio_wdev = wil->wdev; |
| 441 | 453 | wil->scan_request = NULL; |
| 454 | + wake_up_interruptible(&wil->wq); | |
| 455 | + if (wil->p2p.pending_listen_wdev) { | |
| 456 | + wil_dbg_misc(wil, "Scheduling delayed listen\n"); | |
| 457 | + schedule_work(&wil->p2p.delayed_listen_work); | |
| 458 | + } | |
| 442 | 459 | } else { |
| 443 | 460 | wil_err(wil, "SCAN_COMPLETE while not scanning\n"); |
| 444 | 461 | } |
| @@ -548,7 +565,6 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) · 103 unmodified lines | ||
| 548 | 565 | if ((wdev->iftype == NL80211_IFTYPE_STATION) || |
| 549 | 566 | (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { |
| 550 | 567 | if (rc) { |
| 551 | − netif_tx_stop_all_queues(ndev); | |
| 552 | 568 | netif_carrier_off(ndev); |
| 553 | 569 | wil_err(wil, |
| 554 | 570 | "%s: cfg80211_connect_result with failure\n", |
| @@ -588,7 +604,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) · 33 unmodified lines | ||
| 588 | 604 | |
| 589 | 605 | wil->sta[evt->cid].status = wil_sta_connected; |
| 590 | 606 | set_bit(wil_status_fwconnected, wil->status); |
| 591 | − netif_tx_wake_all_queues(ndev); | |
| 607 | + wil_update_net_queues_bh(wil, NULL, false); | |
| 592 | 608 | |
| 593 | 609 | out: |
| 594 | 610 | if (rc) |
| @@ -1564,6 +1580,112 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, · 969 unmodified lines | ||
| 1564 | 1580 | return rc; |
| 1565 | 1581 | } |
| 1566 | 1582 | |
| 1583 | +int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, | |
| 1584 | + enum wmi_ps_profile_type ps_profile) | |
| 1585 | +{ | |
| 1586 | + int rc; | |
| 1587 | + struct wmi_ps_dev_profile_cfg_cmd cmd = { | |
| 1588 | + .ps_profile = ps_profile, | |
| 1589 | + }; | |
| 1590 | + struct { | |
| 1591 | + struct wmi_cmd_hdr wmi; | |
| 1592 | + struct wmi_ps_dev_profile_cfg_event evt; | |
| 1593 | + } __packed reply; | |
| 1594 | + u32 status; | |
| 1595 | + | |
| 1596 | + wil_dbg_wmi(wil, "Setting ps dev profile %d\n", ps_profile); | |
| 1597 | + | |
| 1598 | + reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR); | |
| 1599 | + | |
| 1600 | + rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, &cmd, sizeof(cmd), | |
| 1601 | + WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply), | |
| 1602 | + 100); | |
| 1603 | + if (rc) | |
| 1604 | + return rc; | |
| 1605 | + | |
| 1606 | + status = le32_to_cpu(reply.evt.status); | |
| 1607 | + | |
| 1608 | + if (status != WMI_PS_CFG_CMD_STATUS_SUCCESS) { | |
| 1609 | + wil_err(wil, "ps dev profile cfg failed with status %d\n", | |
| 1610 | + status); | |
| 1611 | + rc = -EINVAL; | |
| 1612 | + } | |
| 1613 | + | |
| 1614 | + return rc; | |
| 1615 | +} | |
| 1616 | + | |
| 1617 | +int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short) | |
| 1618 | +{ | |
| 1619 | + int rc; | |
| 1620 | + struct wmi_set_mgmt_retry_limit_cmd cmd = { | |
| 1621 | + .mgmt_retry_limit = retry_short, | |
| 1622 | + }; | |
| 1623 | + struct { | |
| 1624 | + struct wmi_cmd_hdr wmi; | |
| 1625 | + struct wmi_set_mgmt_retry_limit_event evt; | |
| 1626 | + } __packed reply; | |
| 1627 | + | |
| 1628 | + wil_dbg_wmi(wil, "Setting mgmt retry short %d\n", retry_short); | |
| 1629 | + | |
| 1630 | + if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities)) | |
| 1631 | + return -ENOTSUPP; | |
| 1632 | + | |
| 1633 | + reply.evt.status = WMI_FW_STATUS_FAILURE; | |
| 1634 | + | |
| 1635 | + rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, &cmd, sizeof(cmd), | |
| 1636 | + WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply), | |
| 1637 | + 100); | |
| 1638 | + if (rc) | |
| 1639 | + return rc; | |
| 1640 | + | |
| 1641 | + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { | |
| 1642 | + wil_err(wil, "set mgmt retry limit failed with status %d\n", | |
| 1643 | + reply.evt.status); | |
| 1644 | + rc = -EINVAL; | |
| 1645 | + } | |
| 1646 | + | |
| 1647 | + return rc; | |
| 1648 | +} | |
| 1649 | + | |
| 1650 | +int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short) | |
| 1651 | +{ | |
| 1652 | + int rc; | |
| 1653 | + struct { | |
| 1654 | + struct wmi_cmd_hdr wmi; | |
| 1655 | + struct wmi_get_mgmt_retry_limit_event evt; | |
| 1656 | + } __packed reply; | |
| 1657 | + | |
| 1658 | + wil_dbg_wmi(wil, "getting mgmt retry short\n"); | |
| 1659 | + | |
| 1660 | + if (!test_bit(WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT, wil->fw_capabilities)) | |
| 1661 | + return -ENOTSUPP; | |
| 1662 | + | |
| 1663 | + reply.evt.mgmt_retry_limit = 0; | |
| 1664 | + rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, NULL, 0, | |
| 1665 | + WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply), | |
| 1666 | + 100); | |
| 1667 | + if (rc) | |
| 1668 | + return rc; | |
| 1669 | + | |
| 1670 | + if (retry_short) | |
| 1671 | + *retry_short = reply.evt.mgmt_retry_limit; | |
| 1672 | + | |
| 1673 | + return 0; | |
| 1674 | +} | |
| 1675 | + | |
| 1676 | +int wmi_abort_scan(struct wil6210_priv *wil) | |
| 1677 | +{ | |
| 1678 | + int rc; | |
| 1679 | + | |
| 1680 | + wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n"); | |
| 1681 | + | |
| 1682 | + rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, NULL, 0); | |
| 1683 | + if (rc) | |
| 1684 | + wil_err(wil, "Failed to abort scan (%d)\n", rc); | |
| 1685 | + | |
| 1686 | + return rc; | |
| 1687 | +} | |
| 1688 | + | |
| 1567 | 1689 | void wmi_event_flush(struct wil6210_priv *wil) |
| 1568 | 1690 | { |
| 1569 | 1691 | struct pending_wmi_event *evt, *t; |
| @@ -35,6 +35,7 @@ · 34 unmodified lines | ||
| 35 | 35 | #define WMI_MAC_LEN (6) |
| 36 | 36 | #define WMI_PROX_RANGE_NUM (3) |
| 37 | 37 | #define WMI_MAX_LOSS_DMG_BEACONS (20) |
| 38 | +#define MAX_NUM_OF_SECTORS (128) | |
| 38 | 39 | |
| 39 | 40 | /* Mailbox interface |
| 40 | 41 | * used for commands and events |
| @@ -51,8 +52,10 @@ enum wmi_mid { · 10 unmodified lines | ||
| 51 | 52 | * the host |
| 52 | 53 | */ |
| 53 | 54 | enum wmi_fw_capability { |
| 54 | − WMI_FW_CAPABILITY_FTM = 0, | |
| 55 | − WMI_FW_CAPABILITY_PS_CONFIG = 1, | |
| 55 | + WMI_FW_CAPABILITY_FTM = 0, | |
| 56 | + WMI_FW_CAPABILITY_PS_CONFIG = 1, | |
| 57 | + WMI_FW_CAPABILITY_RF_SECTORS = 2, | |
| 58 | + WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3, | |
| 56 | 59 | WMI_FW_CAPABILITY_MAX, |
| 57 | 60 | }; |
| 58 | 61 | |
| @@ -66,137 +69,149 @@ struct wmi_cmd_hdr { · 7 unmodified lines | ||
| 66 | 69 | |
| 67 | 70 | /* List of Commands */ |
| 68 | 71 | enum wmi_command_id { |
| 69 | − WMI_CONNECT_CMDID = 0x01, | |
| 70 | − WMI_DISCONNECT_CMDID = 0x03, | |
| 71 | − WMI_DISCONNECT_STA_CMDID = 0x04, | |
| 72 | − WMI_START_SCAN_CMDID = 0x07, | |
| 73 | − WMI_SET_BSS_FILTER_CMDID = 0x09, | |
| 74 | − WMI_SET_PROBED_SSID_CMDID = 0x0A, | |
| 75 | − WMI_SET_LISTEN_INT_CMDID = 0x0B, | |
| 76 | − WMI_BCON_CTRL_CMDID = 0x0F, | |
| 77 | − WMI_ADD_CIPHER_KEY_CMDID = 0x16, | |
| 78 | − WMI_DELETE_CIPHER_KEY_CMDID = 0x17, | |
| 79 | − WMI_PCP_CONF_CMDID = 0x18, | |
| 80 | − WMI_SET_APPIE_CMDID = 0x3F, | |
| 81 | − WMI_SET_WSC_STATUS_CMDID = 0x41, | |
| 82 | − WMI_PXMT_RANGE_CFG_CMDID = 0x42, | |
| 83 | − WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x43, | |
| 84 | − WMI_MEM_READ_CMDID = 0x800, | |
| 85 | − WMI_MEM_WR_CMDID = 0x801, | |
| 86 | − WMI_ECHO_CMDID = 0x803, | |
| 87 | − WMI_DEEP_ECHO_CMDID = 0x804, | |
| 88 | − WMI_CONFIG_MAC_CMDID = 0x805, | |
| 89 | − WMI_CONFIG_PHY_DEBUG_CMDID = 0x806, | |
| 90 | − WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x808, | |
| 91 | − WMI_PHY_GET_STATISTICS_CMDID = 0x809, | |
| 92 | − WMI_FS_TUNE_CMDID = 0x80A, | |
| 93 | − WMI_CORR_MEASURE_CMDID = 0x80B, | |
| 94 | − WMI_READ_RSSI_CMDID = 0x80C, | |
| 95 | − WMI_TEMP_SENSE_CMDID = 0x80E, | |
| 96 | − WMI_DC_CALIB_CMDID = 0x80F, | |
| 97 | − WMI_SEND_TONE_CMDID = 0x810, | |
| 98 | − WMI_IQ_TX_CALIB_CMDID = 0x811, | |
| 99 | − WMI_IQ_RX_CALIB_CMDID = 0x812, | |
| 100 | − WMI_SET_UCODE_IDLE_CMDID = 0x813, | |
| 101 | − WMI_SET_WORK_MODE_CMDID = 0x815, | |
| 102 | − WMI_LO_LEAKAGE_CALIB_CMDID = 0x816, | |
| 103 | − WMI_MARLON_R_READ_CMDID = 0x818, | |
| 104 | − WMI_MARLON_R_WRITE_CMDID = 0x819, | |
| 105 | − WMI_MARLON_R_TXRX_SEL_CMDID = 0x81A, | |
| 106 | − MAC_IO_STATIC_PARAMS_CMDID = 0x81B, | |
| 107 | − MAC_IO_DYNAMIC_PARAMS_CMDID = 0x81C, | |
| 108 | − WMI_SILENT_RSSI_CALIB_CMDID = 0x81D, | |
| 109 | − WMI_RF_RX_TEST_CMDID = 0x81E, | |
| 110 | − WMI_CFG_RX_CHAIN_CMDID = 0x820, | |
| 111 | − WMI_VRING_CFG_CMDID = 0x821, | |
| 112 | − WMI_BCAST_VRING_CFG_CMDID = 0x822, | |
| 113 | − WMI_VRING_BA_EN_CMDID = 0x823, | |
| 114 | − WMI_VRING_BA_DIS_CMDID = 0x824, | |
| 115 | − WMI_RCP_ADDBA_RESP_CMDID = 0x825, | |
| 116 | − WMI_RCP_DELBA_CMDID = 0x826, | |
| 117 | − WMI_SET_SSID_CMDID = 0x827, | |
| 118 | − WMI_GET_SSID_CMDID = 0x828, | |
| 119 | − WMI_SET_PCP_CHANNEL_CMDID = 0x829, | |
| 120 | − WMI_GET_PCP_CHANNEL_CMDID = 0x82A, | |
| 121 | − WMI_SW_TX_REQ_CMDID = 0x82B, | |
| 122 | − WMI_READ_MAC_RXQ_CMDID = 0x830, | |
| 123 | − WMI_READ_MAC_TXQ_CMDID = 0x831, | |
| 124 | − WMI_WRITE_MAC_RXQ_CMDID = 0x832, | |
| 125 | − WMI_WRITE_MAC_TXQ_CMDID = 0x833, | |
| 126 | − WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x834, | |
| 127 | − WMI_MLME_PUSH_CMDID = 0x835, | |
| 128 | − WMI_BEAMFORMING_MGMT_CMDID = 0x836, | |
| 129 | − WMI_BF_TXSS_MGMT_CMDID = 0x837, | |
| 130 | − WMI_BF_SM_MGMT_CMDID = 0x838, | |
| 131 | − WMI_BF_RXSS_MGMT_CMDID = 0x839, | |
| 132 | − WMI_BF_TRIG_CMDID = 0x83A, | |
| 133 | − WMI_LINK_MAINTAIN_CFG_WRITE_CMDID = 0x842, | |
| 134 | − WMI_LINK_MAINTAIN_CFG_READ_CMDID = 0x843, | |
| 135 | − WMI_SET_SECTORS_CMDID = 0x849, | |
| 136 | − WMI_MAINTAIN_PAUSE_CMDID = 0x850, | |
| 137 | − WMI_MAINTAIN_RESUME_CMDID = 0x851, | |
| 138 | − WMI_RS_MGMT_CMDID = 0x852, | |
| 139 | − WMI_RF_MGMT_CMDID = 0x853, | |
| 140 | − WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x854, | |
| 141 | − WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x855, | |
| 142 | − WMI_OTP_READ_CMDID = 0x856, | |
| 143 | − WMI_OTP_WRITE_CMDID = 0x857, | |
| 144 | − WMI_LED_CFG_CMDID = 0x858, | |
| 72 | + WMI_CONNECT_CMDID = 0x01, | |
| 73 | + WMI_DISCONNECT_CMDID = 0x03, | |
| 74 | + WMI_DISCONNECT_STA_CMDID = 0x04, | |
| 75 | + WMI_START_SCAN_CMDID = 0x07, | |
| 76 | + WMI_SET_BSS_FILTER_CMDID = 0x09, | |
| 77 | + WMI_SET_PROBED_SSID_CMDID = 0x0A, | |
| 78 | + WMI_SET_LISTEN_INT_CMDID = 0x0B, | |
| 79 | + WMI_BCON_CTRL_CMDID = 0x0F, | |
| 80 | + WMI_ADD_CIPHER_KEY_CMDID = 0x16, | |
| 81 | + WMI_DELETE_CIPHER_KEY_CMDID = 0x17, | |
| 82 | + WMI_PCP_CONF_CMDID = 0x18, | |
| 83 | + WMI_SET_APPIE_CMDID = 0x3F, | |
| 84 | + WMI_SET_WSC_STATUS_CMDID = 0x41, | |
| 85 | + WMI_PXMT_RANGE_CFG_CMDID = 0x42, | |
| 86 | + WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x43, | |
| 87 | + WMI_MEM_READ_CMDID = 0x800, | |
| 88 | + WMI_MEM_WR_CMDID = 0x801, | |
| 89 | + WMI_ECHO_CMDID = 0x803, | |
| 90 | + WMI_DEEP_ECHO_CMDID = 0x804, | |
| 91 | + WMI_CONFIG_MAC_CMDID = 0x805, | |
| 92 | + WMI_CONFIG_PHY_DEBUG_CMDID = 0x806, | |
| 93 | + WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x808, | |
| 94 | + WMI_PHY_GET_STATISTICS_CMDID = 0x809, | |
| 95 | + WMI_FS_TUNE_CMDID = 0x80A, | |
| 96 | + WMI_CORR_MEASURE_CMDID = 0x80B, | |
| 97 | + WMI_READ_RSSI_CMDID = 0x80C, | |
| 98 | + WMI_TEMP_SENSE_CMDID = 0x80E, | |
| 99 | + WMI_DC_CALIB_CMDID = 0x80F, | |
| 100 | + WMI_SEND_TONE_CMDID = 0x810, | |
| 101 | + WMI_IQ_TX_CALIB_CMDID = 0x811, | |
| 102 | + WMI_IQ_RX_CALIB_CMDID = 0x812, | |
| 103 | + WMI_SET_UCODE_IDLE_CMDID = 0x813, | |
| 104 | + WMI_SET_WORK_MODE_CMDID = 0x815, | |
| 105 | + WMI_LO_LEAKAGE_CALIB_CMDID = 0x816, | |
| 106 | + WMI_MARLON_R_READ_CMDID = 0x818, | |
| 107 | + WMI_MARLON_R_WRITE_CMDID = 0x819, | |
| 108 | + WMI_MARLON_R_TXRX_SEL_CMDID = 0x81A, | |
| 109 | + MAC_IO_STATIC_PARAMS_CMDID = 0x81B, | |
| 110 | + MAC_IO_DYNAMIC_PARAMS_CMDID = 0x81C, | |
| 111 | + WMI_SILENT_RSSI_CALIB_CMDID = 0x81D, | |
| 112 | + WMI_RF_RX_TEST_CMDID = 0x81E, | |
| 113 | + WMI_CFG_RX_CHAIN_CMDID = 0x820, | |
| 114 | + WMI_VRING_CFG_CMDID = 0x821, | |
| 115 | + WMI_BCAST_VRING_CFG_CMDID = 0x822, | |
| 116 | + WMI_VRING_BA_EN_CMDID = 0x823, | |
| 117 | + WMI_VRING_BA_DIS_CMDID = 0x824, | |
| 118 | + WMI_RCP_ADDBA_RESP_CMDID = 0x825, | |
| 119 | + WMI_RCP_DELBA_CMDID = 0x826, | |
| 120 | + WMI_SET_SSID_CMDID = 0x827, | |
| 121 | + WMI_GET_SSID_CMDID = 0x828, | |
| 122 | + WMI_SET_PCP_CHANNEL_CMDID = 0x829, | |
| 123 | + WMI_GET_PCP_CHANNEL_CMDID = 0x82A, | |
| 124 | + WMI_SW_TX_REQ_CMDID = 0x82B, | |
| 125 | + WMI_READ_MAC_RXQ_CMDID = 0x830, | |
| 126 | + WMI_READ_MAC_TXQ_CMDID = 0x831, | |
| 127 | + WMI_WRITE_MAC_RXQ_CMDID = 0x832, | |
| 128 | + WMI_WRITE_MAC_TXQ_CMDID = 0x833, | |
| 129 | + WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x834, | |
| 130 | + WMI_MLME_PUSH_CMDID = 0x835, | |
| 131 | + WMI_BEAMFORMING_MGMT_CMDID = 0x836, | |
| 132 | + WMI_BF_TXSS_MGMT_CMDID = 0x837, | |
| 133 | + WMI_BF_SM_MGMT_CMDID = 0x838, | |
| 134 | + WMI_BF_RXSS_MGMT_CMDID = 0x839, | |
| 135 | + WMI_BF_TRIG_CMDID = 0x83A, | |
| 136 | + WMI_LINK_MAINTAIN_CFG_WRITE_CMDID = 0x842, | |
| 137 | + WMI_LINK_MAINTAIN_CFG_READ_CMDID = 0x843, | |
| 138 | + WMI_SET_SECTORS_CMDID = 0x849, | |
| 139 | + WMI_MAINTAIN_PAUSE_CMDID = 0x850, | |
| 140 | + WMI_MAINTAIN_RESUME_CMDID = 0x851, | |
| 141 | + WMI_RS_MGMT_CMDID = 0x852, | |
| 142 | + WMI_RF_MGMT_CMDID = 0x853, | |
| 143 | + WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x854, | |
| 144 | + WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x855, | |
| 145 | + WMI_OTP_READ_CMDID = 0x856, | |
| 146 | + WMI_OTP_WRITE_CMDID = 0x857, | |
| 147 | + WMI_LED_CFG_CMDID = 0x858, | |
| 145 | 148 | /* Performance monitoring commands */ |
| 146 | − WMI_BF_CTRL_CMDID = 0x862, | |
| 147 | − WMI_NOTIFY_REQ_CMDID = 0x863, | |
| 148 | − WMI_GET_STATUS_CMDID = 0x864, | |
| 149 | − WMI_GET_RF_STATUS_CMDID = 0x866, | |
| 150 | − WMI_GET_BASEBAND_TYPE_CMDID = 0x867, | |
| 151 | − WMI_UNIT_TEST_CMDID = 0x900, | |
| 152 | − WMI_HICCUP_CMDID = 0x901, | |
| 153 | − WMI_FLASH_READ_CMDID = 0x902, | |
| 154 | − WMI_FLASH_WRITE_CMDID = 0x903, | |
| 149 | + WMI_BF_CTRL_CMDID = 0x862, | |
| 150 | + WMI_NOTIFY_REQ_CMDID = 0x863, | |
| 151 | + WMI_GET_STATUS_CMDID = 0x864, | |
| 152 | + WMI_GET_RF_STATUS_CMDID = 0x866, | |
| 153 | + WMI_GET_BASEBAND_TYPE_CMDID = 0x867, | |
| 154 | + WMI_UNIT_TEST_CMDID = 0x900, | |
| 155 | + WMI_HICCUP_CMDID = 0x901, | |
| 156 | + WMI_FLASH_READ_CMDID = 0x902, | |
| 157 | + WMI_FLASH_WRITE_CMDID = 0x903, | |
| 155 | 158 | /* Power management */ |
| 156 | − WMI_TRAFFIC_DEFERRAL_CMDID = 0x904, | |
| 157 | − WMI_TRAFFIC_RESUME_CMDID = 0x905, | |
| 159 | + WMI_TRAFFIC_DEFERRAL_CMDID = 0x904, | |
| 160 | + WMI_TRAFFIC_RESUME_CMDID = 0x905, | |
| 158 | 161 | /* P2P */ |
| 159 | − WMI_P2P_CFG_CMDID = 0x910, | |
| 160 | − WMI_PORT_ALLOCATE_CMDID = 0x911, | |
| 161 | − WMI_PORT_DELETE_CMDID = 0x912, | |
| 162 | − WMI_POWER_MGMT_CFG_CMDID = 0x913, | |
| 163 | − WMI_START_LISTEN_CMDID = 0x914, | |
| 164 | − WMI_START_SEARCH_CMDID = 0x915, | |
| 165 | − WMI_DISCOVERY_START_CMDID = 0x916, | |
| 166 | − WMI_DISCOVERY_STOP_CMDID = 0x917, | |
| 167 | − WMI_PCP_START_CMDID = 0x918, | |
| 168 | − WMI_PCP_STOP_CMDID = 0x919, | |
| 169 | − WMI_GET_PCP_FACTOR_CMDID = 0x91B, | |
| 162 | + WMI_P2P_CFG_CMDID = 0x910, | |
| 163 | + WMI_PORT_ALLOCATE_CMDID = 0x911, | |
| 164 | + WMI_PORT_DELETE_CMDID = 0x912, | |
| 165 | + WMI_POWER_MGMT_CFG_CMDID = 0x913, | |
| 166 | + WMI_START_LISTEN_CMDID = 0x914, | |
| 167 | + WMI_START_SEARCH_CMDID = 0x915, | |
| 168 | + WMI_DISCOVERY_START_CMDID = 0x916, | |
| 169 | + WMI_DISCOVERY_STOP_CMDID = 0x917, | |
| 170 | + WMI_PCP_START_CMDID = 0x918, | |
| 171 | + WMI_PCP_STOP_CMDID = 0x919, | |
| 172 | + WMI_GET_PCP_FACTOR_CMDID = 0x91B, | |
| 170 | 173 | /* Power Save Configuration Commands */ |
| 171 | − WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C, | |
| 174 | + WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C, | |
| 172 | 175 | /* Not supported yet */ |
| 173 | − WMI_PS_DEV_CFG_CMDID = 0x91D, | |
| 176 | + WMI_PS_DEV_CFG_CMDID = 0x91D, | |
| 174 | 177 | /* Not supported yet */ |
| 175 | − WMI_PS_DEV_CFG_READ_CMDID = 0x91E, | |
| 178 | + WMI_PS_DEV_CFG_READ_CMDID = 0x91E, | |
| 176 | 179 | /* Per MAC Power Save Configuration commands |
| 177 | 180 | * Not supported yet |
| 178 | 181 | */ |
| 179 | − WMI_PS_MID_CFG_CMDID = 0x91F, | |
| 182 | + WMI_PS_MID_CFG_CMDID = 0x91F, | |
| 180 | 183 | /* Not supported yet */ |
| 181 | − WMI_PS_MID_CFG_READ_CMDID = 0x920, | |
| 182 | − WMI_RS_CFG_CMDID = 0x921, | |
| 183 | − WMI_GET_DETAILED_RS_RES_CMDID = 0x922, | |
| 184 | − WMI_AOA_MEAS_CMDID = 0x923, | |
| 185 | − WMI_TOF_SESSION_START_CMDID = 0x991, | |
| 186 | − WMI_TOF_GET_CAPABILITIES_CMDID = 0x992, | |
| 187 | − WMI_TOF_SET_LCR_CMDID = 0x993, | |
| 188 | − WMI_TOF_SET_LCI_CMDID = 0x994, | |
| 189 | − WMI_TOF_CHANNEL_INFO_CMDID = 0x995, | |
| 190 | − WMI_SET_MAC_ADDRESS_CMDID = 0xF003, | |
| 191 | − WMI_ABORT_SCAN_CMDID = 0xF007, | |
| 192 | − WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, | |
| 193 | − WMI_GET_PMK_CMDID = 0xF048, | |
| 194 | − WMI_SET_PASSPHRASE_CMDID = 0xF049, | |
| 195 | − WMI_SEND_ASSOC_RES_CMDID = 0xF04A, | |
| 196 | − WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xF04B, | |
| 197 | − WMI_MAC_ADDR_REQ_CMDID = 0xF04D, | |
| 198 | − WMI_FW_VER_CMDID = 0xF04E, | |
| 199 | − WMI_PMC_CMDID = 0xF04F, | |
| 184 | + WMI_PS_MID_CFG_READ_CMDID = 0x920, | |
| 185 | + WMI_RS_CFG_CMDID = 0x921, | |
| 186 | + WMI_GET_DETAILED_RS_RES_CMDID = 0x922, | |
| 187 | + WMI_AOA_MEAS_CMDID = 0x923, | |
| 188 | + WMI_SET_MGMT_RETRY_LIMIT_CMDID = 0x930, | |
| 189 | + WMI_GET_MGMT_RETRY_LIMIT_CMDID = 0x931, | |
| 190 | + WMI_TOF_SESSION_START_CMDID = 0x991, | |
| 191 | + WMI_TOF_GET_CAPABILITIES_CMDID = 0x992, | |
| 192 | + WMI_TOF_SET_LCR_CMDID = 0x993, | |
| 193 | + WMI_TOF_SET_LCI_CMDID = 0x994, | |
| 194 | + WMI_TOF_CHANNEL_INFO_CMDID = 0x995, | |
| 195 | + WMI_TOF_SET_TX_RX_OFFSET_CMDID = 0x997, | |
| 196 | + WMI_TOF_GET_TX_RX_OFFSET_CMDID = 0x998, | |
| 197 | + WMI_GET_RF_SECTOR_PARAMS_CMDID = 0x9A0, | |
| 198 | + WMI_SET_RF_SECTOR_PARAMS_CMDID = 0x9A1, | |
| 199 | + WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID = 0x9A2, | |
| 200 | + WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID = 0x9A3, | |
| 201 | + WMI_SET_RF_SECTOR_ON_CMDID = 0x9A4, | |
| 202 | + WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5, | |
| 203 | + WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6, | |
| 204 | + WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7, | |
| 205 | + WMI_SET_MAC_ADDRESS_CMDID = 0xF003, | |
| 206 | + WMI_ABORT_SCAN_CMDID = 0xF007, | |
| 207 | + WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, | |
| 208 | + WMI_GET_PMK_CMDID = 0xF048, | |
| 209 | + WMI_SET_PASSPHRASE_CMDID = 0xF049, | |
| 210 | + WMI_SEND_ASSOC_RES_CMDID = 0xF04A, | |
| 211 | + WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xF04B, | |
| 212 | + WMI_MAC_ADDR_REQ_CMDID = 0xF04D, | |
| 213 | + WMI_FW_VER_CMDID = 0xF04E, | |
| 214 | + WMI_PMC_CMDID = 0xF04F, | |
| 200 | 215 | }; |
| 201 | 216 | |
| 202 | 217 | /* WMI_CONNECT_CMDID */ |
| @@ -879,6 +894,14 @@ struct wmi_aoa_meas_cmd { · 676 unmodified lines | ||
| 879 | 894 | __le32 meas_rf_mask; |
| 880 | 895 | } __packed; |
| 881 | 896 | |
| 897 | +/* WMI_SET_MGMT_RETRY_LIMIT_CMDID */ | |
| 898 | +struct wmi_set_mgmt_retry_limit_cmd { | |
| 899 | + /* MAC retransmit limit for mgmt frames */ | |
| 900 | + u8 mgmt_retry_limit; | |
| 901 | + /* alignment to 32b */ | |
| 902 | + u8 reserved[3]; | |
| 903 | +} __packed; | |
| 904 | + | |
| 882 | 905 | enum wmi_tof_burst_duration { |
| 883 | 906 | WMI_TOF_BURST_DURATION_250_USEC = 2, |
| 884 | 907 | WMI_TOF_BURST_DURATION_500_USEC = 3, |
| @@ -942,6 +965,15 @@ struct wmi_tof_channel_info_cmd { · 57 unmodified lines | ||
| 942 | 965 | __le32 channel_info_report_request; |
| 943 | 966 | } __packed; |
| 944 | 967 | |
| 968 | +/* WMI_TOF_SET_TX_RX_OFFSET_CMDID */ | |
| 969 | +struct wmi_tof_set_tx_rx_offset_cmd { | |
| 970 | + /* TX delay offset */ | |
| 971 | + __le32 tx_offset; | |
| 972 | + /* RX delay offset */ | |
| 973 | + __le32 rx_offset; | |
| 974 | + __le32 reserved[2]; | |
| 975 | +} __packed; | |
| 976 | + | |
| 945 | 977 | /* WMI Events |
| 946 | 978 | * List of Events (target to host) |
| 947 | 979 | */ |
| @@ -1035,12 +1067,24 @@ enum wmi_event_id { · 87 unmodified lines | ||
| 1035 | 1067 | WMI_RS_CFG_DONE_EVENTID = 0x1921, |
| 1036 | 1068 | WMI_GET_DETAILED_RS_RES_EVENTID = 0x1922, |
| 1037 | 1069 | WMI_AOA_MEAS_EVENTID = 0x1923, |
| 1070 | + WMI_SET_MGMT_RETRY_LIMIT_EVENTID = 0x1930, | |
| 1071 | + WMI_GET_MGMT_RETRY_LIMIT_EVENTID = 0x1931, | |
| 1038 | 1072 | WMI_TOF_SESSION_END_EVENTID = 0x1991, |
| 1039 | 1073 | WMI_TOF_GET_CAPABILITIES_EVENTID = 0x1992, |
| 1040 | 1074 | WMI_TOF_SET_LCR_EVENTID = 0x1993, |
| 1041 | 1075 | WMI_TOF_SET_LCI_EVENTID = 0x1994, |
| 1042 | 1076 | WMI_TOF_FTM_PER_DEST_RES_EVENTID = 0x1995, |
| 1043 | 1077 | WMI_TOF_CHANNEL_INFO_EVENTID = 0x1996, |
| 1078 | + WMI_TOF_SET_TX_RX_OFFSET_EVENTID = 0x1997, | |
| 1079 | + WMI_TOF_GET_TX_RX_OFFSET_EVENTID = 0x1998, | |
| 1080 | + WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A0, | |
| 1081 | + WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A1, | |
| 1082 | + WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID = 0x19A2, | |
| 1083 | + WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID = 0x19A3, | |
| 1084 | + WMI_SET_RF_SECTOR_ON_DONE_EVENTID = 0x19A4, | |
| 1085 | + WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5, | |
| 1086 | + WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6, | |
| 1087 | + WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7, | |
| 1044 | 1088 | WMI_SET_CHANNEL_EVENTID = 0x9000, |
| 1045 | 1089 | WMI_ASSOC_REQ_EVENTID = 0x9001, |
| 1046 | 1090 | WMI_EAPOL_RX_EVENTID = 0x9002, |
| @@ -1166,6 +1210,7 @@ enum baseband_type { · 119 unmodified lines | ||
| 1166 | 1210 | BASEBAND_SPARROW_M_B0 = 0x05, |
| 1167 | 1211 | BASEBAND_SPARROW_M_C0 = 0x06, |
| 1168 | 1212 | BASEBAND_SPARROW_M_D0 = 0x07, |
| 1213 | + BASEBAND_TALYN_M_A0 = 0x08, | |
| 1169 | 1214 | }; |
| 1170 | 1215 | |
| 1171 | 1216 | /* WMI_GET_BASEBAND_TYPE_EVENTID */ |
| @@ -2070,6 +2115,22 @@ struct wmi_aoa_meas_event { · 898 unmodified lines | ||
| 2070 | 2115 | u8 meas_data[WMI_AOA_MAX_DATA_SIZE]; |
| 2071 | 2116 | } __packed; |
| 2072 | 2117 | |
| 2118 | +/* WMI_SET_MGMT_RETRY_LIMIT_EVENTID */ | |
| 2119 | +struct wmi_set_mgmt_retry_limit_event { | |
| 2120 | + /* enum wmi_fw_status */ | |
| 2121 | + u8 status; | |
| 2122 | + /* alignment to 32b */ | |
| 2123 | + u8 reserved[3]; | |
| 2124 | +} __packed; | |
| 2125 | + | |
| 2126 | +/* WMI_GET_MGMT_RETRY_LIMIT_EVENTID */ | |
| 2127 | +struct wmi_get_mgmt_retry_limit_event { | |
| 2128 | + /* MAC retransmit limit for mgmt frames */ | |
| 2129 | + u8 mgmt_retry_limit; | |
| 2130 | + /* alignment to 32b */ | |
| 2131 | + u8 reserved[3]; | |
| 2132 | +} __packed; | |
| 2133 | + | |
| 2073 | 2134 | /* WMI_TOF_GET_CAPABILITIES_EVENTID */ |
| 2074 | 2135 | struct wmi_tof_get_capabilities_event { |
| 2075 | 2136 | u8 ftm_capability; |
| @@ -2184,4 +2245,283 @@ struct wmi_tof_channel_info_event { · 108 unmodified lines | ||
| 2184 | 2245 | u8 report[0]; |
| 2185 | 2246 | } __packed; |
| 2186 | 2247 | |
| 2248 | +/* WMI_TOF_SET_TX_RX_OFFSET_EVENTID */ | |
| 2249 | +struct wmi_tof_set_tx_rx_offset_event { | |
| 2250 | + /* enum wmi_fw_status */ | |
| 2251 | + u8 status; | |
| 2252 | + u8 reserved[3]; | |
| 2253 | +} __packed; | |
| 2254 | + | |
| 2255 | +/* WMI_TOF_GET_TX_RX_OFFSET_EVENTID */ | |
| 2256 | +struct wmi_tof_get_tx_rx_offset_event { | |
| 2257 | + /* enum wmi_fw_status */ | |
| 2258 | + u8 status; | |
| 2259 | + u8 reserved1[3]; | |
| 2260 | + /* TX delay offset */ | |
| 2261 | + __le32 tx_offset; | |
| 2262 | + /* RX delay offset */ | |
| 2263 | + __le32 rx_offset; | |
| 2264 | + __le32 reserved2[2]; | |
| 2265 | +} __packed; | |
| 2266 | + | |
| 2267 | +/* Result status codes for WMI commands */ | |
| 2268 | +enum wmi_rf_sector_status { | |
| 2269 | + WMI_RF_SECTOR_STATUS_SUCCESS = 0x00, | |
| 2270 | + WMI_RF_SECTOR_STATUS_BAD_PARAMETERS_ERROR = 0x01, | |
| 2271 | + WMI_RF_SECTOR_STATUS_BUSY_ERROR = 0x02, | |
| 2272 | + WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR = 0x03, | |
| 2273 | +}; | |
| 2274 | + | |
| 2275 | +/* Types of the RF sector (TX,RX) */ | |
| 2276 | +enum wmi_rf_sector_type { | |
| 2277 | + WMI_RF_SECTOR_TYPE_RX = 0x00, | |
| 2278 | + WMI_RF_SECTOR_TYPE_TX = 0x01, | |
| 2279 | +}; | |
| 2280 | + | |
| 2281 | +/* Content of RF Sector (six 32-bits registers) */ | |
| 2282 | +struct wmi_rf_sector_info { | |
| 2283 | + /* Phase values for RF Chains[15-0] (2bits per RF chain) */ | |
| 2284 | + __le32 psh_hi; | |
| 2285 | + /* Phase values for RF Chains[31-16] (2bits per RF chain) */ | |
| 2286 | + __le32 psh_lo; | |
| 2287 | + /* ETYPE Bit0 for all RF chains[31-0] - bit0 of Edge amplifier gain | |
| 2288 | + * index | |
| 2289 | + */ | |
| 2290 | + __le32 etype0; | |
| 2291 | + /* ETYPE Bit1 for all RF chains[31-0] - bit1 of Edge amplifier gain | |
| 2292 | + * index | |
| 2293 | + */ | |
| 2294 | + __le32 etype1; | |
| 2295 | + /* ETYPE Bit2 for all RF chains[31-0] - bit2 of Edge amplifier gain | |
| 2296 | + * index | |
| 2297 | + */ | |
| 2298 | + __le32 etype2; | |
| 2299 | + /* D-Type values (3bits each) for 8 Distribution amplifiers + X16 | |
| 2300 | + * switch bits | |
| 2301 | + */ | |
| 2302 | + __le32 dtype_swch_off; | |
| 2303 | +} __packed; | |
| 2304 | + | |
| 2305 | +#define WMI_INVALID_RF_SECTOR_INDEX (0xFFFF) | |
| 2306 | +#define WMI_MAX_RF_MODULES_NUM (8) | |
| 2307 | + | |
| 2308 | +/* WMI_GET_RF_SECTOR_PARAMS_CMD */ | |
| 2309 | +struct wmi_get_rf_sector_params_cmd { | |
| 2310 | + /* Sector number to be retrieved */ | |
| 2311 | + __le16 sector_idx; | |
| 2312 | + /* enum wmi_rf_sector_type - type of requested RF sector */ | |
| 2313 | + u8 sector_type; | |
| 2314 | + /* bitmask vector specifying destination RF modules */ | |
| 2315 | + u8 rf_modules_vec; | |
| 2316 | +} __packed; | |
| 2317 | + | |
| 2318 | +/* \WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT */ | |
| 2319 | +struct wmi_get_rf_sector_params_done_event { | |
| 2320 | + /* result status of WMI_GET_RF_SECTOR_PARAMS_CMD (enum | |
| 2321 | + * wmi_rf_sector_status) | |
| 2322 | + */ | |
| 2323 | + u8 status; | |
| 2324 | + /* align next field to U64 boundary */ | |
| 2325 | + u8 reserved[7]; | |
| 2326 | + /* TSF timestamp when RF sectors where retrieved */ | |
| 2327 | + __le64 tsf; | |
| 2328 | + /* Content of RF sector retrieved from each RF module */ | |
| 2329 | + struct wmi_rf_sector_info sectors_info[WMI_MAX_RF_MODULES_NUM]; | |
| 2330 | +} __packed; | |
| 2331 | + | |
| 2332 | +/* WMI_SET_RF_SECTOR_PARAMS_CMD */ | |
| 2333 | +struct wmi_set_rf_sector_params_cmd { | |
| 2334 | + /* Sector number to be retrieved */ | |
| 2335 | + __le16 sector_idx; | |
| 2336 | + /* enum wmi_rf_sector_type - type of requested RF sector */ | |
| 2337 | + u8 sector_type; | |
| 2338 | + /* bitmask vector specifying destination RF modules */ | |
| 2339 | + u8 rf_modules_vec; | |
| 2340 | + /* Content of RF sector to be written to each RF module */ | |
| 2341 | + struct wmi_rf_sector_info sectors_info[WMI_MAX_RF_MODULES_NUM]; | |
| 2342 | +} __packed; | |
| 2343 | + | |
| 2344 | +/* \WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT */ | |
| 2345 | +struct wmi_set_rf_sector_params_done_event { | |
| 2346 | + /* result status of WMI_SET_RF_SECTOR_PARAMS_CMD (enum | |
| 2347 | + * wmi_rf_sector_status) | |
| 2348 | + */ | |
| 2349 | + u8 status; | |
| 2350 | +} __packed; | |
| 2351 | + | |
| 2352 | +/* WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD - Get RF sector index selected by | |
| 2353 | + * TXSS/BRP for communication with specified CID | |
| 2354 | + */ | |
| 2355 | +struct wmi_get_selected_rf_sector_index_cmd { | |
| 2356 | + /* Connection/Station ID in [0:7] range */ | |
| 2357 | + u8 cid; | |
| 2358 | + /* type of requested RF sector (enum wmi_rf_sector_type) */ | |
| 2359 | + u8 sector_type; | |
| 2360 | + /* align to U32 boundary */ | |
| 2361 | + u8 reserved[2]; | |
| 2362 | +} __packed; | |
| 2363 | + | |
| 2364 | +/* \WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT - Returns retrieved RF sector | |
| 2365 | + * index selected by TXSS/BRP for communication with specified CID | |
| 2366 | + */ | |
| 2367 | +struct wmi_get_selected_rf_sector_index_done_event { | |
| 2368 | + /* Retrieved sector index selected in TXSS (for TX sector request) or | |
| 2369 | + * BRP (for RX sector request) | |
| 2370 | + */ | |
| 2371 | + __le16 sector_idx; | |
| 2372 | + /* result status of WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD (enum | |
| 2373 | + * wmi_rf_sector_status) | |
| 2374 | + */ | |
| 2375 | + u8 status; | |
| 2376 | + /* align next field to U64 boundary */ | |
| 2377 | + u8 reserved[5]; | |
| 2378 | + /* TSF timestamp when result was retrieved */ | |
| 2379 | + __le64 tsf; | |
| 2380 | +} __packed; | |
| 2381 | + | |
| 2382 | +/* WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD - Force RF sector index for | |
| 2383 | + * communication with specified CID. Assumes that TXSS/BRP is disabled by | |
| 2384 | + * other command | |
| 2385 | + */ | |
| 2386 | +struct wmi_set_selected_rf_sector_index_cmd { | |
| 2387 | + /* Connection/Station ID in [0:7] range */ | |
| 2388 | + u8 cid; | |
| 2389 | + /* type of requested RF sector (enum wmi_rf_sector_type) */ | |
| 2390 | + u8 sector_type; | |
| 2391 | + /* Forced sector index */ | |
| 2392 | + __le16 sector_idx; | |
| 2393 | +} __packed; | |
| 2394 | + | |
| 2395 | +/* \WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT - Success/Fail status for | |
| 2396 | + * WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD | |
| 2397 | + */ | |
| 2398 | +struct wmi_set_selected_rf_sector_index_done_event { | |
| 2399 | + /* result status of WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD (enum | |
| 2400 | + * wmi_rf_sector_status) | |
| 2401 | + */ | |
| 2402 | + u8 status; | |
| 2403 | + /* align to U32 boundary */ | |
| 2404 | + u8 reserved[3]; | |
| 2405 | +} __packed; | |
| 2406 | + | |
| 2407 | +/* WMI_SET_RF_SECTOR_ON_CMD - Activates specified sector for specified rf | |
| 2408 | + * modules | |
| 2409 | + */ | |
| 2410 | +struct wmi_set_rf_sector_on_cmd { | |
| 2411 | + /* Sector index to be activated */ | |
| 2412 | + __le16 sector_idx; | |
| 2413 | + /* type of requested RF sector (enum wmi_rf_sector_type) */ | |
| 2414 | + u8 sector_type; | |
| 2415 | + /* bitmask vector specifying destination RF modules */ | |
| 2416 | + u8 rf_modules_vec; | |
| 2417 | +} __packed; | |
| 2418 | + | |
| 2419 | +/* \WMI_SET_RF_SECTOR_ON_DONE_EVENT - Success/Fail status for | |
| 2420 | + * WMI_SET_RF_SECTOR_ON_CMD | |
| 2421 | + */ | |
| 2422 | +struct wmi_set_rf_sector_on_done_event { | |
| 2423 | + /* result status of WMI_SET_RF_SECTOR_ON_CMD (enum | |
| 2424 | + * wmi_rf_sector_status) | |
| 2425 | + */ | |
| 2426 | + u8 status; | |
| 2427 | + /* align to U32 boundary */ | |
| 2428 | + u8 reserved[3]; | |
| 2429 | +} __packed; | |
| 2430 | + | |
| 2431 | +enum wmi_sector_sweep_type { | |
| 2432 | + WMI_SECTOR_SWEEP_TYPE_TXSS = 0x00, | |
| 2433 | + WMI_SECTOR_SWEEP_TYPE_BCON = 0x01, | |
| 2434 | + WMI_SECTOR_SWEEP_TYPE_TXSS_AND_BCON = 0x02, | |
| 2435 | + WMI_SECTOR_SWEEP_TYPE_NUM = 0x03, | |
| 2436 | +}; | |
| 2437 | + | |
| 2438 | +/* WMI_PRIO_TX_SECTORS_ORDER_CMDID | |
| 2439 | + * | |
| 2440 | + * Set the order of TX sectors in TXSS and/or Beacon(AP). | |
| 2441 | + * | |
| 2442 | + * Returned event: | |
| 2443 | + * - WMI_PRIO_TX_SECTORS_ORDER_EVENTID | |
| 2444 | + */ | |
| 2445 | +struct wmi_prio_tx_sectors_order_cmd { | |
| 2446 | + /* tx sectors order to be applied, 0xFF for end of array */ | |
| 2447 | + u8 tx_sectors_priority_array[MAX_NUM_OF_SECTORS]; | |
| 2448 | + /* enum wmi_sector_sweep_type, TXSS and/or Beacon */ | |
| 2449 | + u8 sector_sweep_type; | |
| 2450 | + /* needed only for TXSS configuration */ | |
| 2451 | + u8 cid; | |
| 2452 | + /* alignment to 32b */ | |
| 2453 | + u8 reserved[2]; | |
| 2454 | +} __packed; | |
| 2455 | + | |
| 2456 | +/* completion status codes */ | |
| 2457 | +enum wmi_prio_tx_sectors_cmd_status { | |
| 2458 | + WMI_PRIO_TX_SECT_CMD_STATUS_SUCCESS = 0x00, | |
| 2459 | + WMI_PRIO_TX_SECT_CMD_STATUS_BAD_PARAM = 0x01, | |
| 2460 | + /* other error */ | |
| 2461 | + WMI_PRIO_TX_SECT_CMD_STATUS_ERROR = 0x02, | |
| 2462 | +}; | |
| 2463 | + | |
| 2464 | +/* WMI_PRIO_TX_SECTORS_ORDER_EVENTID */ | |
| 2465 | +struct wmi_prio_tx_sectors_order_event { | |
| 2466 | + /* enum wmi_prio_tx_sectors_cmd_status */ | |
| 2467 | + u8 status; | |
| 2468 | + /* alignment to 32b */ | |
| 2469 | + u8 reserved[3]; | |
| 2470 | +} __packed; | |
| 2471 | + | |
| 2472 | +struct wmi_prio_tx_sectors_num_cmd { | |
| 2473 | + /* [0-128], 0 = No changes */ | |
| 2474 | + u8 beacon_number_of_sectors; | |
| 2475 | + /* [0-128], 0 = No changes */ | |
| 2476 | + u8 txss_number_of_sectors; | |
| 2477 | + /* [0-8] needed only for TXSS configuration */ | |
| 2478 | + u8 cid; | |
| 2479 | +} __packed; | |
| 2480 | + | |
| 2481 | +/* WMI_PRIO_TX_SECTORS_NUMBER_CMDID | |
| 2482 | + * | |
| 2483 | + * Set the number of active sectors in TXSS and/or Beacon. | |
| 2484 | + * | |
| 2485 | + * Returned event: | |
| 2486 | + * - WMI_PRIO_TX_SECTORS_NUMBER_EVENTID | |
| 2487 | + */ | |
| 2488 | +struct wmi_prio_tx_sectors_number_cmd { | |
| 2489 | + struct wmi_prio_tx_sectors_num_cmd active_sectors_num; | |
| 2490 | + /* alignment to 32b */ | |
| 2491 | + u8 reserved; | |
| 2492 | +} __packed; | |
| 2493 | + | |
| 2494 | +/* WMI_PRIO_TX_SECTORS_NUMBER_EVENTID */ | |
| 2495 | +struct wmi_prio_tx_sectors_number_event { | |
| 2496 | + /* enum wmi_prio_tx_sectors_cmd_status */ | |
| 2497 | + u8 status; | |
| 2498 | + /* alignment to 32b */ | |
| 2499 | + u8 reserved[3]; | |
| 2500 | +} __packed; | |
| 2501 | + | |
| 2502 | +/* WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID | |
| 2503 | + * | |
| 2504 | + * Set default sectors order and number (hard coded in board file) | |
| 2505 | + * in TXSS and/or Beacon. | |
| 2506 | + * | |
| 2507 | + * Returned event: | |
| 2508 | + * - WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID | |
| 2509 | + */ | |
| 2510 | +struct wmi_prio_tx_sectors_set_default_cfg_cmd { | |
| 2511 | + /* enum wmi_sector_sweep_type, TXSS and/or Beacon */ | |
| 2512 | + u8 sector_sweep_type; | |
| 2513 | + /* needed only for TXSS configuration */ | |
| 2514 | + u8 cid; | |
| 2515 | + /* alignment to 32b */ | |
| 2516 | + u8 reserved[2]; | |
| 2517 | +} __packed; | |
| 2518 | + | |
| 2519 | +/* WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID */ | |
| 2520 | +struct wmi_prio_tx_sectors_set_default_cfg_event { | |
| 2521 | + /* enum wmi_prio_tx_sectors_cmd_status */ | |
| 2522 | + u8 status; | |
| 2523 | + /* alignment to 32b */ | |
| 2524 | + u8 reserved[3]; | |
| 2525 | +} __packed; | |
| 2526 | + | |
| 2187 | 2527 | #endif /* __WILOCITY_WMI_H__ */ |
| @@ -35,7 +35,8 @@ brcmfmac-objs += \ · 34 unmodified lines | ||
| 35 | 35 | firmware.o \ |
| 36 | 36 | feature.o \ |
| 37 | 37 | btcoex.o \ |
| 38 | − vendor.o | |
| 38 | + vendor.o \ | |
| 39 | + pno.o | |
| 39 | 40 | brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \ |
| 40 | 41 | bcdc.o |
| 41 | 42 | brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \ |
| @@ -22,10 +22,12 @@ · 21 unmodified lines | ||
| 22 | 22 | /* IDs of the 6 default common rings of msgbuf protocol */ |
| 23 | 23 | #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0 |
| 24 | 24 | #define BRCMF_H2D_MSGRING_RXPOST_SUBMIT 1 |
| 25 | +#define BRCMF_H2D_MSGRING_FLOWRING_IDSTART 2 | |
| 25 | 26 | #define BRCMF_D2H_MSGRING_CONTROL_COMPLETE 2 |
| 26 | 27 | #define BRCMF_D2H_MSGRING_TX_COMPLETE 3 |
| 27 | 28 | #define BRCMF_D2H_MSGRING_RX_COMPLETE 4 |
| 28 | 29 | |
| 30 | + | |
| 29 | 31 | #define BRCMF_NROF_H2D_COMMON_MSGRINGS 2 |
| 30 | 32 | #define BRCMF_NROF_D2H_COMMON_MSGRINGS 3 |
| 31 | 33 | #define BRCMF_NROF_COMMON_MSGRINGS (BRCMF_NROF_H2D_COMMON_MSGRINGS + \ |
| @@ -95,14 +97,18 @@ struct brcmf_bus_ops { · 63 unmodified lines | ||
| 95 | 97 | * @flowrings: commonrings which are dynamically created and destroyed for data. |
| 96 | 98 | * @rx_dataoffset: if set then all rx data has this this offset. |
| 97 | 99 | * @max_rxbufpost: maximum number of buffers to post for rx. |
| 98 | − * @nrof_flowrings: number of flowrings. | |
| 100 | + * @max_flowrings: maximum number of tx flow rings supported. | |
| 101 | + * @max_submissionrings: maximum number of submission rings(h2d) supported. | |
| 102 | + * @max_completionrings: maximum number of completion rings(d2h) supported. | |
| 99 | 103 | */ |
| 100 | 104 | struct brcmf_bus_msgbuf { |
| 101 | 105 | struct brcmf_commonring *commonrings[BRCMF_NROF_COMMON_MSGRINGS]; |
| 102 | 106 | struct brcmf_commonring **flowrings; |
| 103 | 107 | u32 rx_dataoffset; |
| 104 | 108 | u32 max_rxbufpost; |
| 105 | − u32 nrof_flowrings; | |
| 109 | + u16 max_flowrings; | |
| 110 | + u16 max_submissionrings; | |
| 111 | + u16 max_completionrings; | |
| 106 | 112 | }; |
| 107 | 113 | |
| 108 | 114 | |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include "fwil_types.h" |
| 33 | 33 | #include "p2p.h" |
| 34 | 34 | #include "btcoex.h" |
| 35 | +#include "pno.h" | |
| 35 | 36 | #include "cfg80211.h" |
| 36 | 37 | #include "feature.h" |
| 37 | 38 | #include "fwil.h" |
| @@ -41,16 +42,6 @@ · 3 unmodified lines | ||
| 41 | 42 | #include "common.h" |
| 42 | 43 | |
| 43 | 44 | #define BRCMF_SCAN_IE_LEN_MAX 2048 |
| 44 | −#define BRCMF_PNO_VERSION 2 | |
| 45 | −#define BRCMF_PNO_TIME 30 | |
| 46 | −#define BRCMF_PNO_REPEAT 4 | |
| 47 | −#define BRCMF_PNO_FREQ_EXPO_MAX 3 | |
| 48 | −#define BRCMF_PNO_MAX_PFN_COUNT 16 | |
| 49 | −#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6 | |
| 50 | −#define BRCMF_PNO_HIDDEN_BIT 2 | |
| 51 | −#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF | |
| 52 | −#define BRCMF_PNO_SCAN_COMPLETE 1 | |
| 53 | −#define BRCMF_PNO_SCAN_INCOMPLETE 0 | |
| 54 | 45 | |
| 55 | 46 | #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ |
| 56 | 47 | #define WPA_OUI_TYPE 1 |
| @@ -768,12 +759,12 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, · 711 unmodified lines | ||
| 768 | 759 | brcmf_scan_config_mpc(ifp, 1); |
| 769 | 760 | |
| 770 | 761 | /* |
| 771 | − * e-scan can be initiated by scheduled scan | |
| 762 | + * e-scan can be initiated internally | |
| 772 | 763 | * which takes precedence. |
| 773 | 764 | */ |
| 774 | − if (cfg->sched_escan) { | |
| 765 | + if (cfg->internal_escan) { | |
| 775 | 766 | brcmf_dbg(SCAN, "scheduled scan completed\n"); |
| 776 | − cfg->sched_escan = false; | |
| 767 | + cfg->internal_escan = false; | |
| 777 | 768 | if (!aborted) |
| 778 | 769 | cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); |
| 779 | 770 | } else if (scan_request) { |
| @@ -1091,9 +1082,9 @@ exit: · 311 unmodified lines | ||
| 1091 | 1082 | } |
| 1092 | 1083 | |
| 1093 | 1084 | static s32 |
| 1094 | −brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, | |
| 1095 | − struct brcmf_if *ifp, struct cfg80211_scan_request *request) | |
| 1085 | +brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request) | |
| 1096 | 1086 | { |
| 1087 | + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | |
| 1097 | 1088 | s32 err; |
| 1098 | 1089 | u32 passive_scan; |
| 1099 | 1090 | struct brcmf_scan_results *results; |
| @@ -1101,7 +1092,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, · 1 unmodified line | ||
| 1101 | 1092 | |
| 1102 | 1093 | brcmf_dbg(SCAN, "Enter\n"); |
| 1103 | 1094 | escan->ifp = ifp; |
| 1104 | − escan->wiphy = wiphy; | |
| 1095 | + escan->wiphy = cfg->wiphy; | |
| 1105 | 1096 | escan->escan_state = WL_ESCAN_STATE_SCANNING; |
| 1106 | 1097 | passive_scan = cfg->active_scan ? 0 : 1; |
| 1107 | 1098 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN, |
| @@ -1181,7 +1172,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, · 73 unmodified lines | ||
| 1181 | 1172 | if (err) |
| 1182 | 1173 | goto scan_out; |
| 1183 | 1174 | |
| 1184 | − err = brcmf_do_escan(cfg, wiphy, vif->ifp, request); | |
| 1175 | + err = brcmf_do_escan(vif->ifp, request); | |
| 1185 | 1176 | if (err) |
| 1186 | 1177 | goto scan_out; |
| 1187 | 1178 | } else { |
| @@ -3024,7 +3015,7 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) · 1836 unmodified lines | ||
| 3024 | 3015 | struct escan_info *escan = &cfg->escan_info; |
| 3025 | 3016 | |
| 3026 | 3017 | set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); |
| 3027 | − if (cfg->scan_request) { | |
| 3018 | + if (cfg->internal_escan || cfg->scan_request) { | |
| 3028 | 3019 | escan->escan_state = WL_ESCAN_STATE_IDLE; |
| 3029 | 3020 | brcmf_notify_escan_complete(cfg, escan->ifp, true, true); |
| 3030 | 3021 | } |
| @@ -3047,7 +3038,7 @@ static void brcmf_escan_timeout(unsigned long data) · 16 unmodified lines | ||
| 3047 | 3038 | struct brcmf_cfg80211_info *cfg = |
| 3048 | 3039 | (struct brcmf_cfg80211_info *)data; |
| 3049 | 3040 | |
| 3050 | − if (cfg->scan_request) { | |
| 3041 | + if (cfg->internal_escan || cfg->scan_request) { | |
| 3051 | 3042 | brcmf_err("timer expired\n"); |
| 3052 | 3043 | schedule_work(&cfg->escan_timeout_work); |
| 3053 | 3044 | } |
| @@ -3130,7 +3121,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, · 76 unmodified lines | ||
| 3130 | 3121 | if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le)) |
| 3131 | 3122 | goto exit; |
| 3132 | 3123 | |
| 3133 | − if (!cfg->scan_request) { | |
| 3124 | + if (!cfg->internal_escan && !cfg->scan_request) { | |
| 3134 | 3125 | brcmf_dbg(SCAN, "result without cfg80211 request\n"); |
| 3135 | 3126 | goto exit; |
| 3136 | 3127 | } |
| @@ -3176,7 +3167,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, · 39 unmodified lines | ||
| 3176 | 3167 | cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; |
| 3177 | 3168 | if (brcmf_p2p_scan_finding_common_channel(cfg, NULL)) |
| 3178 | 3169 | goto exit; |
| 3179 | − if (cfg->scan_request) { | |
| 3170 | + if (cfg->internal_escan || cfg->scan_request) { | |
| 3180 | 3171 | brcmf_inform_bss(cfg); |
| 3181 | 3172 | aborted = status != BRCMF_E_STATUS_SUCCESS; |
| 3182 | 3173 | brcmf_notify_escan_complete(cfg, ifp, aborted, false); |
| @@ -3201,6 +3192,95 @@ static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) · 18 unmodified lines | ||
| 3201 | 3192 | brcmf_cfg80211_escan_timeout_worker); |
| 3202 | 3193 | } |
| 3203 | 3194 | |
| 3195 | +static struct cfg80211_scan_request * | |
| 3196 | +brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) { | |
| 3197 | + struct cfg80211_scan_request *req; | |
| 3198 | + size_t req_size; | |
| 3199 | + | |
| 3200 | + req_size = sizeof(*req) + | |
| 3201 | + n_netinfo * sizeof(req->channels[0]) + | |
| 3202 | + n_netinfo * sizeof(*req->ssids); | |
| 3203 | + | |
| 3204 | + req = kzalloc(req_size, GFP_KERNEL); | |
| 3205 | + if (req) { | |
| 3206 | + req->wiphy = wiphy; | |
| 3207 | + req->ssids = (void *)(&req->channels[0]) + | |
| 3208 | + n_netinfo * sizeof(req->channels[0]); | |
| 3209 | + } | |
| 3210 | + return req; | |
| 3211 | +} | |
| 3212 | + | |
| 3213 | +static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req, | |
| 3214 | + u8 *ssid, u8 ssid_len, u8 channel) | |
| 3215 | +{ | |
| 3216 | + struct ieee80211_channel *chan; | |
| 3217 | + enum nl80211_band band; | |
| 3218 | + int freq; | |
| 3219 | + | |
| 3220 | + if (channel <= CH_MAX_2G_CHANNEL) | |
| 3221 | + band = NL80211_BAND_2GHZ; | |
| 3222 | + else | |
| 3223 | + band = NL80211_BAND_5GHZ; | |
| 3224 | + | |
| 3225 | + freq = ieee80211_channel_to_frequency(channel, band); | |
| 3226 | + if (!freq) | |
| 3227 | + return -EINVAL; | |
| 3228 | + | |
| 3229 | + chan = ieee80211_get_channel(req->wiphy, freq); | |
| 3230 | + if (!chan) | |
| 3231 | + return -EINVAL; | |
| 3232 | + | |
| 3233 | + req->channels[req->n_channels++] = chan; | |
| 3234 | + memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len); | |
| 3235 | + req->ssids[req->n_ssids++].ssid_len = ssid_len; | |
| 3236 | + | |
| 3237 | + return 0; | |
| 3238 | +} | |
| 3239 | + | |
| 3240 | +static int brcmf_start_internal_escan(struct brcmf_if *ifp, | |
| 3241 | + struct cfg80211_scan_request *request) | |
| 3242 | +{ | |
| 3243 | + struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | |
| 3244 | + int err; | |
| 3245 | + | |
| 3246 | + if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { | |
| 3247 | + /* Abort any on-going scan */ | |
| 3248 | + brcmf_abort_scanning(cfg); | |
| 3249 | + } | |
| 3250 | + | |
| 3251 | + set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); | |
| 3252 | + cfg->escan_info.run = brcmf_run_escan; | |
| 3253 | + err = brcmf_do_escan(ifp, request); | |
| 3254 | + if (err) { | |
| 3255 | + clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); | |
| 3256 | + return err; | |
| 3257 | + } | |
| 3258 | + cfg->internal_escan = true; | |
| 3259 | + return 0; | |
| 3260 | +} | |
| 3261 | + | |
| 3262 | +static struct brcmf_pno_net_info_le * | |
| 3263 | +brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1) | |
| 3264 | +{ | |
| 3265 | + struct brcmf_pno_scanresults_v2_le *pfn_v2; | |
| 3266 | + struct brcmf_pno_net_info_le *netinfo; | |
| 3267 | + | |
| 3268 | + switch (pfn_v1->version) { | |
| 3269 | + default: | |
| 3270 | + WARN_ON(1); | |
| 3271 | + /* fall-thru */ | |
| 3272 | + case cpu_to_le32(1): | |
| 3273 | + netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1); | |
| 3274 | + break; | |
| 3275 | + case cpu_to_le32(2): | |
| 3276 | + pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1; | |
| 3277 | + netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1); | |
| 3278 | + break; | |
| 3279 | + } | |
| 3280 | + | |
| 3281 | + return netinfo; | |
| 3282 | +} | |
| 3283 | + | |
| 3204 | 3284 | /* PFN result doesn't have all the info which are required by the supplicant |
| 3205 | 3285 | * (For e.g IEs) Do a target Escan so that sched scan results are reported |
| 3206 | 3286 | * via wl_inform_single_bss in the required format. Escan does require the |
| @@ -3214,12 +3294,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, · 7 unmodified lines | ||
| 3214 | 3294 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; |
| 3215 | 3295 | struct brcmf_pno_net_info_le *netinfo, *netinfo_start; |
| 3216 | 3296 | struct cfg80211_scan_request *request = NULL; |
| 3217 | − struct cfg80211_ssid *ssid = NULL; | |
| 3218 | − struct ieee80211_channel *channel = NULL; | |
| 3219 | 3297 | struct wiphy *wiphy = cfg_to_wiphy(cfg); |
| 3220 | − int err = 0; | |
| 3221 | − int channel_req = 0; | |
| 3222 | − int band = 0; | |
| 3298 | + int i, err = 0; | |
| 3223 | 3299 | struct brcmf_pno_scanresults_le *pfn_result; |
| 3224 | 3300 | u32 result_count; |
| 3225 | 3301 | u32 status; |
| @@ -3245,254 +3321,86 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, · 19 unmodified lines | ||
| 3245 | 3321 | */ |
| 3246 | 3322 | WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE); |
| 3247 | 3323 | brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count); |
| 3248 | − if (result_count > 0) { | |
| 3249 | − int i; | |
| 3250 | − | |
| 3251 | − request = kzalloc(sizeof(*request), GFP_KERNEL); | |
| 3252 | − ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL); | |
| 3253 | − channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL); | |
| 3254 | − if (!request || !ssid || !channel) { | |
| 3255 | − err = -ENOMEM; | |
| 3256 | − goto out_err; | |
| 3257 | − } | |
| 3258 | − | |
| 3259 | − request->wiphy = wiphy; | |
| 3260 | − data += sizeof(struct brcmf_pno_scanresults_le); | |
| 3261 | − netinfo_start = (struct brcmf_pno_net_info_le *)data; | |
| 3262 | − | |
| 3263 | − for (i = 0; i < result_count; i++) { | |
| 3264 | − netinfo = &netinfo_start[i]; | |
| 3265 | − if (!netinfo) { | |
| 3266 | − brcmf_err("Invalid netinfo ptr. index: %d\n", | |
| 3267 | − i); | |
| 3268 | − err = -EINVAL; | |
| 3269 | − goto out_err; | |
| 3270 | − } | |
| 3271 | − | |
| 3272 | − brcmf_dbg(SCAN, "SSID:%s Channel:%d\n", | |
| 3273 | − netinfo->SSID, netinfo->channel); | |
| 3274 | − memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len); | |
| 3275 | − ssid[i].ssid_len = netinfo->SSID_len; | |
| 3276 | − request->n_ssids++; | |
| 3277 | − | |
| 3278 | − channel_req = netinfo->channel; | |
| 3279 | − if (channel_req <= CH_MAX_2G_CHANNEL) | |
| 3280 | − band = NL80211_BAND_2GHZ; | |
| 3281 | − else | |
| 3282 | − band = NL80211_BAND_5GHZ; | |
| 3283 | − channel[i].center_freq = | |
| 3284 | − ieee80211_channel_to_frequency(channel_req, | |
| 3285 | − band); | |
| 3286 | − channel[i].band = band; | |
| 3287 | − channel[i].flags |= IEEE80211_CHAN_NO_HT40; | |
| 3288 | − request->channels[i] = &channel[i]; | |
| 3289 | − request->n_channels++; | |
| 3290 | − } | |
| 3291 | − | |
| 3292 | − /* assign parsed ssid array */ | |
| 3293 | − if (request->n_ssids) | |
| 3294 | − request->ssids = &ssid[0]; | |
| 3295 | − | |
| 3296 | − if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { | |
| 3297 | − /* Abort any on-going scan */ | |
| 3298 | − brcmf_abort_scanning(cfg); | |
| 3299 | − } | |
| 3300 | − | |
| 3301 | − set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); | |
| 3302 | − cfg->escan_info.run = brcmf_run_escan; | |
| 3303 | − err = brcmf_do_escan(cfg, wiphy, ifp, request); | |
| 3304 | − if (err) { | |
| 3305 | − clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); | |
| 3306 | − goto out_err; | |
| 3307 | − } | |
| 3308 | − cfg->sched_escan = true; | |
| 3309 | − cfg->scan_request = request; | |
| 3310 | − } else { | |
| 3324 | + if (!result_count) { | |
| 3311 | 3325 | brcmf_err("FALSE PNO Event. (pfn_count == 0)\n"); |
| 3312 | 3326 | goto out_err; |
| 3313 | 3327 | } |
| 3314 | − | |
| 3315 | − kfree(ssid); | |
| 3316 | − kfree(channel); | |
| 3317 | − kfree(request); | |
| 3318 | − return 0; | |
| 3319 | − | |
| 3320 | −out_err: | |
| 3321 | − kfree(ssid); | |
| 3322 | − kfree(channel); | |
| 3323 | − kfree(request); | |
| 3324 | − cfg80211_sched_scan_stopped(wiphy); | |
| 3325 | − return err; | |
| 3326 | −} | |
| 3327 | − | |
| 3328 | −static int brcmf_dev_pno_clean(struct net_device *ndev) | |
| 3329 | −{ | |
| 3330 | − int ret; | |
| 3331 | − | |
| 3332 | − /* Disable pfn */ | |
| 3333 | − ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0); | |
| 3334 | − if (ret == 0) { | |
| 3335 | − /* clear pfn */ | |
| 3336 | − ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear", | |
| 3337 | − NULL, 0); | |
| 3338 | − } | |
| 3339 | − if (ret < 0) | |
| 3340 | − brcmf_err("failed code %d\n", ret); | |
| 3341 | − | |
| 3342 | − return ret; | |
| 3343 | −} | |
| 3344 | − | |
| 3345 | −static int brcmf_dev_pno_config(struct brcmf_if *ifp, | |
| 3346 | − struct cfg80211_sched_scan_request *request) | |
| 3347 | −{ | |
| 3348 | − struct brcmf_pno_param_le pfn_param; | |
| 3349 | − struct brcmf_pno_macaddr_le pfn_mac; | |
| 3350 | − s32 err; | |
| 3351 | − u8 *mac_mask; | |
| 3352 | − int i; | |
| 3353 | − | |
| 3354 | − memset(&pfn_param, 0, sizeof(pfn_param)); | |
| 3355 | − pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION); | |
| 3356 | − | |
| 3357 | − /* set extra pno params */ | |
| 3358 | − pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); | |
| 3359 | − pfn_param.repeat = BRCMF_PNO_REPEAT; | |
| 3360 | − pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; | |
| 3361 | − | |
| 3362 | − /* set up pno scan fr */ | |
| 3363 | − pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME); | |
| 3364 | − | |
| 3365 | − err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param, | |
| 3366 | − sizeof(pfn_param)); | |
| 3367 | − if (err) { | |
| 3368 | − brcmf_err("pfn_set failed, err=%d\n", err); | |
| 3369 | − return err; | |
| 3328 | + request = brcmf_alloc_internal_escan_request(wiphy, | |
| 3329 | + result_count); | |
| 3330 | + if (!request) { | |
| 3331 | + err = -ENOMEM; | |
| 3332 | + goto out_err; | |
| 3370 | 3333 | } |
| 3371 | 3334 | |
| 3372 | − /* Find out if mac randomization should be turned on */ | |
| 3373 | − if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) | |
| 3374 | − return 0; | |
| 3335 | + data += sizeof(struct brcmf_pno_scanresults_le); | |
| 3336 | + netinfo_start = brcmf_get_netinfo_array(pfn_result); | |
| 3375 | 3337 | |
| 3376 | − pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; | |
| 3377 | − pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC; | |
| 3338 | + for (i = 0; i < result_count; i++) { | |
| 3339 | + netinfo = &netinfo_start[i]; | |
| 3340 | + if (!netinfo) { | |
| 3341 | + brcmf_err("Invalid netinfo ptr. index: %d\n", | |
| 3342 | + i); | |
| 3343 | + err = -EINVAL; | |
| 3344 | + goto out_err; | |
| 3345 | + } | |
| 3378 | 3346 | |
| 3379 | − memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN); | |
| 3380 | − mac_mask = request->mac_addr_mask; | |
| 3381 | − for (i = 0; i < ETH_ALEN; i++) { | |
| 3382 | − pfn_mac.mac[i] &= mac_mask[i]; | |
| 3383 | − pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]); | |
| 3347 | + brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n", | |
| 3348 | + netinfo->SSID, netinfo->channel); | |
| 3349 | + err = brcmf_internal_escan_add_info(request, | |
| 3350 | + netinfo->SSID, | |
| 3351 | + netinfo->SSID_len, | |
| 3352 | + netinfo->channel); | |
| 3353 | + if (err) | |
| 3354 | + goto out_err; | |
| 3384 | 3355 | } |
| 3385 | − /* Clear multi bit */ | |
| 3386 | − pfn_mac.mac[0] &= 0xFE; | |
| 3387 | − /* Set locally administered */ | |
| 3388 | − pfn_mac.mac[0] |= 0x02; | |
| 3389 | 3356 | |
| 3390 | − err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac, | |
| 3391 | − sizeof(pfn_mac)); | |
| 3392 | − if (err) | |
| 3393 | − brcmf_err("pfn_macaddr failed, err=%d\n", err); | |
| 3357 | + err = brcmf_start_internal_escan(ifp, request); | |
| 3358 | + if (!err) | |
| 3359 | + goto free_req; | |
| 3394 | 3360 | |
| 3361 | +out_err: | |
| 3362 | + cfg80211_sched_scan_stopped(wiphy); | |
| 3363 | +free_req: | |
| 3364 | + kfree(request); | |
| 3395 | 3365 | return err; |
| 3396 | 3366 | } |
| 3397 | 3367 | |
| 3398 | 3368 | static int |
| 3399 | 3369 | brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, |
| 3400 | 3370 | struct net_device *ndev, |
| 3401 | − struct cfg80211_sched_scan_request *request) | |
| 3371 | + struct cfg80211_sched_scan_request *req) | |
| 3402 | 3372 | { |
| 3403 | 3373 | struct brcmf_if *ifp = netdev_priv(ndev); |
| 3404 | 3374 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); |
| 3405 | − struct brcmf_pno_net_param_le pfn; | |
| 3406 | − int i; | |
| 3407 | − int ret = 0; | |
| 3408 | 3375 | |
| 3409 | 3376 | brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n", |
| 3410 | − request->n_match_sets, request->n_ssids); | |
| 3411 | − if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { | |
| 3412 | − brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status); | |
| 3413 | − return -EAGAIN; | |
| 3414 | − } | |
| 3377 | + req->n_match_sets, req->n_ssids); | |
| 3378 | + | |
| 3415 | 3379 | if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) { |
| 3416 | 3380 | brcmf_err("Scanning suppressed: status (%lu)\n", |
| 3417 | 3381 | cfg->scan_status); |
| 3418 | 3382 | return -EAGAIN; |
| 3419 | 3383 | } |
| 3420 | 3384 | |
| 3421 | − if (!request->n_ssids || !request->n_match_sets) { | |
| 3422 | − brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n", | |
| 3423 | − request->n_ssids); | |
| 3385 | + if (req->n_match_sets <= 0) { | |
| 3386 | + brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n", | |
| 3387 | + req->n_match_sets); | |
| 3424 | 3388 | return -EINVAL; |
| 3425 | 3389 | } |
| 3426 | 3390 | |
| 3427 | − if (request->n_ssids > 0) { | |
| 3428 | − for (i = 0; i < request->n_ssids; i++) { | |
| 3429 | − /* Active scan req for ssids */ | |
| 3430 | − brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n", | |
| 3431 | − request->ssids[i].ssid); | |
| 3432 | − | |
| 3433 | − /* match_set ssids is a supert set of n_ssid list, | |
| 3434 | − * so we need not add these set separately. | |
| 3435 | − */ | |
| 3436 | − } | |
| 3437 | − } | |
| 3438 | − | |
| 3439 | − if (request->n_match_sets > 0) { | |
| 3440 | − /* clean up everything */ | |
| 3441 | − ret = brcmf_dev_pno_clean(ndev); | |
| 3442 | − if (ret < 0) { | |
| 3443 | − brcmf_err("failed error=%d\n", ret); | |
| 3444 | − return ret; | |
| 3445 | − } | |
| 3446 | − | |
| 3447 | − /* configure pno */ | |
| 3448 | − if (brcmf_dev_pno_config(ifp, request)) | |
| 3449 | − return -EINVAL; | |
| 3450 | − | |
| 3451 | − /* configure each match set */ | |
| 3452 | − for (i = 0; i < request->n_match_sets; i++) { | |
| 3453 | − struct cfg80211_ssid *ssid; | |
| 3454 | − u32 ssid_len; | |
| 3455 | − | |
| 3456 | − ssid = &request->match_sets[i].ssid; | |
| 3457 | − ssid_len = ssid->ssid_len; | |
| 3458 | − | |
| 3459 | − if (!ssid_len) { | |
| 3460 | − brcmf_err("skip broadcast ssid\n"); | |
| 3461 | − continue; | |
| 3462 | − } | |
| 3463 | − pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); | |
| 3464 | − pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); | |
| 3465 | − pfn.wsec = cpu_to_le32(0); | |
| 3466 | − pfn.infra = cpu_to_le32(1); | |
| 3467 | − pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); | |
| 3468 | − pfn.ssid.SSID_len = cpu_to_le32(ssid_len); | |
| 3469 | − memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len); | |
| 3470 | − ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, | |
| 3471 | − sizeof(pfn)); | |
| 3472 | − brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n", | |
| 3473 | − ret == 0 ? "set" : "failed", ssid->ssid); | |
| 3474 | − } | |
| 3475 | − /* Enable the PNO */ | |
| 3476 | − if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) { | |
| 3477 | − brcmf_err("PNO enable failed!! ret=%d\n", ret); | |
| 3478 | − return -EINVAL; | |
| 3479 | − } | |
| 3480 | − } else { | |
| 3481 | − return -EINVAL; | |
| 3482 | − } | |
| 3483 | − | |
| 3484 | − return 0; | |
| 3391 | + return brcmf_pno_start_sched_scan(ifp, req); | |
| 3485 | 3392 | } |
| 3486 | 3393 | |
| 3487 | 3394 | static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, |
| 3488 | 3395 | struct net_device *ndev) |
| 3489 | 3396 | { |
| 3490 | 3397 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
| 3398 | + struct brcmf_if *ifp = netdev_priv(ndev); | |
| 3491 | 3399 | |
| 3492 | 3400 | brcmf_dbg(SCAN, "enter\n"); |
| 3493 | − brcmf_dev_pno_clean(ndev); | |
| 3494 | − if (cfg->sched_escan) | |
| 3495 | − brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true); | |
| 3401 | + brcmf_pno_clean(ifp); | |
| 3402 | + if (cfg->internal_escan) | |
| 3403 | + brcmf_notify_escan_complete(cfg, ifp, true, true); | |
| 3496 | 3404 | return 0; |
| 3497 | 3405 | } |
| 3498 | 3406 | |
| @@ -6428,6 +6336,7 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) · 2929 unmodified lines | ||
| 6428 | 6336 | wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; |
| 6429 | 6337 | wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; |
| 6430 | 6338 | wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; |
| 6339 | + wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD; | |
| 6431 | 6340 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; |
| 6432 | 6341 | } |
| 6433 | 6342 | |
| @@ -271,7 +271,7 @@ struct brcmf_cfg80211_wowl { · 270 unmodified lines | ||
| 271 | 271 | * @pub: common driver information. |
| 272 | 272 | * @channel: current channel. |
| 273 | 273 | * @active_scan: current scan mode. |
| 274 | − * @sched_escan: e-scan for scheduled scan support running. | |
| 274 | + * @internal_escan: indicates internally initiated e-scan is running. | |
| 275 | 275 | * @ibss_starter: indicates this sta is ibss starter. |
| 276 | 276 | * @pwr_save: indicate whether dongle to support power save mode. |
| 277 | 277 | * @dongle_up: indicate whether dongle up or not. |
| @@ -303,7 +303,7 @@ struct brcmf_cfg80211_info { · 25 unmodified lines | ||
| 303 | 303 | struct brcmf_pub *pub; |
| 304 | 304 | u32 channel; |
| 305 | 305 | bool active_scan; |
| 306 | − bool sched_escan; | |
| 306 | + bool internal_escan; | |
| 307 | 307 | bool ibss_starter; |
| 308 | 308 | bool pwr_save; |
| 309 | 309 | bool dongle_up; |
| @@ -131,6 +131,7 @@ · 130 unmodified lines | ||
| 131 | 131 | #define BRCMF_TXBF_MU_BFR_CAP BIT(1) |
| 132 | 132 | |
| 133 | 133 | #define BRCMF_MAXPMKID 16 /* max # PMKID cache entries */ |
| 134 | +#define BRCMF_NUMCHANNELS 64 | |
| 134 | 135 | |
| 135 | 136 | #define BRCMF_PFN_MACADDR_CFG_VER 1 |
| 136 | 137 | #define BRCMF_PFN_MAC_OUI_ONLY BIT(0) |
| @@ -718,6 +719,21 @@ struct brcmf_pno_param_le { · 581 unmodified lines | ||
| 718 | 719 | __le32 slow_freq; |
| 719 | 720 | }; |
| 720 | 721 | |
| 722 | +/** | |
| 723 | + * struct brcmf_pno_config_le - PNO channel configuration. | |
| 724 | + * | |
| 725 | + * @reporttype: determines what is reported. | |
| 726 | + * @channel_num: number of channels specified in @channel_list. | |
| 727 | + * @channel_list: channels to use in PNO scan. | |
| 728 | + * @flags: reserved. | |
| 729 | + */ | |
| 730 | +struct brcmf_pno_config_le { | |
| 731 | + __le32 reporttype; | |
| 732 | + __le32 channel_num; | |
| 733 | + __le16 channel_list[BRCMF_NUMCHANNELS]; | |
| 734 | + __le32 flags; | |
| 735 | +}; | |
| 736 | + | |
| 721 | 737 | /** |
| 722 | 738 | * struct brcmf_pno_net_param_le - scan parameters per preferred network. |
| 723 | 739 | * |
| @@ -769,6 +785,13 @@ struct brcmf_pno_scanresults_le { · 45 unmodified lines | ||
| 769 | 785 | __le32 count; |
| 770 | 786 | }; |
| 771 | 787 | |
| 788 | +struct brcmf_pno_scanresults_v2_le { | |
| 789 | + __le32 version; | |
| 790 | + __le32 status; | |
| 791 | + __le32 count; | |
| 792 | + __le32 scan_ch_bucket; | |
| 793 | +}; | |
| 794 | + | |
| 772 | 795 | /** |
| 773 | 796 | * struct brcmf_pno_macaddr_le - to configure PNO macaddr randomization. |
| 774 | 797 | * |
| @@ -87,11 +87,6 @@ struct msgbuf_common_hdr { · 86 unmodified lines | ||
| 87 | 87 | __le32 request_id; |
| 88 | 88 | }; |
| 89 | 89 | |
| 90 | −struct msgbuf_buf_addr { | |
| 91 | − __le32 low_addr; | |
| 92 | − __le32 high_addr; | |
| 93 | −}; | |
| 94 | − | |
| 95 | 90 | struct msgbuf_ioctl_req_hdr { |
| 96 | 91 | struct msgbuf_common_hdr msg; |
| 97 | 92 | __le32 cmd; |
| @@ -227,7 +222,10 @@ struct brcmf_msgbuf { · 129 unmodified lines | ||
| 227 | 222 | struct brcmf_commonring **commonrings; |
| 228 | 223 | struct brcmf_commonring **flowrings; |
| 229 | 224 | dma_addr_t *flowring_dma_handle; |
| 230 | − u16 nrof_flowrings; | |
| 225 | + | |
| 226 | + u16 max_flowrings; | |
| 227 | + u16 max_submissionrings; | |
| 228 | + u16 max_completionrings; | |
| 231 | 229 | |
| 232 | 230 | u16 rx_dataoffset; |
| 233 | 231 | u32 max_rxbufpost; |
| @@ -610,7 +608,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf, · 376 unmodified lines | ||
| 610 | 608 | create->msg.request_id = 0; |
| 611 | 609 | create->tid = brcmf_flowring_tid(msgbuf->flow, flowid); |
| 612 | 610 | create->flow_ring_id = cpu_to_le16(flowid + |
| 613 | − BRCMF_NROF_H2D_COMMON_MSGRINGS); | |
| 611 | + BRCMF_H2D_MSGRING_FLOWRING_IDSTART); | |
| 614 | 612 | memcpy(create->sa, work->sa, ETH_ALEN); |
| 615 | 613 | memcpy(create->da, work->da, ETH_ALEN); |
| 616 | 614 | address = (u64)msgbuf->flowring_dma_handle[flowid]; |
| @@ -760,7 +758,7 @@ static void brcmf_msgbuf_txflow_worker(struct work_struct *worker) · 143 unmodified lines | ||
| 760 | 758 | u32 flowid; |
| 761 | 759 | |
| 762 | 760 | msgbuf = container_of(worker, struct brcmf_msgbuf, txflow_work); |
| 763 | − for_each_set_bit(flowid, msgbuf->flow_map, msgbuf->nrof_flowrings) { | |
| 761 | + for_each_set_bit(flowid, msgbuf->flow_map, msgbuf->max_flowrings) { | |
| 764 | 762 | clear_bit(flowid, msgbuf->flow_map); |
| 765 | 763 | brcmf_msgbuf_txflow(msgbuf, flowid); |
| 766 | 764 | } |
| @@ -866,7 +864,7 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) · 99 unmodified lines | ||
| 866 | 864 | tx_status = (struct msgbuf_tx_status *)buf; |
| 867 | 865 | idx = le32_to_cpu(tx_status->msg.request_id); |
| 868 | 866 | flowid = le16_to_cpu(tx_status->compl_hdr.flow_ring_id); |
| 869 | − flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; | |
| 867 | + flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART; | |
| 870 | 868 | skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, |
| 871 | 869 | msgbuf->tx_pktids, idx); |
| 872 | 870 | if (!skb) |
| @@ -1174,7 +1172,7 @@ brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf, · 301 unmodified lines | ||
| 1174 | 1172 | flowring_create_resp = (struct msgbuf_flowring_create_resp *)buf; |
| 1175 | 1173 | |
| 1176 | 1174 | flowid = le16_to_cpu(flowring_create_resp->compl_hdr.flow_ring_id); |
| 1177 | − flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; | |
| 1175 | + flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART; | |
| 1178 | 1176 | status = le16_to_cpu(flowring_create_resp->compl_hdr.status); |
| 1179 | 1177 | |
| 1180 | 1178 | if (status) { |
| @@ -1202,7 +1200,7 @@ brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf, · 21 unmodified lines | ||
| 1202 | 1200 | flowring_delete_resp = (struct msgbuf_flowring_delete_resp *)buf; |
| 1203 | 1201 | |
| 1204 | 1202 | flowid = le16_to_cpu(flowring_delete_resp->compl_hdr.flow_ring_id); |
| 1205 | − flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; | |
| 1203 | + flowid -= BRCMF_H2D_MSGRING_FLOWRING_IDSTART; | |
| 1206 | 1204 | status = le16_to_cpu(flowring_delete_resp->compl_hdr.status); |
| 1207 | 1205 | |
| 1208 | 1206 | if (status) { |
| @@ -1307,7 +1305,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev) · 98 unmodified lines | ||
| 1307 | 1305 | brcmf_msgbuf_process_rx(msgbuf, buf); |
| 1308 | 1306 | |
| 1309 | 1307 | for_each_set_bit(flowid, msgbuf->txstatus_done_map, |
| 1310 | − msgbuf->nrof_flowrings) { | |
| 1308 | + msgbuf->max_flowrings) { | |
| 1311 | 1309 | clear_bit(flowid, msgbuf->txstatus_done_map); |
| 1312 | 1310 | commonring = msgbuf->flowrings[flowid]; |
| 1313 | 1311 | qlen = brcmf_flowring_qlen(msgbuf->flow, flowid); |
| @@ -1349,7 +1347,7 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid) · 35 unmodified lines | ||
| 1349 | 1347 | delete->msg.request_id = 0; |
| 1350 | 1348 | |
| 1351 | 1349 | delete->flow_ring_id = cpu_to_le16(flowid + |
| 1352 | − BRCMF_NROF_H2D_COMMON_MSGRINGS); | |
| 1350 | + BRCMF_H2D_MSGRING_FLOWRING_IDSTART); | |
| 1353 | 1351 | delete->reason = 0; |
| 1354 | 1352 | |
| 1355 | 1353 | brcmf_dbg(MSGBUF, "Send Flow Delete Req flow ID %d, ifindex %d\n", |
| @@ -1427,10 +1425,10 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) · 71 unmodified lines | ||
| 1427 | 1425 | |
| 1428 | 1426 | if_msgbuf = drvr->bus_if->msgbuf; |
| 1429 | 1427 | |
| 1430 | − if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) { | |
| 1428 | + if (if_msgbuf->max_flowrings >= BRCMF_FLOWRING_HASHSIZE) { | |
| 1431 | 1429 | brcmf_err("driver not configured for this many flowrings %d\n", |
| 1432 | − if_msgbuf->nrof_flowrings); | |
| 1433 | − if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1; | |
| 1430 | + if_msgbuf->max_flowrings); | |
| 1431 | + if_msgbuf->max_flowrings = BRCMF_FLOWRING_HASHSIZE - 1; | |
| 1434 | 1432 | } |
| 1435 | 1433 | |
| 1436 | 1434 | msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL); |
| @@ -1443,7 +1441,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) · 6 unmodified lines | ||
| 1443 | 1441 | goto fail; |
| 1444 | 1442 | } |
| 1445 | 1443 | INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker); |
| 1446 | − count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings); | |
| 1444 | + count = BITS_TO_LONGS(if_msgbuf->max_flowrings); | |
| 1447 | 1445 | count = count * sizeof(unsigned long); |
| 1448 | 1446 | msgbuf->flow_map = kzalloc(count, GFP_KERNEL); |
| 1449 | 1447 | if (!msgbuf->flow_map) |
| @@ -1479,8 +1477,8 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) · 29 unmodified lines | ||
| 1479 | 1477 | msgbuf->commonrings = |
| 1480 | 1478 | (struct brcmf_commonring **)if_msgbuf->commonrings; |
| 1481 | 1479 | msgbuf->flowrings = (struct brcmf_commonring **)if_msgbuf->flowrings; |
| 1482 | − msgbuf->nrof_flowrings = if_msgbuf->nrof_flowrings; | |
| 1483 | − msgbuf->flowring_dma_handle = kzalloc(msgbuf->nrof_flowrings * | |
| 1480 | + msgbuf->max_flowrings = if_msgbuf->max_flowrings; | |
| 1481 | + msgbuf->flowring_dma_handle = kzalloc(msgbuf->max_flowrings * | |
| 1484 | 1482 | sizeof(*msgbuf->flowring_dma_handle), GFP_KERNEL); |
| 1485 | 1483 | if (!msgbuf->flowring_dma_handle) |
| 1486 | 1484 | goto fail; |
| @@ -1501,7 +1499,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) · 14 unmodified lines | ||
| 1501 | 1499 | goto fail; |
| 1502 | 1500 | |
| 1503 | 1501 | msgbuf->flow = brcmf_flowring_attach(drvr->bus_if->dev, |
| 1504 | − if_msgbuf->nrof_flowrings); | |
| 1502 | + if_msgbuf->max_flowrings); | |
| 1505 | 1503 | if (!msgbuf->flow) |
| 1506 | 1504 | goto fail; |
| 1507 | 1505 | |
| @@ -31,6 +31,10 @@ · 30 unmodified lines | ||
| 31 | 31 | #define BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE 32 |
| 32 | 32 | #define BRCMF_H2D_TXFLOWRING_ITEMSIZE 48 |
| 33 | 33 | |
| 34 | +struct msgbuf_buf_addr { | |
| 35 | + __le32 low_addr; | |
| 36 | + __le32 high_addr; | |
| 37 | +}; | |
| 34 | 38 | |
| 35 | 39 | int brcmf_proto_msgbuf_rx_trigger(struct device *dev); |
| 36 | 40 | void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid); |
| @@ -135,7 +135,7 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { · 134 unmodified lines | ||
| 135 | 135 | BRCMF_PCIE_MB_INT_D2H3_DB1) |
| 136 | 136 | |
| 137 | 137 | #define BRCMF_PCIE_MIN_SHARED_VERSION 5 |
| 138 | −#define BRCMF_PCIE_MAX_SHARED_VERSION 5 | |
| 138 | +#define BRCMF_PCIE_MAX_SHARED_VERSION 6 | |
| 139 | 139 | #define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF |
| 140 | 140 | #define BRCMF_PCIE_SHARED_DMA_INDEX 0x10000 |
| 141 | 141 | #define BRCMF_PCIE_SHARED_DMA_2B_IDX 0x100000 |
| @@ -166,17 +166,6 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { · 24 unmodified lines | ||
| 166 | 166 | #define BRCMF_RING_MEM_SZ 16 |
| 167 | 167 | #define BRCMF_RING_STATE_SZ 8 |
| 168 | 168 | |
| 169 | −#define BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET 4 | |
| 170 | −#define BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET 8 | |
| 171 | −#define BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET 12 | |
| 172 | −#define BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET 16 | |
| 173 | −#define BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET 20 | |
| 174 | −#define BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET 28 | |
| 175 | −#define BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET 36 | |
| 176 | −#define BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET 44 | |
| 177 | −#define BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET 0 | |
| 178 | −#define BRCMF_SHARED_RING_MAX_SUB_QUEUES 52 | |
| 179 | − | |
| 180 | 169 | #define BRCMF_DEF_MAX_RXBUFPOST 255 |
| 181 | 170 | |
| 182 | 171 | #define BRCMF_CONSOLE_BUFADDR_OFFSET 8 |
| @@ -231,7 +220,9 @@ struct brcmf_pcie_shared_info { · 48 unmodified lines | ||
| 231 | 220 | struct brcmf_pcie_ringbuf *commonrings[BRCMF_NROF_COMMON_MSGRINGS]; |
| 232 | 221 | struct brcmf_pcie_ringbuf *flowrings; |
| 233 | 222 | u16 max_rxbufpost; |
| 234 | − u32 nrof_flowrings; | |
| 223 | + u16 max_flowrings; | |
| 224 | + u16 max_submissionrings; | |
| 225 | + u16 max_completionrings; | |
| 235 | 226 | u32 rx_dataoffset; |
| 236 | 227 | u32 htod_mb_data_addr; |
| 237 | 228 | u32 dtoh_mb_data_addr; |
| @@ -241,6 +232,7 @@ struct brcmf_pcie_shared_info { · 3 unmodified lines | ||
| 241 | 232 | dma_addr_t scratch_dmahandle; |
| 242 | 233 | void *ringupd; |
| 243 | 234 | dma_addr_t ringupd_dmahandle; |
| 235 | + u8 version; | |
| 244 | 236 | }; |
| 245 | 237 | |
| 246 | 238 | struct brcmf_pcie_core_info { |
| @@ -284,6 +276,36 @@ struct brcmf_pcie_ringbuf { · 37 unmodified lines | ||
| 284 | 276 | u8 id; |
| 285 | 277 | }; |
| 286 | 278 | |
| 279 | +/** | |
| 280 | + * struct brcmf_pcie_dhi_ringinfo - dongle/host interface shared ring info | |
| 281 | + * | |
| 282 | + * @ringmem: dongle memory pointer to ring memory location | |
| 283 | + * @h2d_w_idx_ptr: h2d ring write indices dongle memory pointers | |
| 284 | + * @h2d_r_idx_ptr: h2d ring read indices dongle memory pointers | |
| 285 | + * @d2h_w_idx_ptr: d2h ring write indices dongle memory pointers | |
| 286 | + * @d2h_r_idx_ptr: d2h ring read indices dongle memory pointers | |
| 287 | + * @h2d_w_idx_hostaddr: h2d ring write indices host memory pointers | |
| 288 | + * @h2d_r_idx_hostaddr: h2d ring read indices host memory pointers | |
| 289 | + * @d2h_w_idx_hostaddr: d2h ring write indices host memory pointers | |
| 290 | + * @d2h_r_idx_hostaddr: d2h ring reaD indices host memory pointers | |
| 291 | + * @max_flowrings: maximum number of tx flow rings supported. | |
| 292 | + * @max_submissionrings: maximum number of submission rings(h2d) supported. | |
| 293 | + * @max_completionrings: maximum number of completion rings(d2h) supported. | |
| 294 | + */ | |
| 295 | +struct brcmf_pcie_dhi_ringinfo { | |
| 296 | + __le32 ringmem; | |
| 297 | + __le32 h2d_w_idx_ptr; | |
| 298 | + __le32 h2d_r_idx_ptr; | |
| 299 | + __le32 d2h_w_idx_ptr; | |
| 300 | + __le32 d2h_r_idx_ptr; | |
| 301 | + struct msgbuf_buf_addr h2d_w_idx_hostaddr; | |
| 302 | + struct msgbuf_buf_addr h2d_r_idx_hostaddr; | |
| 303 | + struct msgbuf_buf_addr d2h_w_idx_hostaddr; | |
| 304 | + struct msgbuf_buf_addr d2h_r_idx_hostaddr; | |
| 305 | + __le16 max_flowrings; | |
| 306 | + __le16 max_submissionrings; | |
| 307 | + __le16 max_completionrings; | |
| 308 | +}; | |
| 287 | 309 | |
| 288 | 310 | static const u32 brcmf_ring_max_item[BRCMF_NROF_COMMON_MSGRINGS] = { |
| 289 | 311 | BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM, |
| @@ -1054,26 +1076,35 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) · 764 unmodified lines | ||
| 1054 | 1076 | { |
| 1055 | 1077 | struct brcmf_pcie_ringbuf *ring; |
| 1056 | 1078 | struct brcmf_pcie_ringbuf *rings; |
| 1057 | − u32 ring_addr; | |
| 1058 | 1079 | u32 d2h_w_idx_ptr; |
| 1059 | 1080 | u32 d2h_r_idx_ptr; |
| 1060 | 1081 | u32 h2d_w_idx_ptr; |
| 1061 | 1082 | u32 h2d_r_idx_ptr; |
| 1062 | − u32 addr; | |
| 1063 | 1083 | u32 ring_mem_ptr; |
| 1064 | 1084 | u32 i; |
| 1065 | 1085 | u64 address; |
| 1066 | 1086 | u32 bufsz; |
| 1067 | − u16 max_sub_queues; | |
| 1068 | 1087 | u8 idx_offset; |
| 1069 | − | |
| 1070 | − ring_addr = devinfo->shared.ring_info_addr; | |
| 1071 | − brcmf_dbg(PCIE, "Base ring addr = 0x%08x\n", ring_addr); | |
| 1072 | − addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES; | |
| 1073 | − max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr); | |
| 1088 | + struct brcmf_pcie_dhi_ringinfo ringinfo; | |
| 1089 | + u16 max_flowrings; | |
| 1090 | + u16 max_submissionrings; | |
| 1091 | + u16 max_completionrings; | |
| 1092 | + | |
| 1093 | + memcpy_fromio(&ringinfo, devinfo->tcm + devinfo->shared.ring_info_addr, | |
| 1094 | + sizeof(ringinfo)); | |
| 1095 | + if (devinfo->shared.version >= 6) { | |
| 1096 | + max_submissionrings = le16_to_cpu(ringinfo.max_submissionrings); | |
| 1097 | + max_flowrings = le16_to_cpu(ringinfo.max_flowrings); | |
| 1098 | + max_completionrings = le16_to_cpu(ringinfo.max_completionrings); | |
| 1099 | + } else { | |
| 1100 | + max_submissionrings = le16_to_cpu(ringinfo.max_flowrings); | |
| 1101 | + max_flowrings = max_submissionrings - | |
| 1102 | + BRCMF_NROF_H2D_COMMON_MSGRINGS; | |
| 1103 | + max_completionrings = BRCMF_NROF_D2H_COMMON_MSGRINGS; | |
| 1104 | + } | |
| 1074 | 1105 | |
| 1075 | 1106 | if (devinfo->dma_idx_sz != 0) { |
| 1076 | − bufsz = (BRCMF_NROF_D2H_COMMON_MSGRINGS + max_sub_queues) * | |
| 1107 | + bufsz = (max_submissionrings + max_completionrings) * | |
| 1077 | 1108 | devinfo->dma_idx_sz * 2; |
| 1078 | 1109 | devinfo->idxbuf = dma_alloc_coherent(&devinfo->pdev->dev, bufsz, |
| 1079 | 1110 | &devinfo->idxbuf_dmahandle, |
| @@ -1083,14 +1114,10 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) · 3 unmodified lines | ||
| 1083 | 1114 | } |
| 1084 | 1115 | |
| 1085 | 1116 | if (devinfo->dma_idx_sz == 0) { |
| 1086 | − addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET; | |
| 1087 | − d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); | |
| 1088 | − addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET; | |
| 1089 | − d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); | |
| 1090 | − addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET; | |
| 1091 | − h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); | |
| 1092 | − addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET; | |
| 1093 | − h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); | |
| 1117 | + d2h_w_idx_ptr = le32_to_cpu(ringinfo.d2h_w_idx_ptr); | |
| 1118 | + d2h_r_idx_ptr = le32_to_cpu(ringinfo.d2h_r_idx_ptr); | |
| 1119 | + h2d_w_idx_ptr = le32_to_cpu(ringinfo.h2d_w_idx_ptr); | |
| 1120 | + h2d_r_idx_ptr = le32_to_cpu(ringinfo.h2d_r_idx_ptr); | |
| 1094 | 1121 | idx_offset = sizeof(u32); |
| 1095 | 1122 | devinfo->write_ptr = brcmf_pcie_write_tcm16; |
| 1096 | 1123 | devinfo->read_ptr = brcmf_pcie_read_tcm16; |
| @@ -1103,34 +1130,42 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) · 6 unmodified lines | ||
| 1103 | 1130 | devinfo->read_ptr = brcmf_pcie_read_idx; |
| 1104 | 1131 | |
| 1105 | 1132 | h2d_w_idx_ptr = 0; |
| 1106 | − addr = ring_addr + BRCMF_SHARED_RING_H2D_WP_HADDR_OFFSET; | |
| 1107 | 1133 | address = (u64)devinfo->idxbuf_dmahandle; |
| 1108 | − brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); | |
| 1109 | − brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); | |
| 1110 | − | |
| 1111 | − h2d_r_idx_ptr = h2d_w_idx_ptr + max_sub_queues * idx_offset; | |
| 1112 | − addr = ring_addr + BRCMF_SHARED_RING_H2D_RP_HADDR_OFFSET; | |
| 1113 | − address += max_sub_queues * idx_offset; | |
| 1114 | − brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); | |
| 1115 | − brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); | |
| 1116 | − | |
| 1117 | − d2h_w_idx_ptr = h2d_r_idx_ptr + max_sub_queues * idx_offset; | |
| 1118 | − addr = ring_addr + BRCMF_SHARED_RING_D2H_WP_HADDR_OFFSET; | |
| 1119 | − address += max_sub_queues * idx_offset; | |
| 1120 | − brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); | |
| 1121 | − brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); | |
| 1134 | + ringinfo.h2d_w_idx_hostaddr.low_addr = | |
| 1135 | + cpu_to_le32(address & 0xffffffff); | |
| 1136 | + ringinfo.h2d_w_idx_hostaddr.high_addr = | |
| 1137 | + cpu_to_le32(address >> 32); | |
| 1138 | + | |
| 1139 | + h2d_r_idx_ptr = h2d_w_idx_ptr + | |
| 1140 | + max_submissionrings * idx_offset; | |
| 1141 | + address += max_submissionrings * idx_offset; | |
| 1142 | + ringinfo.h2d_r_idx_hostaddr.low_addr = | |
| 1143 | + cpu_to_le32(address & 0xffffffff); | |
| 1144 | + ringinfo.h2d_r_idx_hostaddr.high_addr = | |
| 1145 | + cpu_to_le32(address >> 32); | |
| 1146 | + | |
| 1147 | + d2h_w_idx_ptr = h2d_r_idx_ptr + | |
| 1148 | + max_submissionrings * idx_offset; | |
| 1149 | + address += max_submissionrings * idx_offset; | |
| 1150 | + ringinfo.d2h_w_idx_hostaddr.low_addr = | |
| 1151 | + cpu_to_le32(address & 0xffffffff); | |
| 1152 | + ringinfo.d2h_w_idx_hostaddr.high_addr = | |
| 1153 | + cpu_to_le32(address >> 32); | |
| 1122 | 1154 | |
| 1123 | 1155 | d2h_r_idx_ptr = d2h_w_idx_ptr + |
| 1124 | − BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset; | |
| 1125 | − addr = ring_addr + BRCMF_SHARED_RING_D2H_RP_HADDR_OFFSET; | |
| 1126 | − address += BRCMF_NROF_D2H_COMMON_MSGRINGS * idx_offset; | |
| 1127 | − brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); | |
| 1128 | − brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); | |
| 1156 | + max_completionrings * idx_offset; | |
| 1157 | + address += max_completionrings * idx_offset; | |
| 1158 | + ringinfo.d2h_r_idx_hostaddr.low_addr = | |
| 1159 | + cpu_to_le32(address & 0xffffffff); | |
| 1160 | + ringinfo.d2h_r_idx_hostaddr.high_addr = | |
| 1161 | + cpu_to_le32(address >> 32); | |
| 1162 | + | |
| 1163 | + memcpy_toio(devinfo->tcm + devinfo->shared.ring_info_addr, | |
| 1164 | + &ringinfo, sizeof(ringinfo)); | |
| 1129 | 1165 | brcmf_dbg(PCIE, "Using host memory indices\n"); |
| 1130 | 1166 | } |
| 1131 | 1167 | |
| 1132 | − addr = ring_addr + BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET; | |
| 1133 | − ring_mem_ptr = brcmf_pcie_read_tcm32(devinfo, addr); | |
| 1168 | + ring_mem_ptr = le32_to_cpu(ringinfo.ringmem); | |
| 1134 | 1169 | |
| 1135 | 1170 | for (i = 0; i < BRCMF_NROF_H2D_COMMON_MSGRINGS; i++) { |
| 1136 | 1171 | ring = brcmf_pcie_alloc_dma_and_ring(devinfo, i, ring_mem_ptr); |
| @@ -1161,20 +1196,19 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) · 24 unmodified lines | ||
| 1161 | 1196 | ring_mem_ptr += BRCMF_RING_MEM_SZ; |
| 1162 | 1197 | } |
| 1163 | 1198 | |
| 1164 | − devinfo->shared.nrof_flowrings = | |
| 1165 | − max_sub_queues - BRCMF_NROF_H2D_COMMON_MSGRINGS; | |
| 1166 | − rings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*ring), | |
| 1167 | − GFP_KERNEL); | |
| 1199 | + devinfo->shared.max_flowrings = max_flowrings; | |
| 1200 | + devinfo->shared.max_submissionrings = max_submissionrings; | |
| 1201 | + devinfo->shared.max_completionrings = max_completionrings; | |
| 1202 | + rings = kcalloc(max_flowrings, sizeof(*ring), GFP_KERNEL); | |
| 1168 | 1203 | if (!rings) |
| 1169 | 1204 | goto fail; |
| 1170 | 1205 | |
| 1171 | − brcmf_dbg(PCIE, "Nr of flowrings is %d\n", | |
| 1172 | − devinfo->shared.nrof_flowrings); | |
| 1206 | + brcmf_dbg(PCIE, "Nr of flowrings is %d\n", max_flowrings); | |
| 1173 | 1207 | |
| 1174 | − for (i = 0; i < devinfo->shared.nrof_flowrings; i++) { | |
| 1208 | + for (i = 0; i < max_flowrings; i++) { | |
| 1175 | 1209 | ring = &rings[i]; |
| 1176 | 1210 | ring->devinfo = devinfo; |
| 1177 | − ring->id = i + BRCMF_NROF_COMMON_MSGRINGS; | |
| 1211 | + ring->id = i + BRCMF_H2D_MSGRING_FLOWRING_IDSTART; | |
| 1178 | 1212 | brcmf_commonring_register_cb(&ring->commonring, |
| 1179 | 1213 | brcmf_pcie_ring_mb_ring_bell, |
| 1180 | 1214 | brcmf_pcie_ring_mb_update_rptr, |
| @@ -1357,17 +1391,16 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, · 176 unmodified lines | ||
| 1357 | 1391 | { |
| 1358 | 1392 | struct brcmf_pcie_shared_info *shared; |
| 1359 | 1393 | u32 addr; |
| 1360 | − u32 version; | |
| 1361 | 1394 | |
| 1362 | 1395 | shared = &devinfo->shared; |
| 1363 | 1396 | shared->tcm_base_address = sharedram_addr; |
| 1364 | 1397 | |
| 1365 | 1398 | shared->flags = brcmf_pcie_read_tcm32(devinfo, sharedram_addr); |
| 1366 | − version = shared->flags & BRCMF_PCIE_SHARED_VERSION_MASK; | |
| 1367 | − brcmf_dbg(PCIE, "PCIe protocol version %d\n", version); | |
| 1368 | − if ((version > BRCMF_PCIE_MAX_SHARED_VERSION) || | |
| 1369 | − (version < BRCMF_PCIE_MIN_SHARED_VERSION)) { | |
| 1370 | − brcmf_err("Unsupported PCIE version %d\n", version); | |
| 1399 | + shared->version = (u8)(shared->flags & BRCMF_PCIE_SHARED_VERSION_MASK); | |
| 1400 | + brcmf_dbg(PCIE, "PCIe protocol version %d\n", shared->version); | |
| 1401 | + if ((shared->version > BRCMF_PCIE_MAX_SHARED_VERSION) || | |
| 1402 | + (shared->version < BRCMF_PCIE_MIN_SHARED_VERSION)) { | |
| 1403 | + brcmf_err("Unsupported PCIE version %d\n", shared->version); | |
| 1371 | 1404 | return -EINVAL; |
| 1372 | 1405 | } |
| 1373 | 1406 | |
| @@ -1661,18 +1694,18 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw, · 287 unmodified lines | ||
| 1661 | 1694 | bus->msgbuf->commonrings[i] = |
| 1662 | 1695 | &devinfo->shared.commonrings[i]->commonring; |
| 1663 | 1696 | |
| 1664 | − flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*flowrings), | |
| 1697 | + flowrings = kcalloc(devinfo->shared.max_flowrings, sizeof(*flowrings), | |
| 1665 | 1698 | GFP_KERNEL); |
| 1666 | 1699 | if (!flowrings) |
| 1667 | 1700 | goto fail; |
| 1668 | 1701 | |
| 1669 | − for (i = 0; i < devinfo->shared.nrof_flowrings; i++) | |
| 1702 | + for (i = 0; i < devinfo->shared.max_flowrings; i++) | |
| 1670 | 1703 | flowrings[i] = &devinfo->shared.flowrings[i].commonring; |
| 1671 | 1704 | bus->msgbuf->flowrings = flowrings; |
| 1672 | 1705 | |
| 1673 | 1706 | bus->msgbuf->rx_dataoffset = devinfo->shared.rx_dataoffset; |
| 1674 | 1707 | bus->msgbuf->max_rxbufpost = devinfo->shared.max_rxbufpost; |
| 1675 | − bus->msgbuf->nrof_flowrings = devinfo->shared.nrof_flowrings; | |
| 1708 | + bus->msgbuf->max_flowrings = devinfo->shared.max_flowrings; | |
| 1676 | 1709 | |
| 1677 | 1710 | init_waitqueue_head(&devinfo->mbdata_resp_wait); |
| 1678 | 1711 | |
| @@ -0,0 +1,242 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2016 Broadcom | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
| 11 | + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
| 13 | + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
| 14 | + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | +#include <linux/netdevice.h> | |
| 17 | +#include <net/cfg80211.h> | |
| 18 | + | |
| 19 | +#include "core.h" | |
| 20 | +#include "debug.h" | |
| 21 | +#include "fwil.h" | |
| 22 | +#include "fwil_types.h" | |
| 23 | +#include "cfg80211.h" | |
| 24 | +#include "pno.h" | |
| 25 | + | |
| 26 | +#define BRCMF_PNO_VERSION 2 | |
| 27 | +#define BRCMF_PNO_REPEAT 4 | |
| 28 | +#define BRCMF_PNO_FREQ_EXPO_MAX 3 | |
| 29 | +#define BRCMF_PNO_IMMEDIATE_SCAN_BIT 3 | |
| 30 | +#define BRCMF_PNO_ENABLE_BD_SCAN_BIT 5 | |
| 31 | +#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT 6 | |
| 32 | +#define BRCMF_PNO_REPORT_SEPARATELY_BIT 11 | |
| 33 | +#define BRCMF_PNO_SCAN_INCOMPLETE 0 | |
| 34 | +#define BRCMF_PNO_WPA_AUTH_ANY 0xFFFFFFFF | |
| 35 | +#define BRCMF_PNO_HIDDEN_BIT 2 | |
| 36 | +#define BRCMF_PNO_SCHED_SCAN_PERIOD 30 | |
| 37 | + | |
| 38 | +static int brcmf_pno_channel_config(struct brcmf_if *ifp, | |
| 39 | + struct brcmf_pno_config_le *cfg) | |
| 40 | +{ | |
| 41 | + cfg->reporttype = 0; | |
| 42 | + cfg->flags = 0; | |
| 43 | + | |
| 44 | + return brcmf_fil_iovar_data_set(ifp, "pfn_cfg", cfg, sizeof(*cfg)); | |
| 45 | +} | |
| 46 | + | |
| 47 | +static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq, | |
| 48 | + u32 mscan, u32 bestn) | |
| 49 | +{ | |
| 50 | + struct brcmf_pno_param_le pfn_param; | |
| 51 | + u16 flags; | |
| 52 | + u32 pfnmem; | |
| 53 | + s32 err; | |
| 54 | + | |
| 55 | + memset(&pfn_param, 0, sizeof(pfn_param)); | |
| 56 | + pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION); | |
| 57 | + | |
| 58 | + /* set extra pno params */ | |
| 59 | + flags = BIT(BRCMF_PNO_IMMEDIATE_SCAN_BIT) | | |
| 60 | + BIT(BRCMF_PNO_REPORT_SEPARATELY_BIT) | | |
| 61 | + BIT(BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); | |
| 62 | + pfn_param.repeat = BRCMF_PNO_REPEAT; | |
| 63 | + pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; | |
| 64 | + | |
| 65 | + /* set up pno scan fr */ | |
| 66 | + if (scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) { | |
| 67 | + brcmf_dbg(SCAN, "scan period too small, using minimum\n"); | |
| 68 | + scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD; | |
| 69 | + } | |
| 70 | + pfn_param.scan_freq = cpu_to_le32(scan_freq); | |
| 71 | + | |
| 72 | + if (mscan) { | |
| 73 | + pfnmem = bestn; | |
| 74 | + | |
| 75 | + /* set bestn in firmware */ | |
| 76 | + err = brcmf_fil_iovar_int_set(ifp, "pfnmem", pfnmem); | |
| 77 | + if (err < 0) { | |
| 78 | + brcmf_err("failed to set pfnmem\n"); | |
| 79 | + goto exit; | |
| 80 | + } | |
| 81 | + /* get max mscan which the firmware supports */ | |
| 82 | + err = brcmf_fil_iovar_int_get(ifp, "pfnmem", &pfnmem); | |
| 83 | + if (err < 0) { | |
| 84 | + brcmf_err("failed to get pfnmem\n"); | |
| 85 | + goto exit; | |
| 86 | + } | |
| 87 | + mscan = min_t(u32, mscan, pfnmem); | |
| 88 | + pfn_param.mscan = mscan; | |
| 89 | + pfn_param.bestn = bestn; | |
| 90 | + flags |= BIT(BRCMF_PNO_ENABLE_BD_SCAN_BIT); | |
| 91 | + brcmf_dbg(INFO, "mscan=%d, bestn=%d\n", mscan, bestn); | |
| 92 | + } | |
| 93 | + | |
| 94 | + pfn_param.flags = cpu_to_le16(flags); | |
| 95 | + err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param, | |
| 96 | + sizeof(pfn_param)); | |
| 97 | + if (err) | |
| 98 | + brcmf_err("pfn_set failed, err=%d\n", err); | |
| 99 | + | |
| 100 | +exit: | |
| 101 | + return err; | |
| 102 | +} | |
| 103 | + | |
| 104 | +static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr, | |
| 105 | + u8 *mac_mask) | |
| 106 | +{ | |
| 107 | + struct brcmf_pno_macaddr_le pfn_mac; | |
| 108 | + int err, i; | |
| 109 | + | |
| 110 | + pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; | |
| 111 | + pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC; | |
| 112 | + | |
| 113 | + memcpy(pfn_mac.mac, mac_addr, ETH_ALEN); | |
| 114 | + for (i = 0; i < ETH_ALEN; i++) { | |
| 115 | + pfn_mac.mac[i] &= mac_mask[i]; | |
| 116 | + pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]); | |
| 117 | + } | |
| 118 | + /* Clear multi bit */ | |
| 119 | + pfn_mac.mac[0] &= 0xFE; | |
| 120 | + /* Set locally administered */ | |
| 121 | + pfn_mac.mac[0] |= 0x02; | |
| 122 | + | |
| 123 | + err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac, | |
| 124 | + sizeof(pfn_mac)); | |
| 125 | + if (err) | |
| 126 | + brcmf_err("pfn_macaddr failed, err=%d\n", err); | |
| 127 | + | |
| 128 | + return err; | |
| 129 | +} | |
| 130 | + | |
| 131 | +static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid, | |
| 132 | + bool active) | |
| 133 | +{ | |
| 134 | + struct brcmf_pno_net_param_le pfn; | |
| 135 | + | |
| 136 | + pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); | |
| 137 | + pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); | |
| 138 | + pfn.wsec = cpu_to_le32(0); | |
| 139 | + pfn.infra = cpu_to_le32(1); | |
| 140 | + if (active) | |
| 141 | + pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); | |
| 142 | + pfn.ssid.SSID_len = cpu_to_le32(ssid->ssid_len); | |
| 143 | + memcpy(pfn.ssid.SSID, ssid->ssid, ssid->ssid_len); | |
| 144 | + return brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn)); | |
| 145 | +} | |
| 146 | + | |
| 147 | +static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid, | |
| 148 | + struct cfg80211_sched_scan_request *req) | |
| 149 | +{ | |
| 150 | + int i; | |
| 151 | + | |
| 152 | + if (!ssid || !req->ssids || !req->n_ssids) | |
| 153 | + return false; | |
| 154 | + | |
| 155 | + for (i = 0; i < req->n_ssids; i++) { | |
| 156 | + if (ssid->ssid_len == req->ssids[i].ssid_len) { | |
| 157 | + if (!strncmp(ssid->ssid, req->ssids[i].ssid, | |
| 158 | + ssid->ssid_len)) | |
| 159 | + return true; | |
| 160 | + } | |
| 161 | + } | |
| 162 | + return false; | |
| 163 | +} | |
| 164 | + | |
| 165 | +int brcmf_pno_clean(struct brcmf_if *ifp) | |
| 166 | +{ | |
| 167 | + int ret; | |
| 168 | + | |
| 169 | + /* Disable pfn */ | |
| 170 | + ret = brcmf_fil_iovar_int_set(ifp, "pfn", 0); | |
| 171 | + if (ret == 0) { | |
| 172 | + /* clear pfn */ | |
| 173 | + ret = brcmf_fil_iovar_data_set(ifp, "pfnclear", NULL, 0); | |
| 174 | + } | |
| 175 | + if (ret < 0) | |
| 176 | + brcmf_err("failed code %d\n", ret); | |
| 177 | + | |
| 178 | + return ret; | |
| 179 | +} | |
| 180 | + | |
| 181 | +int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, | |
| 182 | + struct cfg80211_sched_scan_request *req) | |
| 183 | +{ | |
| 184 | + struct brcmu_d11inf *d11inf; | |
| 185 | + struct brcmf_pno_config_le pno_cfg; | |
| 186 | + struct cfg80211_ssid *ssid; | |
| 187 | + u16 chan; | |
| 188 | + int i, ret; | |
| 189 | + | |
| 190 | + /* clean up everything */ | |
| 191 | + ret = brcmf_pno_clean(ifp); | |
| 192 | + if (ret < 0) { | |
| 193 | + brcmf_err("failed error=%d\n", ret); | |
| 194 | + return ret; | |
| 195 | + } | |
| 196 | + | |
| 197 | + /* configure pno */ | |
| 198 | + ret = brcmf_pno_config(ifp, req->scan_plans[0].interval, 0, 0); | |
| 199 | + if (ret < 0) | |
| 200 | + return ret; | |
| 201 | + | |
| 202 | + /* configure random mac */ | |
| 203 | + if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { | |
| 204 | + ret = brcmf_pno_set_random(ifp, req->mac_addr, | |
| 205 | + req->mac_addr_mask); | |
| 206 | + if (ret < 0) | |
| 207 | + return ret; | |
| 208 | + } | |
| 209 | + | |
| 210 | + /* configure channels to use */ | |
| 211 | + d11inf = &ifp->drvr->config->d11inf; | |
| 212 | + for (i = 0; i < req->n_channels; i++) { | |
| 213 | + chan = req->channels[i]->hw_value; | |
| 214 | + pno_cfg.channel_list[i] = cpu_to_le16(chan); | |
| 215 | + } | |
| 216 | + if (req->n_channels) { | |
| 217 | + pno_cfg.channel_num = cpu_to_le32(req->n_channels); | |
| 218 | + brcmf_pno_channel_config(ifp, &pno_cfg); | |
| 219 | + } | |
| 220 | + | |
| 221 | + /* configure each match set */ | |
| 222 | + for (i = 0; i < req->n_match_sets; i++) { | |
| 223 | + ssid = &req->match_sets[i].ssid; | |
| 224 | + if (!ssid->ssid_len) { | |
| 225 | + brcmf_err("skip broadcast ssid\n"); | |
| 226 | + continue; | |
| 227 | + } | |
| 228 | + | |
| 229 | + ret = brcmf_pno_add_ssid(ifp, ssid, | |
| 230 | + brcmf_is_ssid_active(ssid, req)); | |
| 231 | + if (ret < 0) | |
| 232 | + brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n", | |
| 233 | + ret == 0 ? "set" : "failed", ssid->ssid); | |
| 234 | + } | |
| 235 | + /* Enable the PNO */ | |
| 236 | + ret = brcmf_fil_iovar_int_set(ifp, "pfn", 1); | |
| 237 | + if (ret < 0) | |
| 238 | + brcmf_err("PNO enable failed!! ret=%d\n", ret); | |
| 239 | + | |
| 240 | + return ret; | |
| 241 | +} | |
| 242 | + | |
| @@ -0,0 +1,40 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2016 Broadcom | |
| 3 | + * | |
| 4 | + * Permission to use, copy, modify, and/or distribute this software for any | |
| 5 | + * purpose with or without fee is hereby granted, provided that the above | |
| 6 | + * copyright notice and this permission notice appear in all copies. | |
| 7 | + * | |
| 8 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
| 9 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 10 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
| 11 | + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 12 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
| 13 | + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
| 14 | + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 15 | + */ | |
| 16 | +#ifndef _BRCMF_PNO_H | |
| 17 | +#define _BRCMF_PNO_H | |
| 18 | + | |
| 19 | +#define BRCMF_PNO_SCAN_COMPLETE 1 | |
| 20 | +#define BRCMF_PNO_MAX_PFN_COUNT 16 | |
| 21 | +#define BRCMF_PNO_SCHED_SCAN_MIN_PERIOD 10 | |
| 22 | +#define BRCMF_PNO_SCHED_SCAN_MAX_PERIOD 508 | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * brcmf_pno_clean - disable and clear pno in firmware. | |
| 26 | + * | |
| 27 | + * @ifp: interface object used. | |
| 28 | + */ | |
| 29 | +int brcmf_pno_clean(struct brcmf_if *ifp); | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * brcmf_pno_start_sched_scan - initiate scheduled scan on device. | |
| 33 | + * | |
| 34 | + * @ifp: interface object used. | |
| 35 | + * @req: configuration parameters for scheduled scan. | |
| 36 | + */ | |
| 37 | +int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, | |
| 38 | + struct cfg80211_sched_scan_request *req); | |
| 39 | + | |
| 40 | +#endif /* _BRCMF_PNO_H */ | |
| @@ -621,6 +621,7 @@ static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { · 620 unmodified lines | ||
| 621 | 621 | BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330), |
| 622 | 622 | BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334), |
| 623 | 623 | BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340), |
| 624 | + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340), | |
| 624 | 625 | BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), |
| 625 | 626 | BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), |
| 626 | 627 | BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), |
| @@ -179,7 +179,7 @@ s16 qm_norm32(s32 op) · 178 unmodified lines | ||
| 179 | 179 | return u16extraSignBits; |
| 180 | 180 | } |
| 181 | 181 | |
| 182 | −/* This table is log2(1+(i/32)) where i=[0:1:31], in q.15 format */ | |
| 182 | +/* This table is log2(1+(i/32)) where i=[0:1:32], in q.15 format */ | |
| 183 | 183 | static const s16 log_table[] = { |
| 184 | 184 | 0, |
| 185 | 185 | 1455, |
| @@ -212,7 +212,8 @@ static const s16 log_table[] = { · 26 unmodified lines | ||
| 212 | 212 | 29717, |
| 213 | 213 | 30498, |
| 214 | 214 | 31267, |
| 215 | − 32024 | |
| 215 | + 32024, | |
| 216 | + 32768 | |
| 216 | 217 | }; |
| 217 | 218 | |
| 218 | 219 | #define LOG_TABLE_SIZE 32 /* log_table size */ |
| @@ -36,6 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | #define BRCM_CC_4330_CHIP_ID 0x4330 |
| 37 | 37 | #define BRCM_CC_4334_CHIP_ID 0x4334 |
| 38 | 38 | #define BRCM_CC_43340_CHIP_ID 43340 |
| 39 | +#define BRCM_CC_43341_CHIP_ID 43341 | |
| 39 | 40 | #define BRCM_CC_43362_CHIP_ID 43362 |
| 40 | 41 | #define BRCM_CC_4335_CHIP_ID 0x4335 |
| 41 | 42 | #define BRCM_CC_4339_CHIP_ID 0x4339 |
| @@ -2143,6 +2143,16 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, · 2142 unmodified lines | ||
| 2143 | 2143 | ret = mwifiex_set_encode(priv, NULL, NULL, 0, 0, NULL, 1); |
| 2144 | 2144 | |
| 2145 | 2145 | if (mode == NL80211_IFTYPE_ADHOC) { |
| 2146 | + u16 enable = true; | |
| 2147 | + | |
| 2148 | + /* set ibss coalescing_status */ | |
| 2149 | + ret = mwifiex_send_cmd( | |
| 2150 | + priv, | |
| 2151 | + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, | |
| 2152 | + HostCmd_ACT_GEN_SET, 0, &enable, true); | |
| 2153 | + if (ret) | |
| 2154 | + return ret; | |
| 2155 | + | |
| 2146 | 2156 | /* "privacy" is set only for ad-hoc mode */ |
| 2147 | 2157 | if (privacy) { |
| 2148 | 2158 | /* |
| @@ -3980,13 +3990,11 @@ static int mwifiex_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, · 1831 unmodified lines | ||
| 3980 | 3990 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); |
| 3981 | 3991 | struct mwifiex_ds_misc_cmd *hostcmd; |
| 3982 | 3992 | struct nlattr *tb[MWIFIEX_TM_ATTR_MAX + 1]; |
| 3983 | − struct mwifiex_adapter *adapter; | |
| 3984 | 3993 | struct sk_buff *skb; |
| 3985 | 3994 | int err; |
| 3986 | 3995 | |
| 3987 | 3996 | if (!priv) |
| 3988 | 3997 | return -EINVAL; |
| 3989 | − adapter = priv->adapter; | |
| 3990 | 3998 | |
| 3991 | 3999 | err = nla_parse(tb, MWIFIEX_TM_ATTR_MAX, data, len, |
| 3992 | 4000 | mwifiex_tm_policy); |
| @@ -219,6 +219,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { · 218 unmodified lines | ||
| 219 | 219 | #define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14)) |
| 220 | 220 | #define ISSUPP_DRCS_ENABLED(FwCapInfo) (FwCapInfo & BIT(15)) |
| 221 | 221 | #define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16)) |
| 222 | +#define ISSUPP_ADHOC_ENABLED(FwCapInfo) (FwCapInfo & BIT(25)) | |
| 222 | 223 | |
| 223 | 224 | #define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ |
| 224 | 225 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \ |
| @@ -518,7 +518,6 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) · 517 unmodified lines | ||
| 518 | 518 | { |
| 519 | 519 | int ret; |
| 520 | 520 | char fmt[64]; |
| 521 | − struct mwifiex_private *priv; | |
| 522 | 521 | struct mwifiex_adapter *adapter = context; |
| 523 | 522 | struct mwifiex_fw_image fw; |
| 524 | 523 | bool init_failed = false; |
| @@ -576,8 +575,6 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) · 51 unmodified lines | ||
| 576 | 575 | goto err_init_fw; |
| 577 | 576 | } |
| 578 | 577 | |
| 579 | − priv = adapter->priv[MWIFIEX_BSS_ROLE_STA]; | |
| 580 | − | |
| 581 | 578 | if (!adapter->wiphy) { |
| 582 | 579 | if (mwifiex_register_cfg80211(adapter)) { |
| 583 | 580 | mwifiex_dbg(adapter, ERROR, |
| @@ -1424,8 +1424,13 @@ static inline void mwifiex_disable_wake(struct mwifiex_adapter *adapter) · 1423 unmodified lines | ||
| 1424 | 1424 | { |
| 1425 | 1425 | if (adapter->irq_wakeup >= 0) { |
| 1426 | 1426 | disable_irq_wake(adapter->irq_wakeup); |
| 1427 | − if (!adapter->wake_by_wifi) | |
| 1428 | − disable_irq(adapter->irq_wakeup); | |
| 1427 | + disable_irq(adapter->irq_wakeup); | |
| 1428 | + if (adapter->wake_by_wifi) | |
| 1429 | + /* Undo our disable, since interrupt handler already | |
| 1430 | + * did this. | |
| 1431 | + */ | |
| 1432 | + enable_irq(adapter->irq_wakeup); | |
| 1433 | + | |
| 1429 | 1434 | } |
| 1430 | 1435 | } |
| 1431 | 1436 | |
| @@ -135,6 +135,7 @@ static int mwifiex_pcie_suspend(struct device *dev) · 134 unmodified lines | ||
| 135 | 135 | mwifiex_dbg(adapter, ERROR, |
| 136 | 136 | "cmd: failed to suspend\n"); |
| 137 | 137 | adapter->hs_enabling = false; |
| 138 | + mwifiex_disable_wake(adapter); | |
| 138 | 139 | return -EFAULT; |
| 139 | 140 | } |
| 140 | 141 | |
| @@ -2050,7 +2051,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, · 1909 unmodified lines | ||
| 2050 | 2051 | } |
| 2051 | 2052 | |
| 2052 | 2053 | /* Wait for the command done interrupt */ |
| 2053 | − do { | |
| 2054 | + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { | |
| 2054 | 2055 | if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS, |
| 2055 | 2056 | &ireg_intr)) { |
| 2056 | 2057 | mwifiex_dbg(adapter, ERROR, |
| @@ -2062,8 +2063,18 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, · 5 unmodified lines | ||
| 2062 | 2063 | ret = -1; |
| 2063 | 2064 | goto done; |
| 2064 | 2065 | } |
| 2065 | − } while ((ireg_intr & CPU_INTR_DOOR_BELL) == | |
| 2066 | − CPU_INTR_DOOR_BELL); | |
| 2066 | + if (!(ireg_intr & CPU_INTR_DOOR_BELL)) | |
| 2067 | + break; | |
| 2068 | + usleep_range(10, 20); | |
| 2069 | + } | |
| 2070 | + if (ireg_intr & CPU_INTR_DOOR_BELL) { | |
| 2071 | + mwifiex_dbg(adapter, ERROR, "%s: Card failed to ACK download\n", | |
| 2072 | + __func__); | |
| 2073 | + mwifiex_unmap_pci_memory(adapter, skb, | |
| 2074 | + PCI_DMA_TODEVICE); | |
| 2075 | + ret = -1; | |
| 2076 | + goto done; | |
| 2077 | + } | |
| 2067 | 2078 | |
| 2068 | 2079 | mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_TODEVICE); |
| 2069 | 2080 | |
| @@ -827,7 +827,6 @@ mwifiex_config_scan(struct mwifiex_private *priv, · 826 unmodified lines | ||
| 827 | 827 | u32 num_probes; |
| 828 | 828 | u32 ssid_len; |
| 829 | 829 | u32 chan_idx; |
| 830 | − u32 chan_num; | |
| 831 | 830 | u32 scan_type; |
| 832 | 831 | u16 scan_dur; |
| 833 | 832 | u8 channel; |
| @@ -1105,13 +1104,12 @@ mwifiex_config_scan(struct mwifiex_private *priv, · 271 unmodified lines | ||
| 1105 | 1104 | mwifiex_dbg(adapter, INFO, |
| 1106 | 1105 | "info: Scan: Scanning current channel only\n"); |
| 1107 | 1106 | } |
| 1108 | − chan_num = chan_idx; | |
| 1109 | 1107 | } else { |
| 1110 | 1108 | mwifiex_dbg(adapter, INFO, |
| 1111 | 1109 | "info: Scan: Creating full region channel list\n"); |
| 1112 | − chan_num = mwifiex_scan_create_channel_list(priv, user_scan_in, | |
| 1113 | − scan_chan_list, | |
| 1114 | − *filtered_scan); | |
| 1110 | + mwifiex_scan_create_channel_list(priv, user_scan_in, | |
| 1111 | + scan_chan_list, | |
| 1112 | + *filtered_scan); | |
| 1115 | 1113 | } |
| 1116 | 1114 | |
| 1117 | 1115 | } |
| @@ -186,9 +186,7 @@ static int mwifiex_sdio_resume(struct device *dev) · 185 unmodified lines | ||
| 186 | 186 | struct sdio_func *func = dev_to_sdio_func(dev); |
| 187 | 187 | struct sdio_mmc_card *card; |
| 188 | 188 | struct mwifiex_adapter *adapter; |
| 189 | − mmc_pm_flag_t pm_flag = 0; | |
| 190 | 189 | |
| 191 | − pm_flag = sdio_get_host_pm_caps(func); | |
| 192 | 190 | card = sdio_get_drvdata(func); |
| 193 | 191 | if (!card || !card->adapter) { |
| 194 | 192 | dev_err(dev, "resume: invalid card or adapter\n"); |
| @@ -298,6 +296,7 @@ static int mwifiex_sdio_suspend(struct device *dev) · 103 unmodified lines | ||
| 298 | 296 | mwifiex_dbg(adapter, ERROR, |
| 299 | 297 | "cmd: failed to suspend\n"); |
| 300 | 298 | adapter->hs_enabling = false; |
| 299 | + mwifiex_disable_wake(adapter); | |
| 301 | 300 | return -EFAULT; |
| 302 | 301 | } |
| 303 | 302 | |
| @@ -1136,7 +1135,6 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, · 832 unmodified lines | ||
| 1136 | 1135 | { |
| 1137 | 1136 | u32 total_pkt_len, pkt_len; |
| 1138 | 1137 | struct sk_buff *skb_deaggr; |
| 1139 | − u32 pkt_type; | |
| 1140 | 1138 | u16 blk_size; |
| 1141 | 1139 | u8 blk_num; |
| 1142 | 1140 | u8 *data; |
| @@ -1157,8 +1155,6 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, · 14 unmodified lines | ||
| 1157 | 1155 | break; |
| 1158 | 1156 | } |
| 1159 | 1157 | pkt_len = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET)); |
| 1160 | − pkt_type = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET + | |
| 1161 | − 2)); | |
| 1162 | 1158 | if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) { |
| 1163 | 1159 | mwifiex_dbg(adapter, ERROR, |
| 1164 | 1160 | "%s: error in pkt_len,\t" |
| @@ -1746,7 +1746,6 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, · 1745 unmodified lines | ||
| 1746 | 1746 | { |
| 1747 | 1747 | struct host_cmd_ds_tdls_oper *tdls_oper = &cmd->params.tdls_oper; |
| 1748 | 1748 | struct mwifiex_ds_tdls_oper *oper = data_buf; |
| 1749 | − struct mwifiex_sta_node *sta_ptr; | |
| 1750 | 1749 | struct host_cmd_tlv_rates *tlv_rates; |
| 1751 | 1750 | struct mwifiex_ie_types_htcap *ht_capab; |
| 1752 | 1751 | struct mwifiex_ie_types_qos_info *wmm_qos_info; |
| @@ -1764,7 +1763,6 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, · 11 unmodified lines | ||
| 1764 | 1763 | |
| 1765 | 1764 | tdls_oper->reason = 0; |
| 1766 | 1765 | memcpy(tdls_oper->peer_mac, oper->peer_mac, ETH_ALEN); |
| 1767 | − sta_ptr = mwifiex_get_sta_entry(priv, oper->peer_mac); | |
| 1768 | 1766 | |
| 1769 | 1767 | pos = (u8 *)tdls_oper + sizeof(struct host_cmd_ds_tdls_oper); |
| 1770 | 1768 | |
| @@ -1902,6 +1900,24 @@ static int mwifiex_cmd_get_wakeup_reason(struct mwifiex_private *priv, · 131 unmodified lines | ||
| 1902 | 1900 | return 0; |
| 1903 | 1901 | } |
| 1904 | 1902 | |
| 1903 | +/* This function check if the command is supported by firmware */ | |
| 1904 | +static int mwifiex_is_cmd_supported(struct mwifiex_private *priv, u16 cmd_no) | |
| 1905 | +{ | |
| 1906 | + if (!ISSUPP_ADHOC_ENABLED(priv->adapter->fw_cap_info)) { | |
| 1907 | + switch (cmd_no) { | |
| 1908 | + case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: | |
| 1909 | + case HostCmd_CMD_802_11_AD_HOC_START: | |
| 1910 | + case HostCmd_CMD_802_11_AD_HOC_JOIN: | |
| 1911 | + case HostCmd_CMD_802_11_AD_HOC_STOP: | |
| 1912 | + return -EOPNOTSUPP; | |
| 1913 | + default: | |
| 1914 | + break; | |
| 1915 | + } | |
| 1916 | + } | |
| 1917 | + | |
| 1918 | + return 0; | |
| 1919 | +} | |
| 1920 | + | |
| 1905 | 1921 | /* |
| 1906 | 1922 | * This function prepares the commands before sending them to the firmware. |
| 1907 | 1923 | * |
| @@ -1915,6 +1931,13 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, · 7 unmodified lines | ||
| 1915 | 1931 | struct host_cmd_ds_command *cmd_ptr = cmd_buf; |
| 1916 | 1932 | int ret = 0; |
| 1917 | 1933 | |
| 1934 | + if (mwifiex_is_cmd_supported(priv, cmd_no)) { | |
| 1935 | + mwifiex_dbg(priv->adapter, ERROR, | |
| 1936 | + "0x%x command not supported by firmware\n", | |
| 1937 | + cmd_no); | |
| 1938 | + return -EOPNOTSUPP; | |
| 1939 | + } | |
| 1940 | + | |
| 1918 | 1941 | /* Prepare command */ |
| 1919 | 1942 | switch (cmd_no) { |
| 1920 | 1943 | case HostCmd_CMD_GET_HW_SPEC: |
| @@ -2208,7 +2231,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) · 287 unmodified lines | ||
| 2208 | 2231 | { |
| 2209 | 2232 | struct mwifiex_adapter *adapter = priv->adapter; |
| 2210 | 2233 | int ret; |
| 2211 | − u16 enable = true; | |
| 2212 | 2234 | struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; |
| 2213 | 2235 | struct mwifiex_ds_auto_ds auto_ds; |
| 2214 | 2236 | enum state_11d_t state_11d; |
| @@ -2321,16 +2343,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) · 106 unmodified lines | ||
| 2321 | 2343 | if (ret) |
| 2322 | 2344 | return -1; |
| 2323 | 2345 | |
| 2324 | − if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) { | |
| 2325 | − /* set ibss coalescing_status */ | |
| 2326 | − ret = mwifiex_send_cmd( | |
| 2327 | − priv, | |
| 2328 | − HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, | |
| 2329 | − HostCmd_ACT_GEN_SET, 0, &enable, true); | |
| 2330 | − if (ret) | |
| 2331 | − return -1; | |
| 2332 | − } | |
| 2333 | − | |
| 2334 | 2346 | memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); |
| 2335 | 2347 | amsdu_aggr_ctrl.enable = true; |
| 2336 | 2348 | /* Send request to firmware */ |
| @@ -379,7 +379,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf, · 378 unmodified lines | ||
| 379 | 379 | struct usb_endpoint_descriptor *epd; |
| 380 | 380 | int ret, i; |
| 381 | 381 | struct usb_card_rec *card; |
| 382 | − u16 id_vendor, id_product, bcd_device, bcd_usb; | |
| 382 | + u16 id_vendor, id_product, bcd_device; | |
| 383 | 383 | |
| 384 | 384 | card = devm_kzalloc(&intf->dev, sizeof(*card), GFP_KERNEL); |
| 385 | 385 | if (!card) |
| @@ -390,7 +390,6 @@ static int mwifiex_usb_probe(struct usb_interface *intf, · 4 unmodified lines | ||
| 390 | 390 | id_vendor = le16_to_cpu(udev->descriptor.idVendor); |
| 391 | 391 | id_product = le16_to_cpu(udev->descriptor.idProduct); |
| 392 | 392 | bcd_device = le16_to_cpu(udev->descriptor.bcdDevice); |
| 393 | − bcd_usb = le16_to_cpu(udev->descriptor.bcdUSB); | |
| 394 | 393 | pr_debug("info: VID/PID = %X/%X, Boot2 version = %X\n", |
| 395 | 394 | id_vendor, id_product, bcd_device); |
| 396 | 395 | |
| @@ -293,13 +293,13 @@ static void mt7601u_mac_stop_hw(struct mt7601u_dev *dev) · 292 unmodified lines | ||
| 293 | 293 | ok = 0; |
| 294 | 294 | i = 200; |
| 295 | 295 | while (i--) { |
| 296 | − if ((mt76_rr(dev, 0x0430) & 0x00ff0000) || | |
| 297 | − (mt76_rr(dev, 0x0a30) & 0xffffffff) || | |
| 298 | − (mt76_rr(dev, 0x0a34) & 0xffffffff)) | |
| 299 | − ok++; | |
| 300 | − if (ok > 6) | |
| 301 | − break; | |
| 302 | − | |
| 296 | + if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && | |
| 297 | + !mt76_rr(dev, 0x0a30) && | |
| 298 | + !mt76_rr(dev, 0x0a34)) { | |
| 299 | + if (ok++ > 5) | |
| 300 | + break; | |
| 301 | + continue; | |
| 302 | + } | |
| 303 | 303 | msleep(1); |
| 304 | 304 | } |
| 305 | 305 | |
| @@ -192,6 +192,9 @@ · 191 unmodified lines | ||
| 192 | 192 | #define MT_BCN_OFFSET_BASE 0x041c |
| 193 | 193 | #define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2)) |
| 194 | 194 | |
| 195 | +#define MT_RXQ_STA 0x0430 | |
| 196 | +#define MT_TXQ_STA 0x0434 | |
| 197 | + | |
| 195 | 198 | #define MT_RF_CSR_CFG 0x0500 |
| 196 | 199 | #define MT_RF_CSR_CFG_DATA GENMASK(7, 0) |
| 197 | 200 | #define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8) |
| @@ -1337,10 +1337,11 @@ struct rtl8xxxu_fileops { · 1336 unmodified lines | ||
| 1337 | 1337 | u32 ramask, int sgi); |
| 1338 | 1338 | void (*report_connect) (struct rtl8xxxu_priv *priv, |
| 1339 | 1339 | u8 macid, bool connect); |
| 1340 | − void (*fill_txdesc) (struct ieee80211_hdr *hdr, | |
| 1341 | − struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, | |
| 1342 | − u16 rate_flag, bool sgi, bool short_preamble, | |
| 1343 | − bool ampdu_enable); | |
| 1340 | + void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, | |
| 1341 | + struct ieee80211_tx_info *tx_info, | |
| 1342 | + struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, | |
| 1343 | + bool short_preamble, bool ampdu_enable, | |
| 1344 | + u32 rts_rate); | |
| 1344 | 1345 | int writeN_block_size; |
| 1345 | 1346 | int rx_agg_buf_size; |
| 1346 | 1347 | char tx_desc_size; |
| @@ -1434,14 +1435,16 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb); · 87 unmodified lines | ||
| 1434 | 1435 | int rtl8xxxu_gen2_channel_to_group(int channel); |
| 1435 | 1436 | bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv, |
| 1436 | 1437 | int result[][8], int c1, int c2); |
| 1437 | −void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hdr *hdr, | |
| 1438 | − struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, | |
| 1439 | − u16 rate_flag, bool sgi, bool short_preamble, | |
| 1440 | − bool ampdu_enable); | |
| 1441 | −void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hdr *hdr, | |
| 1442 | − struct rtl8xxxu_txdesc32 *tx_desc32, u32 rate, | |
| 1443 | − u16 rate_flag, bool sgi, bool short_preamble, | |
| 1444 | − bool ampdu_enable); | |
| 1438 | +void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, | |
| 1439 | + struct ieee80211_tx_info *tx_info, | |
| 1440 | + struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, | |
| 1441 | + bool short_preamble, bool ampdu_enable, | |
| 1442 | + u32 rts_rate); | |
| 1443 | +void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, | |
| 1444 | + struct ieee80211_tx_info *tx_info, | |
| 1445 | + struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, | |
| 1446 | + bool short_preamble, bool ampdu_enable, | |
| 1447 | + u32 rts_rate); | |
| 1445 | 1448 | |
| 1446 | 1449 | extern struct rtl8xxxu_fileops rtl8192cu_fops; |
| 1447 | 1450 | extern struct rtl8xxxu_fileops rtl8192eu_fops; |
| @@ -1556,7 +1556,7 @@ exit: · 1555 unmodified lines | ||
| 1556 | 1556 | return ret; |
| 1557 | 1557 | } |
| 1558 | 1558 | |
| 1559 | −void rtl8192eu_power_off(struct rtl8xxxu_priv *priv) | |
| 1559 | +static void rtl8192eu_power_off(struct rtl8xxxu_priv *priv) | |
| 1560 | 1560 | { |
| 1561 | 1561 | u8 val8; |
| 1562 | 1562 | u16 val16; |
| @@ -4372,6 +4372,13 @@ void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, · 4371 unmodified lines | ||
| 4372 | 4372 | void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, |
| 4373 | 4373 | u8 macid, bool connect) |
| 4374 | 4374 | { |
| 4375 | +#ifdef RTL8XXXU_GEN2_REPORT_CONNECT | |
| 4376 | + /* | |
| 4377 | + * Barry Day reports this causes issues with 8192eu and 8723bu | |
| 4378 | + * devices reconnecting. The reason for this is unclear, but | |
| 4379 | + * until it is better understood, leave the code in place but | |
| 4380 | + * disabled, so it is not lost. | |
| 4381 | + */ | |
| 4375 | 4382 | struct h2c_cmd h2c; |
| 4376 | 4383 | |
| 4377 | 4384 | memset(&h2c, 0, sizeof(struct h2c_cmd)); |
| @@ -4383,6 +4390,7 @@ void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, · 5 unmodified lines | ||
| 4383 | 4390 | h2c.media_status_rpt.parm &= ~BIT(0); |
| 4384 | 4391 | |
| 4385 | 4392 | rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt)); |
| 4393 | +#endif | |
| 4386 | 4394 | } |
| 4387 | 4395 | |
| 4388 | 4396 | void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv) |
| @@ -4759,13 +4767,28 @@ static void rtl8xxxu_dump_action(struct device *dev, · 370 unmodified lines | ||
| 4759 | 4767 | * This format is used on 8188cu/8192cu/8723au |
| 4760 | 4768 | */ |
| 4761 | 4769 | void |
| 4762 | −rtl8xxxu_fill_txdesc_v1(struct ieee80211_hdr *hdr, | |
| 4763 | − struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, | |
| 4764 | − u16 rate_flag, bool sgi, bool short_preamble, | |
| 4765 | − bool ampdu_enable) | |
| 4770 | +rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, | |
| 4771 | + struct ieee80211_tx_info *tx_info, | |
| 4772 | + struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, | |
| 4773 | + bool short_preamble, bool ampdu_enable, u32 rts_rate) | |
| 4766 | 4774 | { |
| 4775 | + struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); | |
| 4776 | + struct rtl8xxxu_priv *priv = hw->priv; | |
| 4777 | + struct device *dev = &priv->udev->dev; | |
| 4778 | + u32 rate; | |
| 4779 | + u16 rate_flags = tx_info->control.rates[0].flags; | |
| 4767 | 4780 | u16 seq_number; |
| 4768 | 4781 | |
| 4782 | + if (rate_flags & IEEE80211_TX_RC_MCS && | |
| 4783 | + !ieee80211_is_mgmt(hdr->frame_control)) | |
| 4784 | + rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; | |
| 4785 | + else | |
| 4786 | + rate = tx_rate->hw_value; | |
| 4787 | + | |
| 4788 | + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) | |
| 4789 | + dev_info(dev, "%s: TX rate: %d, pkt size %d\n", | |
| 4790 | + __func__, rate, cpu_to_le16(tx_desc->pkt_size)); | |
| 4791 | + | |
| 4769 | 4792 | seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); |
| 4770 | 4793 | |
| 4771 | 4794 | tx_desc->txdw5 = cpu_to_le32(rate); |
| @@ -4796,15 +4819,16 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hdr *hdr, · 24 unmodified lines | ||
| 4796 | 4819 | if (sgi) |
| 4797 | 4820 | tx_desc->txdw5 |= cpu_to_le32(TXDESC32_SHORT_GI); |
| 4798 | 4821 | |
| 4799 | − if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { | |
| 4800 | − /* | |
| 4801 | − * Use RTS rate 24M - does the mac80211 tell | |
| 4802 | − * us which to use? | |
| 4803 | − */ | |
| 4804 | − tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M << | |
| 4805 | − TXDESC32_RTS_RATE_SHIFT); | |
| 4822 | + /* | |
| 4823 | + * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled | |
| 4824 | + */ | |
| 4825 | + tx_desc->txdw4 |= cpu_to_le32(rts_rate << TXDESC32_RTS_RATE_SHIFT); | |
| 4826 | + if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { | |
| 4806 | 4827 | tx_desc->txdw4 |= cpu_to_le32(TXDESC32_RTS_CTS_ENABLE); |
| 4807 | 4828 | tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); |
| 4829 | + } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { | |
| 4830 | + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_CTS_SELF_ENABLE); | |
| 4831 | + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); | |
| 4808 | 4832 | } |
| 4809 | 4833 | } |
| 4810 | 4834 | |
| @@ -4813,16 +4837,31 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hdr *hdr, · 2 unmodified lines | ||
| 4813 | 4837 | * This format is used on 8192eu/8723bu |
| 4814 | 4838 | */ |
| 4815 | 4839 | void |
| 4816 | −rtl8xxxu_fill_txdesc_v2(struct ieee80211_hdr *hdr, | |
| 4817 | − struct rtl8xxxu_txdesc32 *tx_desc32, u32 rate, | |
| 4818 | − u16 rate_flag, bool sgi, bool short_preamble, | |
| 4819 | − bool ampdu_enable) | |
| 4840 | +rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, | |
| 4841 | + struct ieee80211_tx_info *tx_info, | |
| 4842 | + struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, | |
| 4843 | + bool short_preamble, bool ampdu_enable, u32 rts_rate) | |
| 4820 | 4844 | { |
| 4845 | + struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); | |
| 4846 | + struct rtl8xxxu_priv *priv = hw->priv; | |
| 4847 | + struct device *dev = &priv->udev->dev; | |
| 4821 | 4848 | struct rtl8xxxu_txdesc40 *tx_desc40; |
| 4849 | + u32 rate; | |
| 4850 | + u16 rate_flags = tx_info->control.rates[0].flags; | |
| 4822 | 4851 | u16 seq_number; |
| 4823 | 4852 | |
| 4824 | 4853 | tx_desc40 = (struct rtl8xxxu_txdesc40 *)tx_desc32; |
| 4825 | 4854 | |
| 4855 | + if (rate_flags & IEEE80211_TX_RC_MCS && | |
| 4856 | + !ieee80211_is_mgmt(hdr->frame_control)) | |
| 4857 | + rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; | |
| 4858 | + else | |
| 4859 | + rate = tx_rate->hw_value; | |
| 4860 | + | |
| 4861 | + if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) | |
| 4862 | + dev_info(dev, "%s: TX rate: %d, pkt size %d\n", | |
| 4863 | + __func__, rate, cpu_to_le16(tx_desc40->pkt_size)); | |
| 4864 | + | |
| 4826 | 4865 | seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); |
| 4827 | 4866 | |
| 4828 | 4867 | tx_desc40->txdw4 = cpu_to_le32(rate); |
| @@ -4849,15 +4888,19 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hdr *hdr, · 20 unmodified lines | ||
| 4849 | 4888 | if (short_preamble) |
| 4850 | 4889 | tx_desc40->txdw5 |= cpu_to_le32(TXDESC40_SHORT_PREAMBLE); |
| 4851 | 4890 | |
| 4852 | − if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { | |
| 4853 | − /* | |
| 4854 | − * Use RTS rate 24M - does the mac80211 tell | |
| 4855 | − * us which to use? | |
| 4856 | − */ | |
| 4857 | − tx_desc40->txdw4 |= cpu_to_le32(DESC_RATE_24M << | |
| 4858 | − TXDESC40_RTS_RATE_SHIFT); | |
| 4891 | + tx_desc40->txdw4 |= cpu_to_le32(rts_rate << TXDESC40_RTS_RATE_SHIFT); | |
| 4892 | + /* | |
| 4893 | + * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled | |
| 4894 | + */ | |
| 4895 | + if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { | |
| 4859 | 4896 | tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_RTS_CTS_ENABLE); |
| 4860 | 4897 | tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_HW_RTS_ENABLE); |
| 4898 | + } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { | |
| 4899 | + /* | |
| 4900 | + * For some reason the vendor driver doesn't set | |
| 4901 | + * TXDESC40_HW_RTS_ENABLE for CTS to SELF | |
| 4902 | + */ | |
| 4903 | + tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_CTS_SELF_ENABLE); | |
| 4861 | 4904 | } |
| 4862 | 4905 | } |
| 4863 | 4906 | |
| @@ -4867,14 +4910,13 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, · 3 unmodified lines | ||
| 4867 | 4910 | { |
| 4868 | 4911 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
| 4869 | 4912 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
| 4870 | − struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); | |
| 4871 | 4913 | struct rtl8xxxu_priv *priv = hw->priv; |
| 4872 | 4914 | struct rtl8xxxu_txdesc32 *tx_desc; |
| 4873 | 4915 | struct rtl8xxxu_tx_urb *tx_urb; |
| 4874 | 4916 | struct ieee80211_sta *sta = NULL; |
| 4875 | 4917 | struct ieee80211_vif *vif = tx_info->control.vif; |
| 4876 | 4918 | struct device *dev = &priv->udev->dev; |
| 4877 | − u32 queue, rate; | |
| 4919 | + u32 queue, rts_rate; | |
| 4878 | 4920 | u16 pktlen = skb->len; |
| 4879 | 4921 | u16 seq_number; |
| 4880 | 4922 | u16 rate_flag = tx_info->control.rates[0].flags; |
| @@ -4901,10 +4943,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, · 20 unmodified lines | ||
| 4901 | 4943 | goto error; |
| 4902 | 4944 | } |
| 4903 | 4945 | |
| 4904 | − if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) | |
| 4905 | − dev_info(dev, "%s: TX rate: %d (%d), pkt size %d\n", | |
| 4906 | − __func__, tx_rate->bitrate, tx_rate->hw_value, pktlen); | |
| 4907 | − | |
| 4908 | 4946 | if (ieee80211_is_action(hdr->frame_control)) |
| 4909 | 4947 | rtl8xxxu_dump_action(dev, hdr); |
| 4910 | 4948 | |
| @@ -4958,12 +4996,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, · 47 unmodified lines | ||
| 4958 | 4996 | } |
| 4959 | 4997 | } |
| 4960 | 4998 | |
| 4961 | − if (rate_flag & IEEE80211_TX_RC_MCS && | |
| 4962 | − !ieee80211_is_mgmt(hdr->frame_control)) | |
| 4963 | − rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; | |
| 4964 | − else | |
| 4965 | − rate = tx_rate->hw_value; | |
| 4966 | − | |
| 4967 | 4999 | if (rate_flag & IEEE80211_TX_RC_SHORT_GI || |
| 4968 | 5000 | (ieee80211_is_data_qos(hdr->frame_control) && |
| 4969 | 5001 | sta && sta->ht_cap.cap & |
| @@ -4974,10 +5006,17 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, · 4 unmodified lines | ||
| 4974 | 5006 | (sta && vif && vif->bss_conf.use_short_preamble)) |
| 4975 | 5007 | short_preamble = true; |
| 4976 | 5008 | |
| 5009 | + if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) | |
| 5010 | + rts_rate = ieee80211_get_rts_cts_rate(hw, tx_info)->hw_value; | |
| 5011 | + else if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) | |
| 5012 | + rts_rate = ieee80211_get_rts_cts_rate(hw, tx_info)->hw_value; | |
| 5013 | + else | |
| 5014 | + rts_rate = 0; | |
| 5015 | + | |
| 4977 | 5016 | seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); |
| 4978 | 5017 | |
| 4979 | − priv->fops->fill_txdesc(hdr, tx_desc, rate, rate_flag, | |
| 4980 | − sgi, short_preamble, ampdu_enable); | |
| 5018 | + priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble, | |
| 5019 | + ampdu_enable, rts_rate); | |
| 4981 | 5020 | |
| 4982 | 5021 | rtl8xxxu_calc_tx_desc_csum(tx_desc); |
| 4983 | 5022 | |
| @@ -1303,12 +1303,13 @@ EXPORT_SYMBOL_GPL(rtl_action_proc); · 1302 unmodified lines | ||
| 1303 | 1303 | |
| 1304 | 1304 | static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc) |
| 1305 | 1305 | { |
| 1306 | + struct ieee80211_hw *hw = rtlpriv->hw; | |
| 1307 | + | |
| 1306 | 1308 | rtlpriv->ra.is_special_data = true; |
| 1307 | 1309 | if (rtlpriv->cfg->ops->get_btc_status()) |
| 1308 | 1310 | rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( |
| 1309 | 1311 | rtlpriv, 1); |
| 1310 | − rtlpriv->enter_ps = false; | |
| 1311 | − schedule_work(&rtlpriv->works.lps_change_work); | |
| 1312 | + rtl_lps_leave(hw); | |
| 1312 | 1313 | ppsc->last_delaylps_stamp_jiffies = jiffies; |
| 1313 | 1314 | } |
| 1314 | 1315 | |
| @@ -1381,8 +1382,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, · 66 unmodified lines | ||
| 1381 | 1382 | |
| 1382 | 1383 | if (is_tx) { |
| 1383 | 1384 | rtlpriv->ra.is_special_data = true; |
| 1384 | − rtlpriv->enter_ps = false; | |
| 1385 | − schedule_work(&rtlpriv->works.lps_change_work); | |
| 1385 | + rtl_lps_leave(hw); | |
| 1386 | 1386 | ppsc->last_delaylps_stamp_jiffies = jiffies; |
| 1387 | 1387 | } |
| 1388 | 1388 | |
| @@ -1150,10 +1150,8 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, · 1149 unmodified lines | ||
| 1150 | 1150 | } else { |
| 1151 | 1151 | mstatus = RT_MEDIA_DISCONNECT; |
| 1152 | 1152 | |
| 1153 | − if (mac->link_state == MAC80211_LINKED) { | |
| 1154 | − rtlpriv->enter_ps = false; | |
| 1155 | − schedule_work(&rtlpriv->works.lps_change_work); | |
| 1156 | − } | |
| 1153 | + if (mac->link_state == MAC80211_LINKED) | |
| 1154 | + rtl_lps_leave(hw); | |
| 1157 | 1155 | if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE) |
| 1158 | 1156 | rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); |
| 1159 | 1157 | mac->link_state = MAC80211_NOLINK; |
| @@ -1431,8 +1429,7 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw, · 271 unmodified lines | ||
| 1431 | 1429 | } |
| 1432 | 1430 | |
| 1433 | 1431 | if (mac->link_state == MAC80211_LINKED) { |
| 1434 | − rtlpriv->enter_ps = false; | |
| 1435 | − schedule_work(&rtlpriv->works.lps_change_work); | |
| 1432 | + rtl_lps_leave(hw); | |
| 1436 | 1433 | mac->link_state = MAC80211_LINKED_SCANNING; |
| 1437 | 1434 | } else { |
| 1438 | 1435 | rtl_ips_nic_on(hw); |
| @@ -659,11 +659,9 @@ tx_status_ok: · 658 unmodified lines | ||
| 659 | 659 | } |
| 660 | 660 | |
| 661 | 661 | if (((rtlpriv->link_info.num_rx_inperiod + |
| 662 | − rtlpriv->link_info.num_tx_inperiod) > 8) || | |
| 663 | − (rtlpriv->link_info.num_rx_inperiod > 2)) { | |
| 664 | − rtlpriv->enter_ps = false; | |
| 665 | − schedule_work(&rtlpriv->works.lps_change_work); | |
| 666 | − } | |
| 662 | + rtlpriv->link_info.num_tx_inperiod) > 8) || | |
| 663 | + (rtlpriv->link_info.num_rx_inperiod > 2)) | |
| 664 | + rtl_lps_leave(hw); | |
| 667 | 665 | } |
| 668 | 666 | |
| 669 | 667 | static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, |
| @@ -914,10 +912,8 @@ new_trx_end: · 244 unmodified lines | ||
| 914 | 912 | } |
| 915 | 913 | if (((rtlpriv->link_info.num_rx_inperiod + |
| 916 | 914 | rtlpriv->link_info.num_tx_inperiod) > 8) || |
| 917 | − (rtlpriv->link_info.num_rx_inperiod > 2)) { | |
| 918 | − rtlpriv->enter_ps = false; | |
| 919 | − schedule_work(&rtlpriv->works.lps_change_work); | |
| 920 | − } | |
| 915 | + (rtlpriv->link_info.num_rx_inperiod > 2)) | |
| 916 | + rtl_lps_leave(hw); | |
| 921 | 917 | skb = new_skb; |
| 922 | 918 | no_new: |
| 923 | 919 | if (rtlpriv->use_new_trx_flow) { |
| @@ -407,8 +407,8 @@ void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) · 406 unmodified lines | ||
| 407 | 407 | } |
| 408 | 408 | } |
| 409 | 409 | |
| 410 | −/*Enter the leisure power save mode.*/ | |
| 411 | −void rtl_lps_enter(struct ieee80211_hw *hw) | |
| 410 | +/* Interrupt safe routine to enter the leisure power save mode.*/ | |
| 411 | +static void rtl_lps_enter_core(struct ieee80211_hw *hw) | |
| 412 | 412 | { |
| 413 | 413 | struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); |
| 414 | 414 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); |
| @@ -444,10 +444,9 @@ void rtl_lps_enter(struct ieee80211_hw *hw) · 29 unmodified lines | ||
| 444 | 444 | |
| 445 | 445 | spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); |
| 446 | 446 | } |
| 447 | −EXPORT_SYMBOL(rtl_lps_enter); | |
| 448 | 447 | |
| 449 | −/*Leave the leisure power save mode.*/ | |
| 450 | −void rtl_lps_leave(struct ieee80211_hw *hw) | |
| 448 | +/* Interrupt safe routine to leave the leisure power save mode.*/ | |
| 449 | +static void rtl_lps_leave_core(struct ieee80211_hw *hw) | |
| 451 | 450 | { |
| 452 | 451 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
| 453 | 452 | struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); |
| @@ -477,7 +476,6 @@ void rtl_lps_leave(struct ieee80211_hw *hw) · 23 unmodified lines | ||
| 477 | 476 | } |
| 478 | 477 | spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); |
| 479 | 478 | } |
| 480 | −EXPORT_SYMBOL(rtl_lps_leave); | |
| 481 | 479 | |
| 482 | 480 | /* For sw LPS*/ |
| 483 | 481 | void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) |
| @@ -670,12 +668,34 @@ void rtl_lps_change_work_callback(struct work_struct *work) · 186 unmodified lines | ||
| 670 | 668 | struct rtl_priv *rtlpriv = rtl_priv(hw); |
| 671 | 669 | |
| 672 | 670 | if (rtlpriv->enter_ps) |
| 673 | − rtl_lps_enter(hw); | |
| 671 | + rtl_lps_enter_core(hw); | |
| 674 | 672 | else |
| 675 | − rtl_lps_leave(hw); | |
| 673 | + rtl_lps_leave_core(hw); | |
| 676 | 674 | } |
| 677 | 675 | EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback); |
| 678 | 676 | |
| 677 | +void rtl_lps_enter(struct ieee80211_hw *hw) | |
| 678 | +{ | |
| 679 | + struct rtl_priv *rtlpriv = rtl_priv(hw); | |
| 680 | + | |
| 681 | + if (!in_interrupt()) | |
| 682 | + return rtl_lps_enter_core(hw); | |
| 683 | + rtlpriv->enter_ps = true; | |
| 684 | + schedule_work(&rtlpriv->works.lps_change_work); | |
| 685 | +} | |
| 686 | +EXPORT_SYMBOL_GPL(rtl_lps_enter); | |
| 687 | + | |
| 688 | +void rtl_lps_leave(struct ieee80211_hw *hw) | |
| 689 | +{ | |
| 690 | + struct rtl_priv *rtlpriv = rtl_priv(hw); | |
| 691 | + | |
| 692 | + if (!in_interrupt()) | |
| 693 | + return rtl_lps_leave_core(hw); | |
| 694 | + rtlpriv->enter_ps = false; | |
| 695 | + schedule_work(&rtlpriv->works.lps_change_work); | |
| 696 | +} | |
| 697 | +EXPORT_SYMBOL_GPL(rtl_lps_leave); | |
| 698 | + | |
| 679 | 699 | void rtl_swlps_wq_callback(void *data) |
| 680 | 700 | { |
| 681 | 701 | struct rtl_works *rtlworks = container_of_dwork_rtl(data, |
| @@ -275,6 +275,8 @@ static int rsi_mac80211_start(struct ieee80211_hw *hw) · 274 unmodified lines | ||
| 275 | 275 | common->iface_down = false; |
| 276 | 276 | mutex_unlock(&common->mutex); |
| 277 | 277 | |
| 278 | + rsi_send_rx_filter_frame(common, 0); | |
| 279 | + | |
| 278 | 280 | return 0; |
| 279 | 281 | } |
| 280 | 282 | |
| @@ -388,7 +390,7 @@ static int rsi_channel_change(struct ieee80211_hw *hw) · 107 unmodified lines | ||
| 388 | 390 | |
| 389 | 391 | status = rsi_band_check(common); |
| 390 | 392 | if (!status) |
| 391 | − status = rsi_set_channel(adapter->priv, channel); | |
| 393 | + status = rsi_set_channel(adapter->priv, curchan); | |
| 392 | 394 | |
| 393 | 395 | if (bss->assoc) { |
| 394 | 396 | if (common->hw_data_qs_blocked && |
| @@ -408,6 +410,34 @@ static int rsi_channel_change(struct ieee80211_hw *hw) · 13 unmodified lines | ||
| 408 | 410 | return status; |
| 409 | 411 | } |
| 410 | 412 | |
| 413 | +/** | |
| 414 | + * rsi_config_power() - This function configures tx power to device | |
| 415 | + * @hw: Pointer to the ieee80211_hw structure. | |
| 416 | + * | |
| 417 | + * Return: 0 on success, negative error code on failure. | |
| 418 | + */ | |
| 419 | +static int rsi_config_power(struct ieee80211_hw *hw) | |
| 420 | +{ | |
| 421 | + struct rsi_hw *adapter = hw->priv; | |
| 422 | + struct rsi_common *common = adapter->priv; | |
| 423 | + struct ieee80211_conf *conf = &hw->conf; | |
| 424 | + | |
| 425 | + if (adapter->sc_nvifs <= 0) { | |
| 426 | + rsi_dbg(ERR_ZONE, "%s: No virtual interface found\n", __func__); | |
| 427 | + return -EINVAL; | |
| 428 | + } | |
| 429 | + | |
| 430 | + rsi_dbg(INFO_ZONE, | |
| 431 | + "%s: Set tx power: %d dBM\n", __func__, conf->power_level); | |
| 432 | + | |
| 433 | + if (conf->power_level == common->tx_power) | |
| 434 | + return 0; | |
| 435 | + | |
| 436 | + common->tx_power = conf->power_level; | |
| 437 | + | |
| 438 | + return rsi_send_radio_params_update(common); | |
| 439 | +} | |
| 440 | + | |
| 411 | 441 | /** |
| 412 | 442 | * rsi_mac80211_config() - This function is a handler for configuration |
| 413 | 443 | * requests. The stack calls this function to |
| @@ -429,6 +459,12 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, · 15 unmodified lines | ||
| 429 | 459 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) |
| 430 | 460 | status = rsi_channel_change(hw); |
| 431 | 461 | |
| 462 | + /* tx power */ | |
| 463 | + if (changed & IEEE80211_CONF_CHANGE_POWER) { | |
| 464 | + rsi_dbg(INFO_ZONE, "%s: Configuring Power\n", __func__); | |
| 465 | + status = rsi_config_power(hw); | |
| 466 | + } | |
| 467 | + | |
| 432 | 468 | mutex_unlock(&common->mutex); |
| 433 | 469 | |
| 434 | 470 | return status; |
| @@ -471,11 +507,19 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, · 36 unmodified lines | ||
| 471 | 507 | { |
| 472 | 508 | struct rsi_hw *adapter = hw->priv; |
| 473 | 509 | struct rsi_common *common = adapter->priv; |
| 510 | + u16 rx_filter_word = 0; | |
| 474 | 511 | |
| 475 | 512 | mutex_lock(&common->mutex); |
| 476 | 513 | if (changed & BSS_CHANGED_ASSOC) { |
| 477 | 514 | rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", |
| 478 | 515 | __func__, bss_conf->assoc); |
| 516 | + if (bss_conf->assoc) { | |
| 517 | + /* Send the RX filter frame */ | |
| 518 | + rx_filter_word = (ALLOW_DATA_ASSOC_PEER | | |
| 519 | + ALLOW_CTRL_ASSOC_PEER | | |
| 520 | + ALLOW_MGMT_ASSOC_PEER); | |
| 521 | + rsi_send_rx_filter_frame(common, rx_filter_word); | |
| 522 | + } | |
| 479 | 523 | rsi_inform_bss_status(common, |
| 480 | 524 | bss_conf->assoc, |
| 481 | 525 | bss_conf->bssid, |
| @@ -1013,6 +1057,7 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, · 531 unmodified lines | ||
| 1013 | 1057 | struct rsi_common *common = adapter->priv; |
| 1014 | 1058 | |
| 1015 | 1059 | mutex_lock(&common->mutex); |
| 1060 | + | |
| 1016 | 1061 | /* Resetting all the fields to default values */ |
| 1017 | 1062 | common->bitrate_mask[NL80211_BAND_2GHZ] = 0; |
| 1018 | 1063 | common->bitrate_mask[NL80211_BAND_5GHZ] = 0; |
| @@ -1022,9 +1067,114 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, · 3 unmodified lines | ||
| 1022 | 1067 | common->vif_info[0].seq_start = 0; |
| 1023 | 1068 | common->secinfo.ptk_cipher = 0; |
| 1024 | 1069 | common->secinfo.gtk_cipher = 0; |
| 1070 | + | |
| 1071 | + rsi_send_rx_filter_frame(common, 0); | |
| 1072 | + | |
| 1025 | 1073 | mutex_unlock(&common->mutex); |
| 1074 | + | |
| 1075 | + return 0; | |
| 1076 | +} | |
| 1077 | + | |
| 1078 | +/** | |
| 1079 | + * rsi_mac80211_set_antenna() - This function is used to configure | |
| 1080 | + * tx and rx antennas. | |
| 1081 | + * @hw: Pointer to the ieee80211_hw structure. | |
| 1082 | + * @tx_ant: Bitmap for tx antenna | |
| 1083 | + * @rx_ant: Bitmap for rx antenna | |
| 1084 | + * | |
| 1085 | + * Return: 0 on success, Negative error code on failure. | |
| 1086 | + */ | |
| 1087 | +static int rsi_mac80211_set_antenna(struct ieee80211_hw *hw, | |
| 1088 | + u32 tx_ant, u32 rx_ant) | |
| 1089 | +{ | |
| 1090 | + struct rsi_hw *adapter = hw->priv; | |
| 1091 | + struct rsi_common *common = adapter->priv; | |
| 1092 | + u8 antenna = 0; | |
| 1026 | 1093 | |
| 1094 | + if (tx_ant > 1 || rx_ant > 1) { | |
| 1095 | + rsi_dbg(ERR_ZONE, | |
| 1096 | + "Invalid antenna selection (tx: %d, rx:%d)\n", | |
| 1097 | + tx_ant, rx_ant); | |
| 1098 | + rsi_dbg(ERR_ZONE, | |
| 1099 | + "Use 0 for int_ant, 1 for ext_ant\n"); | |
| 1100 | + return -EINVAL; | |
| 1101 | + } | |
| 1102 | + | |
| 1103 | + rsi_dbg(INFO_ZONE, "%s: Antenna map Tx %x Rx %d\n", | |
| 1104 | + __func__, tx_ant, rx_ant); | |
| 1105 | + | |
| 1106 | + mutex_lock(&common->mutex); | |
| 1107 | + | |
| 1108 | + antenna = tx_ant ? ANTENNA_SEL_UFL : ANTENNA_SEL_INT; | |
| 1109 | + if (common->ant_in_use != antenna) | |
| 1110 | + if (rsi_set_antenna(common, antenna)) | |
| 1111 | + goto fail_set_antenna; | |
| 1112 | + | |
| 1113 | + rsi_dbg(INFO_ZONE, "(%s) Antenna path configured successfully\n", | |
| 1114 | + tx_ant ? "UFL" : "INT"); | |
| 1115 | + | |
| 1116 | + common->ant_in_use = antenna; | |
| 1117 | + | |
| 1118 | + mutex_unlock(&common->mutex); | |
| 1119 | + | |
| 1027 | 1120 | return 0; |
| 1121 | + | |
| 1122 | +fail_set_antenna: | |
| 1123 | + rsi_dbg(ERR_ZONE, "%s: Failed.\n", __func__); | |
| 1124 | + mutex_unlock(&common->mutex); | |
| 1125 | + return -EINVAL; | |
| 1126 | +} | |
| 1127 | + | |
| 1128 | +/** | |
| 1129 | + * rsi_mac80211_get_antenna() - This function is used to configure | |
| 1130 | + * tx and rx antennas. | |
| 1131 | + * | |
| 1132 | + * @hw: Pointer to the ieee80211_hw structure. | |
| 1133 | + * @tx_ant: Bitmap for tx antenna | |
| 1134 | + * @rx_ant: Bitmap for rx antenna | |
| 1135 | + * | |
| 1136 | + * Return: 0 on success, -1 on failure. | |
| 1137 | + */ | |
| 1138 | +static int rsi_mac80211_get_antenna(struct ieee80211_hw *hw, | |
| 1139 | + u32 *tx_ant, u32 *rx_ant) | |
| 1140 | +{ | |
| 1141 | + struct rsi_hw *adapter = hw->priv; | |
| 1142 | + struct rsi_common *common = adapter->priv; | |
| 1143 | + | |
| 1144 | + mutex_lock(&common->mutex); | |
| 1145 | + | |
| 1146 | + *tx_ant = (common->ant_in_use == ANTENNA_SEL_UFL) ? 1 : 0; | |
| 1147 | + *rx_ant = 0; | |
| 1148 | + | |
| 1149 | + mutex_unlock(&common->mutex); | |
| 1150 | + | |
| 1151 | + return 0; | |
| 1152 | +} | |
| 1153 | + | |
| 1154 | +static void rsi_reg_notify(struct wiphy *wiphy, | |
| 1155 | + struct regulatory_request *request) | |
| 1156 | +{ | |
| 1157 | + struct ieee80211_supported_band *sband; | |
| 1158 | + struct ieee80211_channel *ch; | |
| 1159 | + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | |
| 1160 | + struct rsi_hw * adapter = hw->priv; | |
| 1161 | + int i; | |
| 1162 | + | |
| 1163 | + sband = wiphy->bands[NL80211_BAND_5GHZ]; | |
| 1164 | + | |
| 1165 | + for (i = 0; i < sband->n_channels; i++) { | |
| 1166 | + ch = &sband->channels[i]; | |
| 1167 | + if (ch->flags & IEEE80211_CHAN_DISABLED) | |
| 1168 | + continue; | |
| 1169 | + | |
| 1170 | + if (ch->flags & IEEE80211_CHAN_RADAR) | |
| 1171 | + ch->flags |= IEEE80211_CHAN_NO_IR; | |
| 1172 | + } | |
| 1173 | + | |
| 1174 | + rsi_dbg(INFO_ZONE, | |
| 1175 | + "country = %s dfs_region = %d\n", | |
| 1176 | + request->alpha2, request->dfs_region); | |
| 1177 | + adapter->dfs_region = request->dfs_region; | |
| 1028 | 1178 | } |
| 1029 | 1179 | |
| 1030 | 1180 | static struct ieee80211_ops mac80211_ops = { |
| @@ -1043,6 +1193,8 @@ static struct ieee80211_ops mac80211_ops = { · 12 unmodified lines | ||
| 1043 | 1193 | .ampdu_action = rsi_mac80211_ampdu_action, |
| 1044 | 1194 | .sta_add = rsi_mac80211_sta_add, |
| 1045 | 1195 | .sta_remove = rsi_mac80211_sta_remove, |
| 1196 | + .set_antenna = rsi_mac80211_set_antenna, | |
| 1197 | + .get_antenna = rsi_mac80211_get_antenna, | |
| 1046 | 1198 | }; |
| 1047 | 1199 | |
| 1048 | 1200 | /** |
| @@ -1107,6 +1259,8 @@ int rsi_mac80211_attach(struct rsi_common *common) · 58 unmodified lines | ||
| 1107 | 1259 | wiphy->bands[NL80211_BAND_5GHZ] = |
| 1108 | 1260 | &adapter->sbands[NL80211_BAND_5GHZ]; |
| 1109 | 1261 | |
| 1262 | + wiphy->reg_notifier = rsi_reg_notify; | |
| 1263 | + | |
| 1110 | 1264 | status = ieee80211_register_hw(hw); |
| 1111 | 1265 | if (status) |
| 1112 | 1266 | return status; |
| @@ -913,7 +913,8 @@ int rsi_band_check(struct rsi_common *common) · 912 unmodified lines | ||
| 913 | 913 | * |
| 914 | 914 | * Return: 0 on success, corresponding error code on failure. |
| 915 | 915 | */ |
| 916 | −int rsi_set_channel(struct rsi_common *common, u16 channel) | |
| 916 | +int rsi_set_channel(struct rsi_common *common, | |
| 917 | + struct ieee80211_channel *channel) | |
| 917 | 918 | { |
| 918 | 919 | struct sk_buff *skb = NULL; |
| 919 | 920 | struct rsi_mac_frame *mgmt_frame; |
| @@ -928,24 +929,76 @@ int rsi_set_channel(struct rsi_common *common, u16 channel) · 8 unmodified lines | ||
| 928 | 929 | return -ENOMEM; |
| 929 | 930 | } |
| 930 | 931 | |
| 932 | + if (!channel) { | |
| 933 | + dev_kfree_skb(skb); | |
| 934 | + return 0; | |
| 935 | + } | |
| 931 | 936 | memset(skb->data, 0, FRAME_DESC_SZ); |
| 932 | 937 | mgmt_frame = (struct rsi_mac_frame *)skb->data; |
| 933 | 938 | |
| 934 | 939 | mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); |
| 935 | 940 | mgmt_frame->desc_word[1] = cpu_to_le16(SCAN_REQUEST); |
| 936 | − mgmt_frame->desc_word[4] = cpu_to_le16(channel); | |
| 941 | + mgmt_frame->desc_word[4] = cpu_to_le16(channel->hw_value); | |
| 942 | + | |
| 943 | + mgmt_frame->desc_word[4] |= | |
| 944 | + cpu_to_le16(((char)(channel->max_antenna_gain)) << 8); | |
| 945 | + mgmt_frame->desc_word[5] = | |
| 946 | + cpu_to_le16((char)(channel->max_antenna_gain)); | |
| 937 | 947 | |
| 938 | 948 | mgmt_frame->desc_word[7] = cpu_to_le16(PUT_BBP_RESET | |
| 939 | 949 | BBP_REG_WRITE | |
| 940 | 950 | (RSI_RF_TYPE << 4)); |
| 941 | 951 | |
| 942 | − mgmt_frame->desc_word[5] = cpu_to_le16(0x01); | |
| 943 | − mgmt_frame->desc_word[6] = cpu_to_le16(0x12); | |
| 952 | + if (!(channel->flags & IEEE80211_CHAN_NO_IR) && | |
| 953 | + !(channel->flags & IEEE80211_CHAN_RADAR)) { | |
| 954 | + if (common->tx_power < channel->max_power) | |
| 955 | + mgmt_frame->desc_word[6] = cpu_to_le16(common->tx_power); | |
| 956 | + else | |
| 957 | + mgmt_frame->desc_word[6] = cpu_to_le16(channel->max_power); | |
| 958 | + } | |
| 959 | + mgmt_frame->desc_word[7] = cpu_to_le16(common->priv->dfs_region); | |
| 944 | 960 | |
| 945 | 961 | if (common->channel_width == BW_40MHZ) |
| 946 | 962 | mgmt_frame->desc_word[5] |= cpu_to_le16(0x1 << 8); |
| 947 | 963 | |
| 948 | − common->channel = channel; | |
| 964 | + common->channel = channel->hw_value; | |
| 965 | + | |
| 966 | + skb_put(skb, FRAME_DESC_SZ); | |
| 967 | + | |
| 968 | + return rsi_send_internal_mgmt_frame(common, skb); | |
| 969 | +} | |
| 970 | + | |
| 971 | +/** | |
| 972 | + * rsi_send_radio_params_update() - This function sends the radio | |
| 973 | + * parameters update to device | |
| 974 | + * @common: Pointer to the driver private structure. | |
| 975 | + * @channel: Channel value to be set. | |
| 976 | + * | |
| 977 | + * Return: 0 on success, corresponding error code on failure. | |
| 978 | + */ | |
| 979 | +int rsi_send_radio_params_update(struct rsi_common *common) | |
| 980 | +{ | |
| 981 | + struct rsi_mac_frame *cmd_frame; | |
| 982 | + struct sk_buff *skb = NULL; | |
| 983 | + | |
| 984 | + rsi_dbg(MGMT_TX_ZONE, | |
| 985 | + "%s: Sending Radio Params update frame\n", __func__); | |
| 986 | + | |
| 987 | + skb = dev_alloc_skb(FRAME_DESC_SZ); | |
| 988 | + if (!skb) { | |
| 989 | + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", | |
| 990 | + __func__); | |
| 991 | + return -ENOMEM; | |
| 992 | + } | |
| 993 | + | |
| 994 | + memset(skb->data, 0, FRAME_DESC_SZ); | |
| 995 | + cmd_frame = (struct rsi_mac_frame *)skb->data; | |
| 996 | + | |
| 997 | + cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); | |
| 998 | + cmd_frame->desc_word[1] = cpu_to_le16(RADIO_PARAMS_UPDATE); | |
| 999 | + cmd_frame->desc_word[3] = cpu_to_le16(BIT(0)); | |
| 1000 | + | |
| 1001 | + cmd_frame->desc_word[3] |= cpu_to_le16(common->tx_power << 8); | |
| 949 | 1002 | |
| 950 | 1003 | skb_put(skb, FRAME_DESC_SZ); |
| 951 | 1004 | |
| @@ -1243,6 +1296,72 @@ int rsi_send_block_unblock_frame(struct rsi_common *common, bool block_event) · 291 unmodified lines | ||
| 1243 | 1296 | |
| 1244 | 1297 | } |
| 1245 | 1298 | |
| 1299 | +/** | |
| 1300 | + * rsi_send_rx_filter_frame() - Sends a frame to filter the RX packets | |
| 1301 | + * | |
| 1302 | + * @common: Pointer to the driver private structure. | |
| 1303 | + * @rx_filter_word: Flags of filter packets | |
| 1304 | + * | |
| 1305 | + * @Return: 0 on success, -1 on failure. | |
| 1306 | + */ | |
| 1307 | +int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word) | |
| 1308 | +{ | |
| 1309 | + struct rsi_mac_frame *cmd_frame; | |
| 1310 | + struct sk_buff *skb; | |
| 1311 | + | |
| 1312 | + rsi_dbg(MGMT_TX_ZONE, "Sending RX filter frame\n"); | |
| 1313 | + | |
| 1314 | + skb = dev_alloc_skb(FRAME_DESC_SZ); | |
| 1315 | + if (!skb) { | |
| 1316 | + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", | |
| 1317 | + __func__); | |
| 1318 | + return -ENOMEM; | |
| 1319 | + } | |
| 1320 | + | |
| 1321 | + memset(skb->data, 0, FRAME_DESC_SZ); | |
| 1322 | + cmd_frame = (struct rsi_mac_frame *)skb->data; | |
| 1323 | + | |
| 1324 | + cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); | |
| 1325 | + cmd_frame->desc_word[1] = cpu_to_le16(SET_RX_FILTER); | |
| 1326 | + cmd_frame->desc_word[4] = cpu_to_le16(rx_filter_word); | |
| 1327 | + | |
| 1328 | + skb_put(skb, FRAME_DESC_SZ); | |
| 1329 | + | |
| 1330 | + return rsi_send_internal_mgmt_frame(common, skb); | |
| 1331 | +} | |
| 1332 | + | |
| 1333 | +/** | |
| 1334 | + * rsi_set_antenna() - This fuction send antenna configuration request | |
| 1335 | + * to device | |
| 1336 | + * | |
| 1337 | + * @common: Pointer to the driver private structure. | |
| 1338 | + * @antenna: bitmap for tx antenna selection | |
| 1339 | + * | |
| 1340 | + * Return: 0 on Success, negative error code on failure | |
| 1341 | + */ | |
| 1342 | +int rsi_set_antenna(struct rsi_common *common, u8 antenna) | |
| 1343 | +{ | |
| 1344 | + struct rsi_mac_frame *cmd_frame; | |
| 1345 | + struct sk_buff *skb; | |
| 1346 | + | |
| 1347 | + skb = dev_alloc_skb(FRAME_DESC_SZ); | |
| 1348 | + if (!skb) { | |
| 1349 | + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", | |
| 1350 | + __func__); | |
| 1351 | + return -ENOMEM; | |
| 1352 | + } | |
| 1353 | + | |
| 1354 | + memset(skb->data, 0, FRAME_DESC_SZ); | |
| 1355 | + cmd_frame = (struct rsi_mac_frame *)skb->data; | |
| 1356 | + | |
| 1357 | + cmd_frame->desc_word[1] = cpu_to_le16(ANT_SEL_FRAME); | |
| 1358 | + cmd_frame->desc_word[3] = cpu_to_le16(antenna & 0x00ff); | |
| 1359 | + cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); | |
| 1360 | + | |
| 1361 | + skb_put(skb, FRAME_DESC_SZ); | |
| 1362 | + | |
| 1363 | + return rsi_send_internal_mgmt_frame(common, skb); | |
| 1364 | +} | |
| 1246 | 1365 | |
| 1247 | 1366 | /** |
| 1248 | 1367 | * rsi_handle_ta_confirm_type() - This function handles the confirm frames. |
| @@ -204,6 +204,9 @@ struct rsi_common { · 203 unmodified lines | ||
| 204 | 204 | struct cqm_info cqm_info; |
| 205 | 205 | |
| 206 | 206 | bool hw_data_qs_blocked; |
| 207 | + | |
| 208 | + int tx_power; | |
| 209 | + u8 ant_in_use; | |
| 207 | 210 | }; |
| 208 | 211 | |
| 209 | 212 | struct rsi_hw { |
| @@ -220,6 +223,7 @@ struct rsi_hw { · 10 unmodified lines | ||
| 220 | 223 | struct rsi_debugfs *dfsentry; |
| 221 | 224 | u8 num_debugfs_entries; |
| 222 | 225 | #endif |
| 226 | + u8 dfs_region; | |
| 223 | 227 | void *rsi_dev; |
| 224 | 228 | int (*host_intf_read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); |
| 225 | 229 | int (*host_intf_write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); |
| @@ -140,6 +140,19 @@ · 139 unmodified lines | ||
| 140 | 140 | |
| 141 | 141 | #define RSI_SUPP_FILTERS (FIF_ALLMULTI | FIF_PROBE_REQ |\ |
| 142 | 142 | FIF_BCN_PRBRESP_PROMISC) |
| 143 | + | |
| 144 | +#define ANTENNA_SEL_INT 0x02 /* RF_OUT_2 / Integerated */ | |
| 145 | +#define ANTENNA_SEL_UFL 0x03 /* RF_OUT_1 / U.FL */ | |
| 146 | + | |
| 147 | +/* Rx filter word definitions */ | |
| 148 | +#define PROMISCOUS_MODE BIT(0) | |
| 149 | +#define ALLOW_DATA_ASSOC_PEER BIT(1) | |
| 150 | +#define ALLOW_MGMT_ASSOC_PEER BIT(2) | |
| 151 | +#define ALLOW_CTRL_ASSOC_PEER BIT(3) | |
| 152 | +#define DISALLOW_BEACONS BIT(4) | |
| 153 | +#define ALLOW_CONN_PEER_MGMT_WHILE_BUF_FULL BIT(5) | |
| 154 | +#define DISALLOW_BROADCAST_DATA BIT(6) | |
| 155 | + | |
| 143 | 156 | enum opmode { |
| 144 | 157 | STA_OPMODE = 1, |
| 145 | 158 | AP_OPMODE = 2 |
| @@ -190,7 +203,9 @@ enum cmd_frame_type { · 44 unmodified lines | ||
| 190 | 203 | BG_SCAN_PARAMS, |
| 191 | 204 | BG_SCAN_PROBE_REQ, |
| 192 | 205 | CW_MODE_REQ, |
| 193 | − PER_CMD_PKT | |
| 206 | + PER_CMD_PKT, | |
| 207 | + ANT_SEL_FRAME = 0x20, | |
| 208 | + RADIO_PARAMS_UPDATE = 0x29 | |
| 194 | 209 | }; |
| 195 | 210 | |
| 196 | 211 | struct rsi_mac_frame { |
| @@ -299,7 +314,8 @@ int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid, · 102 unmodified lines | ||
| 299 | 314 | u16 ssn, u8 buf_size, u8 event); |
| 300 | 315 | int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len, |
| 301 | 316 | u8 key_type, u8 key_id, u32 cipher); |
| 302 | −int rsi_set_channel(struct rsi_common *common, u16 chno); | |
| 317 | +int rsi_set_channel(struct rsi_common *common, | |
| 318 | + struct ieee80211_channel *channel); | |
| 303 | 319 | int rsi_send_block_unblock_frame(struct rsi_common *common, bool event); |
| 304 | 320 | void rsi_inform_bss_status(struct rsi_common *common, u8 status, |
| 305 | 321 | const u8 *bssid, u8 qos_enable, u16 aid); |
| @@ -313,4 +329,7 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb); · 7 unmodified lines | ||
| 313 | 329 | int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb); |
| 314 | 330 | int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb); |
| 315 | 331 | int rsi_band_check(struct rsi_common *common); |
| 332 | +int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word); | |
| 333 | +int rsi_send_radio_params_update(struct rsi_common *common); | |
| 334 | +int rsi_set_antenna(struct rsi_common *common, u8 antenna); | |
| 316 | 335 | #endif |