18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of wl18xx 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "../wlcore/cmd.h" 98c2ecf20Sopenharmony_ci#include "../wlcore/debug.h" 108c2ecf20Sopenharmony_ci#include "../wlcore/hw_ops.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "cmd.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciint wl18xx_cmd_channel_switch(struct wl1271 *wl, 158c2ecf20Sopenharmony_ci struct wl12xx_vif *wlvif, 168c2ecf20Sopenharmony_ci struct ieee80211_channel_switch *ch_switch) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct wl18xx_cmd_channel_switch *cmd; 198c2ecf20Sopenharmony_ci u32 supported_rates; 208c2ecf20Sopenharmony_ci int ret; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_ACX, "cmd channel switch (count=%d)", 238c2ecf20Sopenharmony_ci ch_switch->count); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 268c2ecf20Sopenharmony_ci if (!cmd) { 278c2ecf20Sopenharmony_ci ret = -ENOMEM; 288c2ecf20Sopenharmony_ci goto out; 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci cmd->role_id = wlvif->role_id; 328c2ecf20Sopenharmony_ci cmd->channel = ch_switch->chandef.chan->hw_value; 338c2ecf20Sopenharmony_ci cmd->switch_time = ch_switch->count; 348c2ecf20Sopenharmony_ci cmd->stop_tx = ch_switch->block_tx; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci switch (ch_switch->chandef.chan->band) { 378c2ecf20Sopenharmony_ci case NL80211_BAND_2GHZ: 388c2ecf20Sopenharmony_ci cmd->band = WLCORE_BAND_2_4GHZ; 398c2ecf20Sopenharmony_ci break; 408c2ecf20Sopenharmony_ci case NL80211_BAND_5GHZ: 418c2ecf20Sopenharmony_ci cmd->band = WLCORE_BAND_5GHZ; 428c2ecf20Sopenharmony_ci break; 438c2ecf20Sopenharmony_ci default: 448c2ecf20Sopenharmony_ci wl1271_error("invalid channel switch band: %d", 458c2ecf20Sopenharmony_ci ch_switch->chandef.chan->band); 468c2ecf20Sopenharmony_ci ret = -EINVAL; 478c2ecf20Sopenharmony_ci goto out_free; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES; 518c2ecf20Sopenharmony_ci if (wlvif->bss_type == BSS_TYPE_STA_BSS) 528c2ecf20Sopenharmony_ci supported_rates |= wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); 538c2ecf20Sopenharmony_ci else 548c2ecf20Sopenharmony_ci supported_rates |= 558c2ecf20Sopenharmony_ci wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif); 568c2ecf20Sopenharmony_ci if (wlvif->p2p) 578c2ecf20Sopenharmony_ci supported_rates &= ~CONF_TX_CCK_RATES; 588c2ecf20Sopenharmony_ci cmd->local_supported_rates = cpu_to_le32(supported_rates); 598c2ecf20Sopenharmony_ci cmd->channel_type = wlvif->channel_type; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); 628c2ecf20Sopenharmony_ci if (ret < 0) { 638c2ecf20Sopenharmony_ci wl1271_error("failed to send channel switch command"); 648c2ecf20Sopenharmony_ci goto out_free; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciout_free: 688c2ecf20Sopenharmony_ci kfree(cmd); 698c2ecf20Sopenharmony_ciout: 708c2ecf20Sopenharmony_ci return ret; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciint wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct wl18xx_cmd_smart_config_start *cmd; 768c2ecf20Sopenharmony_ci int ret = 0; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_CMD, "cmd smart config start group_bitmap=0x%x", 798c2ecf20Sopenharmony_ci group_bitmap); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 828c2ecf20Sopenharmony_ci if (!cmd) { 838c2ecf20Sopenharmony_ci ret = -ENOMEM; 848c2ecf20Sopenharmony_ci goto out; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci cmd->group_id_bitmask = cpu_to_le32(group_bitmap); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_START, cmd, sizeof(*cmd), 0); 908c2ecf20Sopenharmony_ci if (ret < 0) { 918c2ecf20Sopenharmony_ci wl1271_error("failed to send smart config start command"); 928c2ecf20Sopenharmony_ci goto out_free; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciout_free: 968c2ecf20Sopenharmony_ci kfree(cmd); 978c2ecf20Sopenharmony_ciout: 988c2ecf20Sopenharmony_ci return ret; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciint wl18xx_cmd_smart_config_stop(struct wl1271 *wl) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct wl1271_cmd_header *cmd; 1048c2ecf20Sopenharmony_ci int ret = 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_CMD, "cmd smart config stop"); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1098c2ecf20Sopenharmony_ci if (!cmd) { 1108c2ecf20Sopenharmony_ci ret = -ENOMEM; 1118c2ecf20Sopenharmony_ci goto out; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_STOP, cmd, sizeof(*cmd), 0); 1158c2ecf20Sopenharmony_ci if (ret < 0) { 1168c2ecf20Sopenharmony_ci wl1271_error("failed to send smart config stop command"); 1178c2ecf20Sopenharmony_ci goto out_free; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciout_free: 1218c2ecf20Sopenharmony_ci kfree(cmd); 1228c2ecf20Sopenharmony_ciout: 1238c2ecf20Sopenharmony_ci return ret; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciint wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, 1278c2ecf20Sopenharmony_ci u8 key_len, u8 *key) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct wl18xx_cmd_smart_config_set_group_key *cmd; 1308c2ecf20Sopenharmony_ci int ret = 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_CMD, "cmd smart config set group key id=0x%x", 1338c2ecf20Sopenharmony_ci group_id); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (key_len != sizeof(cmd->key)) { 1368c2ecf20Sopenharmony_ci wl1271_error("invalid group key size: %d", key_len); 1378c2ecf20Sopenharmony_ci return -E2BIG; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1418c2ecf20Sopenharmony_ci if (!cmd) { 1428c2ecf20Sopenharmony_ci ret = -ENOMEM; 1438c2ecf20Sopenharmony_ci goto out; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci cmd->group_id = cpu_to_le32(group_id); 1478c2ecf20Sopenharmony_ci memcpy(cmd->key, key, key_len); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_SET_GROUP_KEY, cmd, 1508c2ecf20Sopenharmony_ci sizeof(*cmd), 0); 1518c2ecf20Sopenharmony_ci if (ret < 0) { 1528c2ecf20Sopenharmony_ci wl1271_error("failed to send smart config set group key cmd"); 1538c2ecf20Sopenharmony_ci goto out_free; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ciout_free: 1578c2ecf20Sopenharmony_ci kfree(cmd); 1588c2ecf20Sopenharmony_ciout: 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciint wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct wlcore_cmd_cac_start *cmd; 1658c2ecf20Sopenharmony_ci int ret = 0; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_CMD, "cmd cac (channel %d) %s", 1688c2ecf20Sopenharmony_ci wlvif->channel, start ? "start" : "stop"); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1718c2ecf20Sopenharmony_ci if (!cmd) 1728c2ecf20Sopenharmony_ci return -ENOMEM; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci cmd->role_id = wlvif->role_id; 1758c2ecf20Sopenharmony_ci cmd->channel = wlvif->channel; 1768c2ecf20Sopenharmony_ci if (wlvif->band == NL80211_BAND_5GHZ) 1778c2ecf20Sopenharmony_ci cmd->band = WLCORE_BAND_5GHZ; 1788c2ecf20Sopenharmony_ci cmd->bandwidth = wlcore_get_native_channel_type(wlvif->channel_type); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ret = wl1271_cmd_send(wl, 1818c2ecf20Sopenharmony_ci start ? CMD_CAC_START : CMD_CAC_STOP, 1828c2ecf20Sopenharmony_ci cmd, sizeof(*cmd), 0); 1838c2ecf20Sopenharmony_ci if (ret < 0) { 1848c2ecf20Sopenharmony_ci wl1271_error("failed to send cac command"); 1858c2ecf20Sopenharmony_ci goto out_free; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciout_free: 1898c2ecf20Sopenharmony_ci kfree(cmd); 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciint wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct wl18xx_cmd_dfs_radar_debug *cmd; 1968c2ecf20Sopenharmony_ci int ret = 0; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_CMD, "cmd radar detection debug (chan %d)", 1998c2ecf20Sopenharmony_ci channel); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2028c2ecf20Sopenharmony_ci if (!cmd) 2038c2ecf20Sopenharmony_ci return -ENOMEM; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci cmd->channel = channel; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = wl1271_cmd_send(wl, CMD_DFS_RADAR_DETECTION_DEBUG, 2088c2ecf20Sopenharmony_ci cmd, sizeof(*cmd), 0); 2098c2ecf20Sopenharmony_ci if (ret < 0) { 2108c2ecf20Sopenharmony_ci wl1271_error("failed to send radar detection debug command"); 2118c2ecf20Sopenharmony_ci goto out_free; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciout_free: 2158c2ecf20Sopenharmony_ci kfree(cmd); 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciint wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct wl18xx_cmd_dfs_master_restart *cmd; 2228c2ecf20Sopenharmony_ci int ret = 0; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_CMD, "cmd dfs master restart (role %d)", 2258c2ecf20Sopenharmony_ci wlvif->role_id); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2288c2ecf20Sopenharmony_ci if (!cmd) 2298c2ecf20Sopenharmony_ci return -ENOMEM; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci cmd->role_id = wlvif->role_id; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ret = wl1271_cmd_send(wl, CMD_DFS_MASTER_RESTART, 2348c2ecf20Sopenharmony_ci cmd, sizeof(*cmd), 0); 2358c2ecf20Sopenharmony_ci if (ret < 0) { 2368c2ecf20Sopenharmony_ci wl1271_error("failed to send dfs master restart command"); 2378c2ecf20Sopenharmony_ci goto out_free; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ciout_free: 2408c2ecf20Sopenharmony_ci kfree(cmd); 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci} 243