18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of wl12xx 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Texas Instruments. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <net/genetlink.h> 98c2ecf20Sopenharmony_ci#include "event.h" 108c2ecf20Sopenharmony_ci#include "scan.h" 118c2ecf20Sopenharmony_ci#include "conf.h" 128c2ecf20Sopenharmony_ci#include "../wlcore/cmd.h" 138c2ecf20Sopenharmony_ci#include "../wlcore/debug.h" 148c2ecf20Sopenharmony_ci#include "../wlcore/vendor_cmd.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciint wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, 178c2ecf20Sopenharmony_ci bool *timeout) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci u32 local_event; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci switch (event) { 228c2ecf20Sopenharmony_ci case WLCORE_EVENT_PEER_REMOVE_COMPLETE: 238c2ecf20Sopenharmony_ci local_event = PEER_REMOVE_COMPLETE_EVENT_ID; 248c2ecf20Sopenharmony_ci break; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci case WLCORE_EVENT_DFS_CONFIG_COMPLETE: 278c2ecf20Sopenharmony_ci local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT; 288c2ecf20Sopenharmony_ci break; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci default: 318c2ecf20Sopenharmony_ci /* event not implemented */ 328c2ecf20Sopenharmony_ci return 0; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const char *wl18xx_radar_type_decode(u8 radar_type) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci switch (radar_type) { 408c2ecf20Sopenharmony_ci case RADAR_TYPE_REGULAR: 418c2ecf20Sopenharmony_ci return "REGULAR"; 428c2ecf20Sopenharmony_ci case RADAR_TYPE_CHIRP: 438c2ecf20Sopenharmony_ci return "CHIRP"; 448c2ecf20Sopenharmony_ci case RADAR_TYPE_NONE: 458c2ecf20Sopenharmony_ci default: 468c2ecf20Sopenharmony_ci return "N/A"; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel, 518c2ecf20Sopenharmony_ci u8 sync_band) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct sk_buff *skb; 548c2ecf20Sopenharmony_ci enum nl80211_band band; 558c2ecf20Sopenharmony_ci int freq; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (sync_band == WLCORE_BAND_5GHZ) 588c2ecf20Sopenharmony_ci band = NL80211_BAND_5GHZ; 598c2ecf20Sopenharmony_ci else 608c2ecf20Sopenharmony_ci band = NL80211_BAND_2GHZ; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci freq = ieee80211_channel_to_frequency(sync_channel, band); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_EVENT, 658c2ecf20Sopenharmony_ci "SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)", 668c2ecf20Sopenharmony_ci freq, sync_channel, sync_band); 678c2ecf20Sopenharmony_ci skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL, 20, 688c2ecf20Sopenharmony_ci WLCORE_VENDOR_EVENT_SC_SYNC, 698c2ecf20Sopenharmony_ci GFP_KERNEL); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (nla_put_u32(skb, WLCORE_VENDOR_ATTR_FREQ, freq)) { 728c2ecf20Sopenharmony_ci kfree_skb(skb); 738c2ecf20Sopenharmony_ci return -EMSGSIZE; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci cfg80211_vendor_event(skb, GFP_KERNEL); 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int wlcore_smart_config_decode_event(struct wl1271 *wl, 808c2ecf20Sopenharmony_ci u8 ssid_len, u8 *ssid, 818c2ecf20Sopenharmony_ci u8 pwd_len, u8 *pwd) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct sk_buff *skb; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_DECODE_EVENT_ID"); 868c2ecf20Sopenharmony_ci wl1271_dump_ascii(DEBUG_EVENT, "SSID:", ssid, ssid_len); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL, 898c2ecf20Sopenharmony_ci ssid_len + pwd_len + 20, 908c2ecf20Sopenharmony_ci WLCORE_VENDOR_EVENT_SC_DECODE, 918c2ecf20Sopenharmony_ci GFP_KERNEL); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (nla_put(skb, WLCORE_VENDOR_ATTR_SSID, ssid_len, ssid) || 948c2ecf20Sopenharmony_ci nla_put(skb, WLCORE_VENDOR_ATTR_PSK, pwd_len, pwd)) { 958c2ecf20Sopenharmony_ci kfree_skb(skb); 968c2ecf20Sopenharmony_ci return -EMSGSIZE; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci cfg80211_vendor_event(skb, GFP_KERNEL); 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic void wlcore_event_time_sync(struct wl1271 *wl, 1038c2ecf20Sopenharmony_ci u16 tsf_high_msb, u16 tsf_high_lsb, 1048c2ecf20Sopenharmony_ci u16 tsf_low_msb, u16 tsf_low_lsb) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci u32 clock_low; 1078c2ecf20Sopenharmony_ci u32 clock_high; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci clock_high = (tsf_high_msb << 16) | tsf_high_lsb; 1108c2ecf20Sopenharmony_ci clock_low = (tsf_low_msb << 16) | tsf_low_lsb; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci wl1271_info("TIME_SYNC_EVENT_ID: clock_high %u, clock low %u", 1138c2ecf20Sopenharmony_ci clock_high, clock_low); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciint wl18xx_process_mailbox_events(struct wl1271 *wl) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct wl18xx_event_mailbox *mbox = wl->mbox; 1198c2ecf20Sopenharmony_ci u32 vector; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci vector = le32_to_cpu(mbox->events_vector); 1228c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (vector & SCAN_COMPLETE_EVENT_ID) { 1258c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_EVENT, "scan results: %d", 1268c2ecf20Sopenharmony_ci mbox->number_of_scan_results); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (wl->scan_wlvif) 1298c2ecf20Sopenharmony_ci wl18xx_scan_completed(wl, wl->scan_wlvif); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (vector & TIME_SYNC_EVENT_ID) 1338c2ecf20Sopenharmony_ci wlcore_event_time_sync(wl, 1348c2ecf20Sopenharmony_ci mbox->time_sync_tsf_high_msb, 1358c2ecf20Sopenharmony_ci mbox->time_sync_tsf_high_lsb, 1368c2ecf20Sopenharmony_ci mbox->time_sync_tsf_low_msb, 1378c2ecf20Sopenharmony_ci mbox->time_sync_tsf_low_lsb); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (vector & RADAR_DETECTED_EVENT_ID) { 1408c2ecf20Sopenharmony_ci wl1271_info("radar event: channel %d type %s", 1418c2ecf20Sopenharmony_ci mbox->radar_channel, 1428c2ecf20Sopenharmony_ci wl18xx_radar_type_decode(mbox->radar_type)); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (!wl->radar_debug_mode) 1458c2ecf20Sopenharmony_ci ieee80211_radar_detected(wl->hw); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { 1498c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_EVENT, 1508c2ecf20Sopenharmony_ci "PERIODIC_SCAN_REPORT_EVENT (results %d)", 1518c2ecf20Sopenharmony_ci mbox->number_of_sched_scan_results); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci wlcore_scan_sched_scan_results(wl); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) 1578c2ecf20Sopenharmony_ci wlcore_event_sched_scan_completed(wl, 1); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) 1608c2ecf20Sopenharmony_ci wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) 1638c2ecf20Sopenharmony_ci wlcore_event_ba_rx_constraint(wl, 1648c2ecf20Sopenharmony_ci le16_to_cpu(mbox->rx_ba_role_id_bitmap), 1658c2ecf20Sopenharmony_ci le16_to_cpu(mbox->rx_ba_allowed_bitmap)); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (vector & BSS_LOSS_EVENT_ID) 1688c2ecf20Sopenharmony_ci wlcore_event_beacon_loss(wl, 1698c2ecf20Sopenharmony_ci le16_to_cpu(mbox->bss_loss_bitmap)); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) 1728c2ecf20Sopenharmony_ci wlcore_event_channel_switch(wl, 1738c2ecf20Sopenharmony_ci le16_to_cpu(mbox->channel_switch_role_id_bitmap), 1748c2ecf20Sopenharmony_ci true); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (vector & DUMMY_PACKET_EVENT_ID) 1778c2ecf20Sopenharmony_ci wlcore_event_dummy_packet(wl); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * "TX retries exceeded" has a different meaning according to mode. 1818c2ecf20Sopenharmony_ci * In AP mode the offending station is disconnected. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci if (vector & MAX_TX_FAILURE_EVENT_ID) 1848c2ecf20Sopenharmony_ci wlcore_event_max_tx_failure(wl, 1858c2ecf20Sopenharmony_ci le16_to_cpu(mbox->tx_retry_exceeded_bitmap)); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (vector & INACTIVE_STA_EVENT_ID) 1888c2ecf20Sopenharmony_ci wlcore_event_inactive_sta(wl, 1898c2ecf20Sopenharmony_ci le16_to_cpu(mbox->inactive_sta_bitmap)); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) 1928c2ecf20Sopenharmony_ci wlcore_event_roc_complete(wl); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (vector & SMART_CONFIG_SYNC_EVENT_ID) 1958c2ecf20Sopenharmony_ci wlcore_smart_config_sync_event(wl, mbox->sc_sync_channel, 1968c2ecf20Sopenharmony_ci mbox->sc_sync_band); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (vector & SMART_CONFIG_DECODE_EVENT_ID) 1998c2ecf20Sopenharmony_ci wlcore_smart_config_decode_event(wl, 2008c2ecf20Sopenharmony_ci mbox->sc_ssid_len, 2018c2ecf20Sopenharmony_ci mbox->sc_ssid, 2028c2ecf20Sopenharmony_ci mbox->sc_pwd_len, 2038c2ecf20Sopenharmony_ci mbox->sc_pwd); 2048c2ecf20Sopenharmony_ci if (vector & FW_LOGGER_INDICATION) 2058c2ecf20Sopenharmony_ci wlcore_event_fw_logger(wl); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (vector & RX_BA_WIN_SIZE_CHANGE_EVENT_ID) { 2088c2ecf20Sopenharmony_ci struct wl12xx_vif *wlvif; 2098c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 2108c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 2118c2ecf20Sopenharmony_ci u8 link_id = mbox->rx_ba_link_id; 2128c2ecf20Sopenharmony_ci u8 win_size = mbox->rx_ba_win_size; 2138c2ecf20Sopenharmony_ci const u8 *addr; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci wlvif = wl->links[link_id].wlvif; 2168c2ecf20Sopenharmony_ci vif = wl12xx_wlvif_to_vif(wlvif); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Update RX aggregation window size and call 2198c2ecf20Sopenharmony_ci * MAC routine to stop active RX aggregations for this link 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci if (wlvif->bss_type != BSS_TYPE_AP_BSS) 2228c2ecf20Sopenharmony_ci addr = vif->bss_conf.bssid; 2238c2ecf20Sopenharmony_ci else 2248c2ecf20Sopenharmony_ci addr = wl->links[link_id].addr; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci sta = ieee80211_find_sta(vif, addr); 2278c2ecf20Sopenharmony_ci if (sta) { 2288c2ecf20Sopenharmony_ci sta->max_rx_aggregation_subframes = win_size; 2298c2ecf20Sopenharmony_ci ieee80211_stop_rx_ba_session(vif, 2308c2ecf20Sopenharmony_ci wl->links[link_id].ba_bitmap, 2318c2ecf20Sopenharmony_ci addr); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 237