17b3115f2SLuciano Coelho /* 27b3115f2SLuciano Coelho * This file is part of wl1271 37b3115f2SLuciano Coelho * 47b3115f2SLuciano Coelho * Copyright (C) 2008-2009 Nokia Corporation 57b3115f2SLuciano Coelho * 67b3115f2SLuciano Coelho * Contact: Luciano Coelho <luciano.coelho@nokia.com> 77b3115f2SLuciano Coelho * 87b3115f2SLuciano Coelho * This program is free software; you can redistribute it and/or 97b3115f2SLuciano Coelho * modify it under the terms of the GNU General Public License 107b3115f2SLuciano Coelho * version 2 as published by the Free Software Foundation. 117b3115f2SLuciano Coelho * 127b3115f2SLuciano Coelho * This program is distributed in the hope that it will be useful, but 137b3115f2SLuciano Coelho * WITHOUT ANY WARRANTY; without even the implied warranty of 147b3115f2SLuciano Coelho * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 157b3115f2SLuciano Coelho * General Public License for more details. 167b3115f2SLuciano Coelho * 177b3115f2SLuciano Coelho * You should have received a copy of the GNU General Public License 187b3115f2SLuciano Coelho * along with this program; if not, write to the Free Software 197b3115f2SLuciano Coelho * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 207b3115f2SLuciano Coelho * 02110-1301 USA 217b3115f2SLuciano Coelho * 227b3115f2SLuciano Coelho */ 237b3115f2SLuciano Coelho 247b3115f2SLuciano Coelho #include "acx.h" 257b3115f2SLuciano Coelho 267b3115f2SLuciano Coelho #include <linux/module.h> 277b3115f2SLuciano Coelho #include <linux/platform_device.h> 287b3115f2SLuciano Coelho #include <linux/spi/spi.h> 297b3115f2SLuciano Coelho #include <linux/slab.h> 307b3115f2SLuciano Coelho 31c31be25aSLuciano Coelho #include "wlcore.h" 327b3115f2SLuciano Coelho #include "debug.h" 337b3115f2SLuciano Coelho #include "wl12xx_80211.h" 347b3115f2SLuciano Coelho #include "ps.h" 35fa7930afSArik Nemtsov #include "hw_ops.h" 367b3115f2SLuciano Coelho 377b3115f2SLuciano Coelho int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif, 387b3115f2SLuciano Coelho u8 wake_up_event, u8 listen_interval) 397b3115f2SLuciano Coelho { 407b3115f2SLuciano Coelho struct acx_wake_up_condition *wake_up; 417b3115f2SLuciano Coelho int ret; 427b3115f2SLuciano Coelho 437b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)", 447b3115f2SLuciano Coelho wake_up_event, listen_interval); 457b3115f2SLuciano Coelho 467b3115f2SLuciano Coelho wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); 477b3115f2SLuciano Coelho if (!wake_up) { 487b3115f2SLuciano Coelho ret = -ENOMEM; 497b3115f2SLuciano Coelho goto out; 507b3115f2SLuciano Coelho } 517b3115f2SLuciano Coelho 527b3115f2SLuciano Coelho wake_up->role_id = wlvif->role_id; 537b3115f2SLuciano Coelho wake_up->wake_up_event = wake_up_event; 547b3115f2SLuciano Coelho wake_up->listen_interval = listen_interval; 557b3115f2SLuciano Coelho 567b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, 577b3115f2SLuciano Coelho wake_up, sizeof(*wake_up)); 587b3115f2SLuciano Coelho if (ret < 0) { 597b3115f2SLuciano Coelho wl1271_warning("could not set wake up conditions: %d", ret); 607b3115f2SLuciano Coelho goto out; 617b3115f2SLuciano Coelho } 627b3115f2SLuciano Coelho 637b3115f2SLuciano Coelho out: 647b3115f2SLuciano Coelho kfree(wake_up); 657b3115f2SLuciano Coelho return ret; 667b3115f2SLuciano Coelho } 677b3115f2SLuciano Coelho 687b3115f2SLuciano Coelho int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) 697b3115f2SLuciano Coelho { 707b3115f2SLuciano Coelho struct acx_sleep_auth *auth; 717b3115f2SLuciano Coelho int ret; 727b3115f2SLuciano Coelho 7366340e5bSArik Nemtsov wl1271_debug(DEBUG_ACX, "acx sleep auth %d", sleep_auth); 747b3115f2SLuciano Coelho 757b3115f2SLuciano Coelho auth = kzalloc(sizeof(*auth), GFP_KERNEL); 767b3115f2SLuciano Coelho if (!auth) { 777b3115f2SLuciano Coelho ret = -ENOMEM; 787b3115f2SLuciano Coelho goto out; 797b3115f2SLuciano Coelho } 807b3115f2SLuciano Coelho 817b3115f2SLuciano Coelho auth->sleep_auth = sleep_auth; 827b3115f2SLuciano Coelho 837b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); 842f18cf7cSArik Nemtsov if (ret < 0) { 852f18cf7cSArik Nemtsov wl1271_error("could not configure sleep_auth to %d: %d", 862f18cf7cSArik Nemtsov sleep_auth, ret); 8726b5858aSLuciano Coelho goto out; 882f18cf7cSArik Nemtsov } 897b3115f2SLuciano Coelho 9026b5858aSLuciano Coelho wl->sleep_auth = sleep_auth; 917b3115f2SLuciano Coelho out: 927b3115f2SLuciano Coelho kfree(auth); 937b3115f2SLuciano Coelho return ret; 947b3115f2SLuciano Coelho } 95c331b344SLuciano Coelho EXPORT_SYMBOL_GPL(wl1271_acx_sleep_auth); 967b3115f2SLuciano Coelho 977b3115f2SLuciano Coelho int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, 987b3115f2SLuciano Coelho int power) 997b3115f2SLuciano Coelho { 1007b3115f2SLuciano Coelho struct acx_current_tx_power *acx; 1017b3115f2SLuciano Coelho int ret; 1027b3115f2SLuciano Coelho 1037b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d", power); 1047b3115f2SLuciano Coelho 1057b3115f2SLuciano Coelho if (power < 0 || power > 25) 1067b3115f2SLuciano Coelho return -EINVAL; 1077b3115f2SLuciano Coelho 1087b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 1097b3115f2SLuciano Coelho if (!acx) { 1107b3115f2SLuciano Coelho ret = -ENOMEM; 1117b3115f2SLuciano Coelho goto out; 1127b3115f2SLuciano Coelho } 1137b3115f2SLuciano Coelho 1147b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 1157b3115f2SLuciano Coelho acx->current_tx_power = power * 10; 1167b3115f2SLuciano Coelho 1177b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); 1187b3115f2SLuciano Coelho if (ret < 0) { 1197b3115f2SLuciano Coelho wl1271_warning("configure of tx power failed: %d", ret); 1207b3115f2SLuciano Coelho goto out; 1217b3115f2SLuciano Coelho } 1227b3115f2SLuciano Coelho 1237b3115f2SLuciano Coelho out: 1247b3115f2SLuciano Coelho kfree(acx); 1257b3115f2SLuciano Coelho return ret; 1267b3115f2SLuciano Coelho } 1277b3115f2SLuciano Coelho 1287b3115f2SLuciano Coelho int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif) 1297b3115f2SLuciano Coelho { 1307b3115f2SLuciano Coelho struct acx_feature_config *feature; 1317b3115f2SLuciano Coelho int ret; 1327b3115f2SLuciano Coelho 1337b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx feature cfg"); 1347b3115f2SLuciano Coelho 1357b3115f2SLuciano Coelho feature = kzalloc(sizeof(*feature), GFP_KERNEL); 1367b3115f2SLuciano Coelho if (!feature) { 1377b3115f2SLuciano Coelho ret = -ENOMEM; 1387b3115f2SLuciano Coelho goto out; 1397b3115f2SLuciano Coelho } 1407b3115f2SLuciano Coelho 1417b3115f2SLuciano Coelho /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ 1427b3115f2SLuciano Coelho feature->role_id = wlvif->role_id; 1437b3115f2SLuciano Coelho feature->data_flow_options = 0; 1447b3115f2SLuciano Coelho feature->options = 0; 1457b3115f2SLuciano Coelho 1467b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, 1477b3115f2SLuciano Coelho feature, sizeof(*feature)); 1487b3115f2SLuciano Coelho if (ret < 0) { 1497b3115f2SLuciano Coelho wl1271_error("Couldnt set HW encryption"); 1507b3115f2SLuciano Coelho goto out; 1517b3115f2SLuciano Coelho } 1527b3115f2SLuciano Coelho 1537b3115f2SLuciano Coelho out: 1547b3115f2SLuciano Coelho kfree(feature); 1557b3115f2SLuciano Coelho return ret; 1567b3115f2SLuciano Coelho } 1577b3115f2SLuciano Coelho 1587b3115f2SLuciano Coelho int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, 1597b3115f2SLuciano Coelho size_t len) 1607b3115f2SLuciano Coelho { 1617b3115f2SLuciano Coelho int ret; 1627b3115f2SLuciano Coelho 1637b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx mem map"); 1647b3115f2SLuciano Coelho 1654b674144SIgal Chernobelsky ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, 1664b674144SIgal Chernobelsky sizeof(struct acx_header), len); 1677b3115f2SLuciano Coelho if (ret < 0) 1687b3115f2SLuciano Coelho return ret; 1697b3115f2SLuciano Coelho 1707b3115f2SLuciano Coelho return 0; 1717b3115f2SLuciano Coelho } 1727b3115f2SLuciano Coelho 1737b3115f2SLuciano Coelho int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) 1747b3115f2SLuciano Coelho { 1757b3115f2SLuciano Coelho struct acx_rx_msdu_lifetime *acx; 1767b3115f2SLuciano Coelho int ret; 1777b3115f2SLuciano Coelho 1787b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); 1797b3115f2SLuciano Coelho 1807b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 1817b3115f2SLuciano Coelho if (!acx) { 1827b3115f2SLuciano Coelho ret = -ENOMEM; 1837b3115f2SLuciano Coelho goto out; 1847b3115f2SLuciano Coelho } 1857b3115f2SLuciano Coelho 1867b3115f2SLuciano Coelho acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); 1877b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, 1887b3115f2SLuciano Coelho acx, sizeof(*acx)); 1897b3115f2SLuciano Coelho if (ret < 0) { 1907b3115f2SLuciano Coelho wl1271_warning("failed to set rx msdu life time: %d", ret); 1917b3115f2SLuciano Coelho goto out; 1927b3115f2SLuciano Coelho } 1937b3115f2SLuciano Coelho 1947b3115f2SLuciano Coelho out: 1957b3115f2SLuciano Coelho kfree(acx); 1967b3115f2SLuciano Coelho return ret; 1977b3115f2SLuciano Coelho } 1987b3115f2SLuciano Coelho 1997b3115f2SLuciano Coelho int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, 2007b3115f2SLuciano Coelho enum acx_slot_type slot_time) 2017b3115f2SLuciano Coelho { 2027b3115f2SLuciano Coelho struct acx_slot *slot; 2037b3115f2SLuciano Coelho int ret; 2047b3115f2SLuciano Coelho 2057b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx slot"); 2067b3115f2SLuciano Coelho 2077b3115f2SLuciano Coelho slot = kzalloc(sizeof(*slot), GFP_KERNEL); 2087b3115f2SLuciano Coelho if (!slot) { 2097b3115f2SLuciano Coelho ret = -ENOMEM; 2107b3115f2SLuciano Coelho goto out; 2117b3115f2SLuciano Coelho } 2127b3115f2SLuciano Coelho 2137b3115f2SLuciano Coelho slot->role_id = wlvif->role_id; 2147b3115f2SLuciano Coelho slot->wone_index = STATION_WONE_INDEX; 2157b3115f2SLuciano Coelho slot->slot_time = slot_time; 2167b3115f2SLuciano Coelho 2177b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); 2187b3115f2SLuciano Coelho if (ret < 0) { 2197b3115f2SLuciano Coelho wl1271_warning("failed to set slot time: %d", ret); 2207b3115f2SLuciano Coelho goto out; 2217b3115f2SLuciano Coelho } 2227b3115f2SLuciano Coelho 2237b3115f2SLuciano Coelho out: 2247b3115f2SLuciano Coelho kfree(slot); 2257b3115f2SLuciano Coelho return ret; 2267b3115f2SLuciano Coelho } 2277b3115f2SLuciano Coelho 2287b3115f2SLuciano Coelho int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, 2297b3115f2SLuciano Coelho bool enable, void *mc_list, u32 mc_list_len) 2307b3115f2SLuciano Coelho { 2317b3115f2SLuciano Coelho struct acx_dot11_grp_addr_tbl *acx; 2327b3115f2SLuciano Coelho int ret; 2337b3115f2SLuciano Coelho 2347b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx group address tbl"); 2357b3115f2SLuciano Coelho 2367b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 2377b3115f2SLuciano Coelho if (!acx) { 2387b3115f2SLuciano Coelho ret = -ENOMEM; 2397b3115f2SLuciano Coelho goto out; 2407b3115f2SLuciano Coelho } 2417b3115f2SLuciano Coelho 2427b3115f2SLuciano Coelho /* MAC filtering */ 2437b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 2447b3115f2SLuciano Coelho acx->enabled = enable; 2457b3115f2SLuciano Coelho acx->num_groups = mc_list_len; 2467b3115f2SLuciano Coelho memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); 2477b3115f2SLuciano Coelho 2487b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, 2497b3115f2SLuciano Coelho acx, sizeof(*acx)); 2507b3115f2SLuciano Coelho if (ret < 0) { 2517b3115f2SLuciano Coelho wl1271_warning("failed to set group addr table: %d", ret); 2527b3115f2SLuciano Coelho goto out; 2537b3115f2SLuciano Coelho } 2547b3115f2SLuciano Coelho 2557b3115f2SLuciano Coelho out: 2567b3115f2SLuciano Coelho kfree(acx); 2577b3115f2SLuciano Coelho return ret; 2587b3115f2SLuciano Coelho } 2597b3115f2SLuciano Coelho 2607b3115f2SLuciano Coelho int wl1271_acx_service_period_timeout(struct wl1271 *wl, 2617b3115f2SLuciano Coelho struct wl12xx_vif *wlvif) 2627b3115f2SLuciano Coelho { 2637b3115f2SLuciano Coelho struct acx_rx_timeout *rx_timeout; 2647b3115f2SLuciano Coelho int ret; 2657b3115f2SLuciano Coelho 2667b3115f2SLuciano Coelho rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); 2677b3115f2SLuciano Coelho if (!rx_timeout) { 2687b3115f2SLuciano Coelho ret = -ENOMEM; 2697b3115f2SLuciano Coelho goto out; 2707b3115f2SLuciano Coelho } 2717b3115f2SLuciano Coelho 2727b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx service period timeout"); 2737b3115f2SLuciano Coelho 2747b3115f2SLuciano Coelho rx_timeout->role_id = wlvif->role_id; 2757b3115f2SLuciano Coelho rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); 2767b3115f2SLuciano Coelho rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); 2777b3115f2SLuciano Coelho 2787b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, 2797b3115f2SLuciano Coelho rx_timeout, sizeof(*rx_timeout)); 2807b3115f2SLuciano Coelho if (ret < 0) { 2817b3115f2SLuciano Coelho wl1271_warning("failed to set service period timeout: %d", 2827b3115f2SLuciano Coelho ret); 2837b3115f2SLuciano Coelho goto out; 2847b3115f2SLuciano Coelho } 2857b3115f2SLuciano Coelho 2867b3115f2SLuciano Coelho out: 2877b3115f2SLuciano Coelho kfree(rx_timeout); 2887b3115f2SLuciano Coelho return ret; 2897b3115f2SLuciano Coelho } 2907b3115f2SLuciano Coelho 2917b3115f2SLuciano Coelho int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, 2927b3115f2SLuciano Coelho u32 rts_threshold) 2937b3115f2SLuciano Coelho { 2947b3115f2SLuciano Coelho struct acx_rts_threshold *rts; 2957b3115f2SLuciano Coelho int ret; 2967b3115f2SLuciano Coelho 2977b3115f2SLuciano Coelho /* 2987b3115f2SLuciano Coelho * If the RTS threshold is not configured or out of range, use the 2997b3115f2SLuciano Coelho * default value. 3007b3115f2SLuciano Coelho */ 3017b3115f2SLuciano Coelho if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD) 3027b3115f2SLuciano Coelho rts_threshold = wl->conf.rx.rts_threshold; 3037b3115f2SLuciano Coelho 3047b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold); 3057b3115f2SLuciano Coelho 3067b3115f2SLuciano Coelho rts = kzalloc(sizeof(*rts), GFP_KERNEL); 3077b3115f2SLuciano Coelho if (!rts) { 3087b3115f2SLuciano Coelho ret = -ENOMEM; 3097b3115f2SLuciano Coelho goto out; 3107b3115f2SLuciano Coelho } 3117b3115f2SLuciano Coelho 3127b3115f2SLuciano Coelho rts->role_id = wlvif->role_id; 3137b3115f2SLuciano Coelho rts->threshold = cpu_to_le16((u16)rts_threshold); 3147b3115f2SLuciano Coelho 3157b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); 3167b3115f2SLuciano Coelho if (ret < 0) { 3177b3115f2SLuciano Coelho wl1271_warning("failed to set rts threshold: %d", ret); 3187b3115f2SLuciano Coelho goto out; 3197b3115f2SLuciano Coelho } 3207b3115f2SLuciano Coelho 3217b3115f2SLuciano Coelho out: 3227b3115f2SLuciano Coelho kfree(rts); 3237b3115f2SLuciano Coelho return ret; 3247b3115f2SLuciano Coelho } 3257b3115f2SLuciano Coelho 3267b3115f2SLuciano Coelho int wl1271_acx_dco_itrim_params(struct wl1271 *wl) 3277b3115f2SLuciano Coelho { 3287b3115f2SLuciano Coelho struct acx_dco_itrim_params *dco; 3297b3115f2SLuciano Coelho struct conf_itrim_settings *c = &wl->conf.itrim; 3307b3115f2SLuciano Coelho int ret; 3317b3115f2SLuciano Coelho 3327b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); 3337b3115f2SLuciano Coelho 3347b3115f2SLuciano Coelho dco = kzalloc(sizeof(*dco), GFP_KERNEL); 3357b3115f2SLuciano Coelho if (!dco) { 3367b3115f2SLuciano Coelho ret = -ENOMEM; 3377b3115f2SLuciano Coelho goto out; 3387b3115f2SLuciano Coelho } 3397b3115f2SLuciano Coelho 3407b3115f2SLuciano Coelho dco->enable = c->enable; 3417b3115f2SLuciano Coelho dco->timeout = cpu_to_le32(c->timeout); 3427b3115f2SLuciano Coelho 3437b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, 3447b3115f2SLuciano Coelho dco, sizeof(*dco)); 3457b3115f2SLuciano Coelho if (ret < 0) { 3467b3115f2SLuciano Coelho wl1271_warning("failed to set dco itrim parameters: %d", ret); 3477b3115f2SLuciano Coelho goto out; 3487b3115f2SLuciano Coelho } 3497b3115f2SLuciano Coelho 3507b3115f2SLuciano Coelho out: 3517b3115f2SLuciano Coelho kfree(dco); 3527b3115f2SLuciano Coelho return ret; 3537b3115f2SLuciano Coelho } 3547b3115f2SLuciano Coelho 3557b3115f2SLuciano Coelho int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, 3567b3115f2SLuciano Coelho bool enable_filter) 3577b3115f2SLuciano Coelho { 3587b3115f2SLuciano Coelho struct acx_beacon_filter_option *beacon_filter = NULL; 3597b3115f2SLuciano Coelho int ret = 0; 3607b3115f2SLuciano Coelho 361d881fa2cSEliad Peller wl1271_debug(DEBUG_ACX, "acx beacon filter opt enable=%d", 362d881fa2cSEliad Peller enable_filter); 3637b3115f2SLuciano Coelho 3647b3115f2SLuciano Coelho if (enable_filter && 3657b3115f2SLuciano Coelho wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) 3667b3115f2SLuciano Coelho goto out; 3677b3115f2SLuciano Coelho 3687b3115f2SLuciano Coelho beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); 3697b3115f2SLuciano Coelho if (!beacon_filter) { 3707b3115f2SLuciano Coelho ret = -ENOMEM; 3717b3115f2SLuciano Coelho goto out; 3727b3115f2SLuciano Coelho } 3737b3115f2SLuciano Coelho 3747b3115f2SLuciano Coelho beacon_filter->role_id = wlvif->role_id; 3757b3115f2SLuciano Coelho beacon_filter->enable = enable_filter; 3767b3115f2SLuciano Coelho 3777b3115f2SLuciano Coelho /* 3787b3115f2SLuciano Coelho * When set to zero, and the filter is enabled, beacons 3797b3115f2SLuciano Coelho * without the unicast TIM bit set are dropped. 3807b3115f2SLuciano Coelho */ 3817b3115f2SLuciano Coelho beacon_filter->max_num_beacons = 0; 3827b3115f2SLuciano Coelho 3837b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, 3847b3115f2SLuciano Coelho beacon_filter, sizeof(*beacon_filter)); 3857b3115f2SLuciano Coelho if (ret < 0) { 3867b3115f2SLuciano Coelho wl1271_warning("failed to set beacon filter opt: %d", ret); 3877b3115f2SLuciano Coelho goto out; 3887b3115f2SLuciano Coelho } 3897b3115f2SLuciano Coelho 3907b3115f2SLuciano Coelho out: 3917b3115f2SLuciano Coelho kfree(beacon_filter); 3927b3115f2SLuciano Coelho return ret; 3937b3115f2SLuciano Coelho } 3947b3115f2SLuciano Coelho 3957b3115f2SLuciano Coelho int wl1271_acx_beacon_filter_table(struct wl1271 *wl, 3967b3115f2SLuciano Coelho struct wl12xx_vif *wlvif) 3977b3115f2SLuciano Coelho { 3987b3115f2SLuciano Coelho struct acx_beacon_filter_ie_table *ie_table; 3997b3115f2SLuciano Coelho int i, idx = 0; 4007b3115f2SLuciano Coelho int ret; 4017b3115f2SLuciano Coelho bool vendor_spec = false; 4027b3115f2SLuciano Coelho 4037b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx beacon filter table"); 4047b3115f2SLuciano Coelho 4057b3115f2SLuciano Coelho ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); 4067b3115f2SLuciano Coelho if (!ie_table) { 4077b3115f2SLuciano Coelho ret = -ENOMEM; 4087b3115f2SLuciano Coelho goto out; 4097b3115f2SLuciano Coelho } 4107b3115f2SLuciano Coelho 4117b3115f2SLuciano Coelho /* configure default beacon pass-through rules */ 4127b3115f2SLuciano Coelho ie_table->role_id = wlvif->role_id; 4137b3115f2SLuciano Coelho ie_table->num_ie = 0; 4147b3115f2SLuciano Coelho for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { 4157b3115f2SLuciano Coelho struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); 4167b3115f2SLuciano Coelho ie_table->table[idx++] = r->ie; 4177b3115f2SLuciano Coelho ie_table->table[idx++] = r->rule; 4187b3115f2SLuciano Coelho 4197b3115f2SLuciano Coelho if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { 4207b3115f2SLuciano Coelho /* only one vendor specific ie allowed */ 4217b3115f2SLuciano Coelho if (vendor_spec) 4227b3115f2SLuciano Coelho continue; 4237b3115f2SLuciano Coelho 4247b3115f2SLuciano Coelho /* for vendor specific rules configure the 4257b3115f2SLuciano Coelho additional fields */ 4267b3115f2SLuciano Coelho memcpy(&(ie_table->table[idx]), r->oui, 4277b3115f2SLuciano Coelho CONF_BCN_IE_OUI_LEN); 4287b3115f2SLuciano Coelho idx += CONF_BCN_IE_OUI_LEN; 4297b3115f2SLuciano Coelho ie_table->table[idx++] = r->type; 4307b3115f2SLuciano Coelho memcpy(&(ie_table->table[idx]), r->version, 4317b3115f2SLuciano Coelho CONF_BCN_IE_VER_LEN); 4327b3115f2SLuciano Coelho idx += CONF_BCN_IE_VER_LEN; 4337b3115f2SLuciano Coelho vendor_spec = true; 4347b3115f2SLuciano Coelho } 4357b3115f2SLuciano Coelho 4367b3115f2SLuciano Coelho ie_table->num_ie++; 4377b3115f2SLuciano Coelho } 4387b3115f2SLuciano Coelho 4397b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, 4407b3115f2SLuciano Coelho ie_table, sizeof(*ie_table)); 4417b3115f2SLuciano Coelho if (ret < 0) { 4427b3115f2SLuciano Coelho wl1271_warning("failed to set beacon filter table: %d", ret); 4437b3115f2SLuciano Coelho goto out; 4447b3115f2SLuciano Coelho } 4457b3115f2SLuciano Coelho 4467b3115f2SLuciano Coelho out: 4477b3115f2SLuciano Coelho kfree(ie_table); 4487b3115f2SLuciano Coelho return ret; 4497b3115f2SLuciano Coelho } 4507b3115f2SLuciano Coelho 4517b3115f2SLuciano Coelho #define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff 4527b3115f2SLuciano Coelho 4537b3115f2SLuciano Coelho int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, 4547b3115f2SLuciano Coelho bool enable) 4557b3115f2SLuciano Coelho { 4567b3115f2SLuciano Coelho struct acx_conn_monit_params *acx; 4577b3115f2SLuciano Coelho u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; 4587b3115f2SLuciano Coelho u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; 4597b3115f2SLuciano Coelho int ret; 4607b3115f2SLuciano Coelho 4617b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s", 4627b3115f2SLuciano Coelho enable ? "enabled" : "disabled"); 4637b3115f2SLuciano Coelho 4647b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 4657b3115f2SLuciano Coelho if (!acx) { 4667b3115f2SLuciano Coelho ret = -ENOMEM; 4677b3115f2SLuciano Coelho goto out; 4687b3115f2SLuciano Coelho } 4697b3115f2SLuciano Coelho 4707b3115f2SLuciano Coelho if (enable) { 4717b3115f2SLuciano Coelho threshold = wl->conf.conn.synch_fail_thold; 4727b3115f2SLuciano Coelho timeout = wl->conf.conn.bss_lose_timeout; 4737b3115f2SLuciano Coelho } 4747b3115f2SLuciano Coelho 4757b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 4767b3115f2SLuciano Coelho acx->synch_fail_thold = cpu_to_le32(threshold); 4777b3115f2SLuciano Coelho acx->bss_lose_timeout = cpu_to_le32(timeout); 4787b3115f2SLuciano Coelho 4797b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, 4807b3115f2SLuciano Coelho acx, sizeof(*acx)); 4817b3115f2SLuciano Coelho if (ret < 0) { 4827b3115f2SLuciano Coelho wl1271_warning("failed to set connection monitor " 4837b3115f2SLuciano Coelho "parameters: %d", ret); 4847b3115f2SLuciano Coelho goto out; 4857b3115f2SLuciano Coelho } 4867b3115f2SLuciano Coelho 4877b3115f2SLuciano Coelho out: 4887b3115f2SLuciano Coelho kfree(acx); 4897b3115f2SLuciano Coelho return ret; 4907b3115f2SLuciano Coelho } 4917b3115f2SLuciano Coelho 4927b3115f2SLuciano Coelho 4937b3115f2SLuciano Coelho int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) 4947b3115f2SLuciano Coelho { 4957b3115f2SLuciano Coelho struct acx_bt_wlan_coex *pta; 4967b3115f2SLuciano Coelho int ret; 4977b3115f2SLuciano Coelho 4987b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx sg enable"); 4997b3115f2SLuciano Coelho 5007b3115f2SLuciano Coelho pta = kzalloc(sizeof(*pta), GFP_KERNEL); 5017b3115f2SLuciano Coelho if (!pta) { 5027b3115f2SLuciano Coelho ret = -ENOMEM; 5037b3115f2SLuciano Coelho goto out; 5047b3115f2SLuciano Coelho } 5057b3115f2SLuciano Coelho 5067b3115f2SLuciano Coelho if (enable) 5077b3115f2SLuciano Coelho pta->enable = wl->conf.sg.state; 5087b3115f2SLuciano Coelho else 5097b3115f2SLuciano Coelho pta->enable = CONF_SG_DISABLE; 5107b3115f2SLuciano Coelho 5117b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); 5127b3115f2SLuciano Coelho if (ret < 0) { 5137b3115f2SLuciano Coelho wl1271_warning("failed to set softgemini enable: %d", ret); 5147b3115f2SLuciano Coelho goto out; 5157b3115f2SLuciano Coelho } 5167b3115f2SLuciano Coelho 5177b3115f2SLuciano Coelho out: 5187b3115f2SLuciano Coelho kfree(pta); 5197b3115f2SLuciano Coelho return ret; 5207b3115f2SLuciano Coelho } 5217b3115f2SLuciano Coelho 5227b3115f2SLuciano Coelho int wl12xx_acx_sg_cfg(struct wl1271 *wl) 5237b3115f2SLuciano Coelho { 5247b3115f2SLuciano Coelho struct acx_bt_wlan_coex_param *param; 5257b3115f2SLuciano Coelho struct conf_sg_settings *c = &wl->conf.sg; 5267b3115f2SLuciano Coelho int i, ret; 5277b3115f2SLuciano Coelho 5287b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx sg cfg"); 5297b3115f2SLuciano Coelho 5307b3115f2SLuciano Coelho param = kzalloc(sizeof(*param), GFP_KERNEL); 5317b3115f2SLuciano Coelho if (!param) { 5327b3115f2SLuciano Coelho ret = -ENOMEM; 5337b3115f2SLuciano Coelho goto out; 5347b3115f2SLuciano Coelho } 5357b3115f2SLuciano Coelho 5367b3115f2SLuciano Coelho /* BT-WLAN coext parameters */ 5377b3115f2SLuciano Coelho for (i = 0; i < CONF_SG_PARAMS_MAX; i++) 5387b3115f2SLuciano Coelho param->params[i] = cpu_to_le32(c->params[i]); 5397b3115f2SLuciano Coelho param->param_idx = CONF_SG_PARAMS_ALL; 5407b3115f2SLuciano Coelho 5417b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); 5427b3115f2SLuciano Coelho if (ret < 0) { 5437b3115f2SLuciano Coelho wl1271_warning("failed to set sg config: %d", ret); 5447b3115f2SLuciano Coelho goto out; 5457b3115f2SLuciano Coelho } 5467b3115f2SLuciano Coelho 5477b3115f2SLuciano Coelho out: 5487b3115f2SLuciano Coelho kfree(param); 5497b3115f2SLuciano Coelho return ret; 5507b3115f2SLuciano Coelho } 5517b3115f2SLuciano Coelho 5527b3115f2SLuciano Coelho int wl1271_acx_cca_threshold(struct wl1271 *wl) 5537b3115f2SLuciano Coelho { 5547b3115f2SLuciano Coelho struct acx_energy_detection *detection; 5557b3115f2SLuciano Coelho int ret; 5567b3115f2SLuciano Coelho 5577b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx cca threshold"); 5587b3115f2SLuciano Coelho 5597b3115f2SLuciano Coelho detection = kzalloc(sizeof(*detection), GFP_KERNEL); 5607b3115f2SLuciano Coelho if (!detection) { 5617b3115f2SLuciano Coelho ret = -ENOMEM; 5627b3115f2SLuciano Coelho goto out; 5637b3115f2SLuciano Coelho } 5647b3115f2SLuciano Coelho 5657b3115f2SLuciano Coelho detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); 5667b3115f2SLuciano Coelho detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; 5677b3115f2SLuciano Coelho 5687b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, 5697b3115f2SLuciano Coelho detection, sizeof(*detection)); 5707b3115f2SLuciano Coelho if (ret < 0) 5717b3115f2SLuciano Coelho wl1271_warning("failed to set cca threshold: %d", ret); 5727b3115f2SLuciano Coelho 5737b3115f2SLuciano Coelho out: 5747b3115f2SLuciano Coelho kfree(detection); 5757b3115f2SLuciano Coelho return ret; 5767b3115f2SLuciano Coelho } 5777b3115f2SLuciano Coelho 5787b3115f2SLuciano Coelho int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif) 5797b3115f2SLuciano Coelho { 5807b3115f2SLuciano Coelho struct acx_beacon_broadcast *bb; 5817b3115f2SLuciano Coelho int ret; 5827b3115f2SLuciano Coelho 5837b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); 5847b3115f2SLuciano Coelho 5857b3115f2SLuciano Coelho bb = kzalloc(sizeof(*bb), GFP_KERNEL); 5867b3115f2SLuciano Coelho if (!bb) { 5877b3115f2SLuciano Coelho ret = -ENOMEM; 5887b3115f2SLuciano Coelho goto out; 5897b3115f2SLuciano Coelho } 5907b3115f2SLuciano Coelho 5917b3115f2SLuciano Coelho bb->role_id = wlvif->role_id; 5927b3115f2SLuciano Coelho bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); 5937b3115f2SLuciano Coelho bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); 5947b3115f2SLuciano Coelho bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; 5957b3115f2SLuciano Coelho bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; 5967b3115f2SLuciano Coelho 5977b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); 5987b3115f2SLuciano Coelho if (ret < 0) { 5997b3115f2SLuciano Coelho wl1271_warning("failed to set rx config: %d", ret); 6007b3115f2SLuciano Coelho goto out; 6017b3115f2SLuciano Coelho } 6027b3115f2SLuciano Coelho 6037b3115f2SLuciano Coelho out: 6047b3115f2SLuciano Coelho kfree(bb); 6057b3115f2SLuciano Coelho return ret; 6067b3115f2SLuciano Coelho } 6077b3115f2SLuciano Coelho 6087b3115f2SLuciano Coelho int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid) 6097b3115f2SLuciano Coelho { 6107b3115f2SLuciano Coelho struct acx_aid *acx_aid; 6117b3115f2SLuciano Coelho int ret; 6127b3115f2SLuciano Coelho 6137b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx aid"); 6147b3115f2SLuciano Coelho 6157b3115f2SLuciano Coelho acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); 6167b3115f2SLuciano Coelho if (!acx_aid) { 6177b3115f2SLuciano Coelho ret = -ENOMEM; 6187b3115f2SLuciano Coelho goto out; 6197b3115f2SLuciano Coelho } 6207b3115f2SLuciano Coelho 6217b3115f2SLuciano Coelho acx_aid->role_id = wlvif->role_id; 6227b3115f2SLuciano Coelho acx_aid->aid = cpu_to_le16(aid); 6237b3115f2SLuciano Coelho 6247b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); 6257b3115f2SLuciano Coelho if (ret < 0) { 6267b3115f2SLuciano Coelho wl1271_warning("failed to set aid: %d", ret); 6277b3115f2SLuciano Coelho goto out; 6287b3115f2SLuciano Coelho } 6297b3115f2SLuciano Coelho 6307b3115f2SLuciano Coelho out: 6317b3115f2SLuciano Coelho kfree(acx_aid); 6327b3115f2SLuciano Coelho return ret; 6337b3115f2SLuciano Coelho } 6347b3115f2SLuciano Coelho 6357b3115f2SLuciano Coelho int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) 6367b3115f2SLuciano Coelho { 6377b3115f2SLuciano Coelho struct acx_event_mask *mask; 6387b3115f2SLuciano Coelho int ret; 6397b3115f2SLuciano Coelho 6407b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx event mbox mask"); 6417b3115f2SLuciano Coelho 6427b3115f2SLuciano Coelho mask = kzalloc(sizeof(*mask), GFP_KERNEL); 6437b3115f2SLuciano Coelho if (!mask) { 6447b3115f2SLuciano Coelho ret = -ENOMEM; 6457b3115f2SLuciano Coelho goto out; 6467b3115f2SLuciano Coelho } 6477b3115f2SLuciano Coelho 6487b3115f2SLuciano Coelho /* high event mask is unused */ 6497b3115f2SLuciano Coelho mask->high_event_mask = cpu_to_le32(0xffffffff); 6507b3115f2SLuciano Coelho mask->event_mask = cpu_to_le32(event_mask); 6517b3115f2SLuciano Coelho 6527b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, 6537b3115f2SLuciano Coelho mask, sizeof(*mask)); 6547b3115f2SLuciano Coelho if (ret < 0) { 6557b3115f2SLuciano Coelho wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); 6567b3115f2SLuciano Coelho goto out; 6577b3115f2SLuciano Coelho } 6587b3115f2SLuciano Coelho 6597b3115f2SLuciano Coelho out: 6607b3115f2SLuciano Coelho kfree(mask); 6617b3115f2SLuciano Coelho return ret; 6627b3115f2SLuciano Coelho } 6637b3115f2SLuciano Coelho 6647b3115f2SLuciano Coelho int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, 6657b3115f2SLuciano Coelho enum acx_preamble_type preamble) 6667b3115f2SLuciano Coelho { 6677b3115f2SLuciano Coelho struct acx_preamble *acx; 6687b3115f2SLuciano Coelho int ret; 6697b3115f2SLuciano Coelho 6707b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx_set_preamble"); 6717b3115f2SLuciano Coelho 6727b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 6737b3115f2SLuciano Coelho if (!acx) { 6747b3115f2SLuciano Coelho ret = -ENOMEM; 6757b3115f2SLuciano Coelho goto out; 6767b3115f2SLuciano Coelho } 6777b3115f2SLuciano Coelho 6787b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 6797b3115f2SLuciano Coelho acx->preamble = preamble; 6807b3115f2SLuciano Coelho 6817b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); 6827b3115f2SLuciano Coelho if (ret < 0) { 6837b3115f2SLuciano Coelho wl1271_warning("Setting of preamble failed: %d", ret); 6847b3115f2SLuciano Coelho goto out; 6857b3115f2SLuciano Coelho } 6867b3115f2SLuciano Coelho 6877b3115f2SLuciano Coelho out: 6887b3115f2SLuciano Coelho kfree(acx); 6897b3115f2SLuciano Coelho return ret; 6907b3115f2SLuciano Coelho } 6917b3115f2SLuciano Coelho 6927b3115f2SLuciano Coelho int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, 6937b3115f2SLuciano Coelho enum acx_ctsprotect_type ctsprotect) 6947b3115f2SLuciano Coelho { 6957b3115f2SLuciano Coelho struct acx_ctsprotect *acx; 6967b3115f2SLuciano Coelho int ret; 6977b3115f2SLuciano Coelho 6987b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); 6997b3115f2SLuciano Coelho 7007b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 7017b3115f2SLuciano Coelho if (!acx) { 7027b3115f2SLuciano Coelho ret = -ENOMEM; 7037b3115f2SLuciano Coelho goto out; 7047b3115f2SLuciano Coelho } 7057b3115f2SLuciano Coelho 7067b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 7077b3115f2SLuciano Coelho acx->ctsprotect = ctsprotect; 7087b3115f2SLuciano Coelho 7097b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); 7107b3115f2SLuciano Coelho if (ret < 0) { 7117b3115f2SLuciano Coelho wl1271_warning("Setting of ctsprotect failed: %d", ret); 7127b3115f2SLuciano Coelho goto out; 7137b3115f2SLuciano Coelho } 7147b3115f2SLuciano Coelho 7157b3115f2SLuciano Coelho out: 7167b3115f2SLuciano Coelho kfree(acx); 7177b3115f2SLuciano Coelho return ret; 7187b3115f2SLuciano Coelho } 7197b3115f2SLuciano Coelho 7204987257cSLuciano Coelho int wl1271_acx_statistics(struct wl1271 *wl, void *stats) 7217b3115f2SLuciano Coelho { 7227b3115f2SLuciano Coelho int ret; 7237b3115f2SLuciano Coelho 7247b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx statistics"); 7257b3115f2SLuciano Coelho 7267b3115f2SLuciano Coelho ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, 7274b674144SIgal Chernobelsky sizeof(struct acx_header), 7284987257cSLuciano Coelho wl->stats.fw_stats_len); 7297b3115f2SLuciano Coelho if (ret < 0) { 7307b3115f2SLuciano Coelho wl1271_warning("acx statistics failed: %d", ret); 7317b3115f2SLuciano Coelho return -ENOMEM; 7327b3115f2SLuciano Coelho } 7337b3115f2SLuciano Coelho 7347b3115f2SLuciano Coelho return 0; 7357b3115f2SLuciano Coelho } 7367b3115f2SLuciano Coelho 7377b3115f2SLuciano Coelho int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) 7387b3115f2SLuciano Coelho { 7397b3115f2SLuciano Coelho struct acx_rate_policy *acx; 7407b3115f2SLuciano Coelho struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; 7417b3115f2SLuciano Coelho int ret = 0; 7427b3115f2SLuciano Coelho 7437b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx rate policies"); 7447b3115f2SLuciano Coelho 7457b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 7467b3115f2SLuciano Coelho 7477b3115f2SLuciano Coelho if (!acx) { 7487b3115f2SLuciano Coelho ret = -ENOMEM; 7497b3115f2SLuciano Coelho goto out; 7507b3115f2SLuciano Coelho } 7517b3115f2SLuciano Coelho 7527b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", 7537b3115f2SLuciano Coelho wlvif->basic_rate, wlvif->rate_set); 7547b3115f2SLuciano Coelho 7557b3115f2SLuciano Coelho /* configure one basic rate class */ 7567b3115f2SLuciano Coelho acx->rate_policy_idx = cpu_to_le32(wlvif->sta.basic_rate_idx); 7577b3115f2SLuciano Coelho acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->basic_rate); 7587b3115f2SLuciano Coelho acx->rate_policy.short_retry_limit = c->short_retry_limit; 7597b3115f2SLuciano Coelho acx->rate_policy.long_retry_limit = c->long_retry_limit; 7607b3115f2SLuciano Coelho acx->rate_policy.aflags = c->aflags; 7617b3115f2SLuciano Coelho 7627b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); 7637b3115f2SLuciano Coelho if (ret < 0) { 7647b3115f2SLuciano Coelho wl1271_warning("Setting of rate policies failed: %d", ret); 7657b3115f2SLuciano Coelho goto out; 7667b3115f2SLuciano Coelho } 7677b3115f2SLuciano Coelho 7687b3115f2SLuciano Coelho /* configure one AP supported rate class */ 7697b3115f2SLuciano Coelho acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx); 770fa7930afSArik Nemtsov 771fa7930afSArik Nemtsov /* the AP policy is HW specific */ 772fa7930afSArik Nemtsov acx->rate_policy.enabled_rates = 773fa7930afSArik Nemtsov cpu_to_le32(wlcore_hw_sta_get_ap_rate_mask(wl, wlvif)); 7747b3115f2SLuciano Coelho acx->rate_policy.short_retry_limit = c->short_retry_limit; 7757b3115f2SLuciano Coelho acx->rate_policy.long_retry_limit = c->long_retry_limit; 7767b3115f2SLuciano Coelho acx->rate_policy.aflags = c->aflags; 7777b3115f2SLuciano Coelho 7787b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); 7797b3115f2SLuciano Coelho if (ret < 0) { 7807b3115f2SLuciano Coelho wl1271_warning("Setting of rate policies failed: %d", ret); 7817b3115f2SLuciano Coelho goto out; 7827b3115f2SLuciano Coelho } 7837b3115f2SLuciano Coelho 7847b3115f2SLuciano Coelho /* 7857b3115f2SLuciano Coelho * configure one rate class for basic p2p operations. 7867b3115f2SLuciano Coelho * (p2p packets should always go out with OFDM rates, even 7877b3115f2SLuciano Coelho * if we are currently connected to 11b AP) 7887b3115f2SLuciano Coelho */ 7897b3115f2SLuciano Coelho acx->rate_policy_idx = cpu_to_le32(wlvif->sta.p2p_rate_idx); 7907b3115f2SLuciano Coelho acx->rate_policy.enabled_rates = 7917b3115f2SLuciano Coelho cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P); 7927b3115f2SLuciano Coelho acx->rate_policy.short_retry_limit = c->short_retry_limit; 7937b3115f2SLuciano Coelho acx->rate_policy.long_retry_limit = c->long_retry_limit; 7947b3115f2SLuciano Coelho acx->rate_policy.aflags = c->aflags; 7957b3115f2SLuciano Coelho 7967b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); 7977b3115f2SLuciano Coelho if (ret < 0) { 7987b3115f2SLuciano Coelho wl1271_warning("Setting of rate policies failed: %d", ret); 7997b3115f2SLuciano Coelho goto out; 8007b3115f2SLuciano Coelho } 8017b3115f2SLuciano Coelho 8027b3115f2SLuciano Coelho out: 8037b3115f2SLuciano Coelho kfree(acx); 8047b3115f2SLuciano Coelho return ret; 8057b3115f2SLuciano Coelho } 8067b3115f2SLuciano Coelho 8077b3115f2SLuciano Coelho int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, 8087b3115f2SLuciano Coelho u8 idx) 8097b3115f2SLuciano Coelho { 8107b3115f2SLuciano Coelho struct acx_rate_policy *acx; 8117b3115f2SLuciano Coelho int ret = 0; 8127b3115f2SLuciano Coelho 8137b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x", 8147b3115f2SLuciano Coelho idx, c->enabled_rates); 8157b3115f2SLuciano Coelho 8167b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 8177b3115f2SLuciano Coelho if (!acx) { 8187b3115f2SLuciano Coelho ret = -ENOMEM; 8197b3115f2SLuciano Coelho goto out; 8207b3115f2SLuciano Coelho } 8217b3115f2SLuciano Coelho 8227b3115f2SLuciano Coelho acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); 8237b3115f2SLuciano Coelho acx->rate_policy.short_retry_limit = c->short_retry_limit; 8247b3115f2SLuciano Coelho acx->rate_policy.long_retry_limit = c->long_retry_limit; 8257b3115f2SLuciano Coelho acx->rate_policy.aflags = c->aflags; 8267b3115f2SLuciano Coelho 8277b3115f2SLuciano Coelho acx->rate_policy_idx = cpu_to_le32(idx); 8287b3115f2SLuciano Coelho 8297b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); 8307b3115f2SLuciano Coelho if (ret < 0) { 8317b3115f2SLuciano Coelho wl1271_warning("Setting of ap rate policy failed: %d", ret); 8327b3115f2SLuciano Coelho goto out; 8337b3115f2SLuciano Coelho } 8347b3115f2SLuciano Coelho 8357b3115f2SLuciano Coelho out: 8367b3115f2SLuciano Coelho kfree(acx); 8377b3115f2SLuciano Coelho return ret; 8387b3115f2SLuciano Coelho } 8397b3115f2SLuciano Coelho 8407b3115f2SLuciano Coelho int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, 8417b3115f2SLuciano Coelho u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) 8427b3115f2SLuciano Coelho { 8437b3115f2SLuciano Coelho struct acx_ac_cfg *acx; 8447b3115f2SLuciano Coelho int ret = 0; 8457b3115f2SLuciano Coelho 8467b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " 8477b3115f2SLuciano Coelho "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop); 8487b3115f2SLuciano Coelho 8497b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 8507b3115f2SLuciano Coelho 8517b3115f2SLuciano Coelho if (!acx) { 8527b3115f2SLuciano Coelho ret = -ENOMEM; 8537b3115f2SLuciano Coelho goto out; 8547b3115f2SLuciano Coelho } 8557b3115f2SLuciano Coelho 8567b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 8577b3115f2SLuciano Coelho acx->ac = ac; 8587b3115f2SLuciano Coelho acx->cw_min = cw_min; 8597b3115f2SLuciano Coelho acx->cw_max = cpu_to_le16(cw_max); 8607b3115f2SLuciano Coelho acx->aifsn = aifsn; 8617b3115f2SLuciano Coelho acx->tx_op_limit = cpu_to_le16(txop); 8627b3115f2SLuciano Coelho 8637b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); 8647b3115f2SLuciano Coelho if (ret < 0) { 8657b3115f2SLuciano Coelho wl1271_warning("acx ac cfg failed: %d", ret); 8667b3115f2SLuciano Coelho goto out; 8677b3115f2SLuciano Coelho } 8687b3115f2SLuciano Coelho 8697b3115f2SLuciano Coelho out: 8707b3115f2SLuciano Coelho kfree(acx); 8717b3115f2SLuciano Coelho return ret; 8727b3115f2SLuciano Coelho } 8737b3115f2SLuciano Coelho 8747b3115f2SLuciano Coelho int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, 8757b3115f2SLuciano Coelho u8 queue_id, u8 channel_type, 8767b3115f2SLuciano Coelho u8 tsid, u8 ps_scheme, u8 ack_policy, 8777b3115f2SLuciano Coelho u32 apsd_conf0, u32 apsd_conf1) 8787b3115f2SLuciano Coelho { 8797b3115f2SLuciano Coelho struct acx_tid_config *acx; 8807b3115f2SLuciano Coelho int ret = 0; 8817b3115f2SLuciano Coelho 8827b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx tid config"); 8837b3115f2SLuciano Coelho 8847b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 8857b3115f2SLuciano Coelho 8867b3115f2SLuciano Coelho if (!acx) { 8877b3115f2SLuciano Coelho ret = -ENOMEM; 8887b3115f2SLuciano Coelho goto out; 8897b3115f2SLuciano Coelho } 8907b3115f2SLuciano Coelho 8917b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 8927b3115f2SLuciano Coelho acx->queue_id = queue_id; 8937b3115f2SLuciano Coelho acx->channel_type = channel_type; 8947b3115f2SLuciano Coelho acx->tsid = tsid; 8957b3115f2SLuciano Coelho acx->ps_scheme = ps_scheme; 8967b3115f2SLuciano Coelho acx->ack_policy = ack_policy; 8977b3115f2SLuciano Coelho acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); 8987b3115f2SLuciano Coelho acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); 8997b3115f2SLuciano Coelho 9007b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); 9017b3115f2SLuciano Coelho if (ret < 0) { 9027b3115f2SLuciano Coelho wl1271_warning("Setting of tid config failed: %d", ret); 9037b3115f2SLuciano Coelho goto out; 9047b3115f2SLuciano Coelho } 9057b3115f2SLuciano Coelho 9067b3115f2SLuciano Coelho out: 9077b3115f2SLuciano Coelho kfree(acx); 9087b3115f2SLuciano Coelho return ret; 9097b3115f2SLuciano Coelho } 9107b3115f2SLuciano Coelho 9117b3115f2SLuciano Coelho int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold) 9127b3115f2SLuciano Coelho { 9137b3115f2SLuciano Coelho struct acx_frag_threshold *acx; 9147b3115f2SLuciano Coelho int ret = 0; 9157b3115f2SLuciano Coelho 9167b3115f2SLuciano Coelho /* 9177b3115f2SLuciano Coelho * If the fragmentation is not configured or out of range, use the 9187b3115f2SLuciano Coelho * default value. 9197b3115f2SLuciano Coelho */ 9207b3115f2SLuciano Coelho if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD) 9217b3115f2SLuciano Coelho frag_threshold = wl->conf.tx.frag_threshold; 9227b3115f2SLuciano Coelho 9237b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold); 9247b3115f2SLuciano Coelho 9257b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 9267b3115f2SLuciano Coelho 9277b3115f2SLuciano Coelho if (!acx) { 9287b3115f2SLuciano Coelho ret = -ENOMEM; 9297b3115f2SLuciano Coelho goto out; 9307b3115f2SLuciano Coelho } 9317b3115f2SLuciano Coelho 9327b3115f2SLuciano Coelho acx->frag_threshold = cpu_to_le16((u16)frag_threshold); 9337b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); 9347b3115f2SLuciano Coelho if (ret < 0) { 9357b3115f2SLuciano Coelho wl1271_warning("Setting of frag threshold failed: %d", ret); 9367b3115f2SLuciano Coelho goto out; 9377b3115f2SLuciano Coelho } 9387b3115f2SLuciano Coelho 9397b3115f2SLuciano Coelho out: 9407b3115f2SLuciano Coelho kfree(acx); 9417b3115f2SLuciano Coelho return ret; 9427b3115f2SLuciano Coelho } 9437b3115f2SLuciano Coelho 9447b3115f2SLuciano Coelho int wl1271_acx_tx_config_options(struct wl1271 *wl) 9457b3115f2SLuciano Coelho { 9467b3115f2SLuciano Coelho struct acx_tx_config_options *acx; 9477b3115f2SLuciano Coelho int ret = 0; 9487b3115f2SLuciano Coelho 9497b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx tx config options"); 9507b3115f2SLuciano Coelho 9517b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 9527b3115f2SLuciano Coelho 9537b3115f2SLuciano Coelho if (!acx) { 9547b3115f2SLuciano Coelho ret = -ENOMEM; 9557b3115f2SLuciano Coelho goto out; 9567b3115f2SLuciano Coelho } 9577b3115f2SLuciano Coelho 9587b3115f2SLuciano Coelho acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); 9597b3115f2SLuciano Coelho acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); 9607b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); 9617b3115f2SLuciano Coelho if (ret < 0) { 9627b3115f2SLuciano Coelho wl1271_warning("Setting of tx options failed: %d", ret); 9637b3115f2SLuciano Coelho goto out; 9647b3115f2SLuciano Coelho } 9657b3115f2SLuciano Coelho 9667b3115f2SLuciano Coelho out: 9677b3115f2SLuciano Coelho kfree(acx); 9687b3115f2SLuciano Coelho return ret; 9697b3115f2SLuciano Coelho } 9707b3115f2SLuciano Coelho 9717b3115f2SLuciano Coelho int wl12xx_acx_mem_cfg(struct wl1271 *wl) 9727b3115f2SLuciano Coelho { 9737b3115f2SLuciano Coelho struct wl12xx_acx_config_memory *mem_conf; 9747b3115f2SLuciano Coelho struct conf_memory_settings *mem; 9757b3115f2SLuciano Coelho int ret; 9767b3115f2SLuciano Coelho 9777b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); 9787b3115f2SLuciano Coelho 9797b3115f2SLuciano Coelho mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); 9807b3115f2SLuciano Coelho if (!mem_conf) { 9817b3115f2SLuciano Coelho ret = -ENOMEM; 9827b3115f2SLuciano Coelho goto out; 9837b3115f2SLuciano Coelho } 9847b3115f2SLuciano Coelho 9855453dc10SLuciano Coelho mem = &wl->conf.mem; 9867b3115f2SLuciano Coelho 9877b3115f2SLuciano Coelho /* memory config */ 9887b3115f2SLuciano Coelho mem_conf->num_stations = mem->num_stations; 9897b3115f2SLuciano Coelho mem_conf->rx_mem_block_num = mem->rx_block_num; 9907b3115f2SLuciano Coelho mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; 9917b3115f2SLuciano Coelho mem_conf->num_ssid_profiles = mem->ssid_profiles; 99272b0624fSArik Nemtsov mem_conf->total_tx_descriptors = cpu_to_le32(wl->num_tx_desc); 9937b3115f2SLuciano Coelho mem_conf->dyn_mem_enable = mem->dynamic_memory; 9947b3115f2SLuciano Coelho mem_conf->tx_free_req = mem->min_req_tx_blocks; 9957b3115f2SLuciano Coelho mem_conf->rx_free_req = mem->min_req_rx_blocks; 9967b3115f2SLuciano Coelho mem_conf->tx_min = mem->tx_min; 9977b3115f2SLuciano Coelho mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks; 9987b3115f2SLuciano Coelho 9997b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, 10007b3115f2SLuciano Coelho sizeof(*mem_conf)); 10017b3115f2SLuciano Coelho if (ret < 0) { 10027b3115f2SLuciano Coelho wl1271_warning("wl1271 mem config failed: %d", ret); 10037b3115f2SLuciano Coelho goto out; 10047b3115f2SLuciano Coelho } 10057b3115f2SLuciano Coelho 10067b3115f2SLuciano Coelho out: 10077b3115f2SLuciano Coelho kfree(mem_conf); 10087b3115f2SLuciano Coelho return ret; 10097b3115f2SLuciano Coelho } 1010c331b344SLuciano Coelho EXPORT_SYMBOL_GPL(wl12xx_acx_mem_cfg); 10117b3115f2SLuciano Coelho 10127b3115f2SLuciano Coelho int wl1271_acx_init_mem_config(struct wl1271 *wl) 10137b3115f2SLuciano Coelho { 10147b3115f2SLuciano Coelho int ret; 10157b3115f2SLuciano Coelho 10167b3115f2SLuciano Coelho wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), 10177b3115f2SLuciano Coelho GFP_KERNEL); 10187b3115f2SLuciano Coelho if (!wl->target_mem_map) { 10197b3115f2SLuciano Coelho wl1271_error("couldn't allocate target memory map"); 10207b3115f2SLuciano Coelho return -ENOMEM; 10217b3115f2SLuciano Coelho } 10227b3115f2SLuciano Coelho 10237b3115f2SLuciano Coelho /* we now ask for the firmware built memory map */ 10247b3115f2SLuciano Coelho ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, 10257b3115f2SLuciano Coelho sizeof(struct wl1271_acx_mem_map)); 10267b3115f2SLuciano Coelho if (ret < 0) { 10277b3115f2SLuciano Coelho wl1271_error("couldn't retrieve firmware memory map"); 10287b3115f2SLuciano Coelho kfree(wl->target_mem_map); 10297b3115f2SLuciano Coelho wl->target_mem_map = NULL; 10307b3115f2SLuciano Coelho return ret; 10317b3115f2SLuciano Coelho } 10327b3115f2SLuciano Coelho 10337b3115f2SLuciano Coelho /* initialize TX block book keeping */ 10347b3115f2SLuciano Coelho wl->tx_blocks_available = 10357b3115f2SLuciano Coelho le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); 10367b3115f2SLuciano Coelho wl1271_debug(DEBUG_TX, "available tx blocks: %d", 10377b3115f2SLuciano Coelho wl->tx_blocks_available); 10387b3115f2SLuciano Coelho 10397b3115f2SLuciano Coelho return 0; 10407b3115f2SLuciano Coelho } 1041c331b344SLuciano Coelho EXPORT_SYMBOL_GPL(wl1271_acx_init_mem_config); 10427b3115f2SLuciano Coelho 10437b3115f2SLuciano Coelho int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) 10447b3115f2SLuciano Coelho { 10457b3115f2SLuciano Coelho struct wl1271_acx_rx_config_opt *rx_conf; 10467b3115f2SLuciano Coelho int ret; 10477b3115f2SLuciano Coelho 10487b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); 10497b3115f2SLuciano Coelho 10507b3115f2SLuciano Coelho rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); 10517b3115f2SLuciano Coelho if (!rx_conf) { 10527b3115f2SLuciano Coelho ret = -ENOMEM; 10537b3115f2SLuciano Coelho goto out; 10547b3115f2SLuciano Coelho } 10557b3115f2SLuciano Coelho 10567b3115f2SLuciano Coelho rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); 10577b3115f2SLuciano Coelho rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); 10587b3115f2SLuciano Coelho rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); 10597b3115f2SLuciano Coelho rx_conf->queue_type = wl->conf.rx.queue_type; 10607b3115f2SLuciano Coelho 10617b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, 10627b3115f2SLuciano Coelho sizeof(*rx_conf)); 10637b3115f2SLuciano Coelho if (ret < 0) { 10647b3115f2SLuciano Coelho wl1271_warning("wl1271 rx config opt failed: %d", ret); 10657b3115f2SLuciano Coelho goto out; 10667b3115f2SLuciano Coelho } 10677b3115f2SLuciano Coelho 10687b3115f2SLuciano Coelho out: 10697b3115f2SLuciano Coelho kfree(rx_conf); 10707b3115f2SLuciano Coelho return ret; 10717b3115f2SLuciano Coelho } 10727b3115f2SLuciano Coelho 10737b3115f2SLuciano Coelho int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, 10747b3115f2SLuciano Coelho bool enable) 10757b3115f2SLuciano Coelho { 10767b3115f2SLuciano Coelho struct wl1271_acx_bet_enable *acx = NULL; 10777b3115f2SLuciano Coelho int ret = 0; 10787b3115f2SLuciano Coelho 10797b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx bet enable"); 10807b3115f2SLuciano Coelho 10817b3115f2SLuciano Coelho if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) 10827b3115f2SLuciano Coelho goto out; 10837b3115f2SLuciano Coelho 10847b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 10857b3115f2SLuciano Coelho if (!acx) { 10867b3115f2SLuciano Coelho ret = -ENOMEM; 10877b3115f2SLuciano Coelho goto out; 10887b3115f2SLuciano Coelho } 10897b3115f2SLuciano Coelho 10907b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 10917b3115f2SLuciano Coelho acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; 10927b3115f2SLuciano Coelho acx->max_consecutive = wl->conf.conn.bet_max_consecutive; 10937b3115f2SLuciano Coelho 10947b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); 10957b3115f2SLuciano Coelho if (ret < 0) { 10967b3115f2SLuciano Coelho wl1271_warning("acx bet enable failed: %d", ret); 10977b3115f2SLuciano Coelho goto out; 10987b3115f2SLuciano Coelho } 10997b3115f2SLuciano Coelho 11007b3115f2SLuciano Coelho out: 11017b3115f2SLuciano Coelho kfree(acx); 11027b3115f2SLuciano Coelho return ret; 11037b3115f2SLuciano Coelho } 11047b3115f2SLuciano Coelho 11057b3115f2SLuciano Coelho int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, 11067b3115f2SLuciano Coelho u8 enable, __be32 address) 11077b3115f2SLuciano Coelho { 11087b3115f2SLuciano Coelho struct wl1271_acx_arp_filter *acx; 11097b3115f2SLuciano Coelho int ret; 11107b3115f2SLuciano Coelho 11117b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); 11127b3115f2SLuciano Coelho 11137b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 11147b3115f2SLuciano Coelho if (!acx) { 11157b3115f2SLuciano Coelho ret = -ENOMEM; 11167b3115f2SLuciano Coelho goto out; 11177b3115f2SLuciano Coelho } 11187b3115f2SLuciano Coelho 11197b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 11207b3115f2SLuciano Coelho acx->version = ACX_IPV4_VERSION; 11217b3115f2SLuciano Coelho acx->enable = enable; 11227b3115f2SLuciano Coelho 11237b3115f2SLuciano Coelho if (enable) 11247b3115f2SLuciano Coelho memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); 11257b3115f2SLuciano Coelho 11267b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, 11277b3115f2SLuciano Coelho acx, sizeof(*acx)); 11287b3115f2SLuciano Coelho if (ret < 0) { 11297b3115f2SLuciano Coelho wl1271_warning("failed to set arp ip filter: %d", ret); 11307b3115f2SLuciano Coelho goto out; 11317b3115f2SLuciano Coelho } 11327b3115f2SLuciano Coelho 11337b3115f2SLuciano Coelho out: 11347b3115f2SLuciano Coelho kfree(acx); 11357b3115f2SLuciano Coelho return ret; 11367b3115f2SLuciano Coelho } 11377b3115f2SLuciano Coelho 11387b3115f2SLuciano Coelho int wl1271_acx_pm_config(struct wl1271 *wl) 11397b3115f2SLuciano Coelho { 11407b3115f2SLuciano Coelho struct wl1271_acx_pm_config *acx = NULL; 11417b3115f2SLuciano Coelho struct conf_pm_config_settings *c = &wl->conf.pm_config; 11427b3115f2SLuciano Coelho int ret = 0; 11437b3115f2SLuciano Coelho 11447b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx pm config"); 11457b3115f2SLuciano Coelho 11467b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 11477b3115f2SLuciano Coelho if (!acx) { 11487b3115f2SLuciano Coelho ret = -ENOMEM; 11497b3115f2SLuciano Coelho goto out; 11507b3115f2SLuciano Coelho } 11517b3115f2SLuciano Coelho 11527b3115f2SLuciano Coelho acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); 11537b3115f2SLuciano Coelho acx->host_fast_wakeup_support = c->host_fast_wakeup_support; 11547b3115f2SLuciano Coelho 11557b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); 11567b3115f2SLuciano Coelho if (ret < 0) { 11577b3115f2SLuciano Coelho wl1271_warning("acx pm config failed: %d", ret); 11587b3115f2SLuciano Coelho goto out; 11597b3115f2SLuciano Coelho } 11607b3115f2SLuciano Coelho 11617b3115f2SLuciano Coelho out: 11627b3115f2SLuciano Coelho kfree(acx); 11637b3115f2SLuciano Coelho return ret; 11647b3115f2SLuciano Coelho } 1165c331b344SLuciano Coelho EXPORT_SYMBOL_GPL(wl1271_acx_pm_config); 11667b3115f2SLuciano Coelho 11677b3115f2SLuciano Coelho int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, 11687b3115f2SLuciano Coelho bool enable) 11697b3115f2SLuciano Coelho { 11707b3115f2SLuciano Coelho struct wl1271_acx_keep_alive_mode *acx = NULL; 11717b3115f2SLuciano Coelho int ret = 0; 11727b3115f2SLuciano Coelho 11737b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable); 11747b3115f2SLuciano Coelho 11757b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 11767b3115f2SLuciano Coelho if (!acx) { 11777b3115f2SLuciano Coelho ret = -ENOMEM; 11787b3115f2SLuciano Coelho goto out; 11797b3115f2SLuciano Coelho } 11807b3115f2SLuciano Coelho 11817b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 11827b3115f2SLuciano Coelho acx->enabled = enable; 11837b3115f2SLuciano Coelho 11847b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); 11857b3115f2SLuciano Coelho if (ret < 0) { 11867b3115f2SLuciano Coelho wl1271_warning("acx keep alive mode failed: %d", ret); 11877b3115f2SLuciano Coelho goto out; 11887b3115f2SLuciano Coelho } 11897b3115f2SLuciano Coelho 11907b3115f2SLuciano Coelho out: 11917b3115f2SLuciano Coelho kfree(acx); 11927b3115f2SLuciano Coelho return ret; 11937b3115f2SLuciano Coelho } 11947b3115f2SLuciano Coelho 11957b3115f2SLuciano Coelho int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, 11967b3115f2SLuciano Coelho u8 index, u8 tpl_valid) 11977b3115f2SLuciano Coelho { 11987b3115f2SLuciano Coelho struct wl1271_acx_keep_alive_config *acx = NULL; 11997b3115f2SLuciano Coelho int ret = 0; 12007b3115f2SLuciano Coelho 12017b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx keep alive config"); 12027b3115f2SLuciano Coelho 12037b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 12047b3115f2SLuciano Coelho if (!acx) { 12057b3115f2SLuciano Coelho ret = -ENOMEM; 12067b3115f2SLuciano Coelho goto out; 12077b3115f2SLuciano Coelho } 12087b3115f2SLuciano Coelho 12097b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 12107b3115f2SLuciano Coelho acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); 12117b3115f2SLuciano Coelho acx->index = index; 12127b3115f2SLuciano Coelho acx->tpl_validation = tpl_valid; 12137b3115f2SLuciano Coelho acx->trigger = ACX_KEEP_ALIVE_NO_TX; 12147b3115f2SLuciano Coelho 12157b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG, 12167b3115f2SLuciano Coelho acx, sizeof(*acx)); 12177b3115f2SLuciano Coelho if (ret < 0) { 12187b3115f2SLuciano Coelho wl1271_warning("acx keep alive config failed: %d", ret); 12197b3115f2SLuciano Coelho goto out; 12207b3115f2SLuciano Coelho } 12217b3115f2SLuciano Coelho 12227b3115f2SLuciano Coelho out: 12237b3115f2SLuciano Coelho kfree(acx); 12247b3115f2SLuciano Coelho return ret; 12257b3115f2SLuciano Coelho } 12267b3115f2SLuciano Coelho 12277b3115f2SLuciano Coelho int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, 12287b3115f2SLuciano Coelho bool enable, s16 thold, u8 hyst) 12297b3115f2SLuciano Coelho { 12307b3115f2SLuciano Coelho struct wl1271_acx_rssi_snr_trigger *acx = NULL; 12317b3115f2SLuciano Coelho int ret = 0; 12327b3115f2SLuciano Coelho 12337b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx rssi snr trigger"); 12347b3115f2SLuciano Coelho 12357b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 12367b3115f2SLuciano Coelho if (!acx) { 12377b3115f2SLuciano Coelho ret = -ENOMEM; 12387b3115f2SLuciano Coelho goto out; 12397b3115f2SLuciano Coelho } 12407b3115f2SLuciano Coelho 12417b3115f2SLuciano Coelho wlvif->last_rssi_event = -1; 12427b3115f2SLuciano Coelho 12437b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 12447b3115f2SLuciano Coelho acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); 12457b3115f2SLuciano Coelho acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; 12467b3115f2SLuciano Coelho acx->type = WL1271_ACX_TRIG_TYPE_EDGE; 12477b3115f2SLuciano Coelho if (enable) 12487b3115f2SLuciano Coelho acx->enable = WL1271_ACX_TRIG_ENABLE; 12497b3115f2SLuciano Coelho else 12507b3115f2SLuciano Coelho acx->enable = WL1271_ACX_TRIG_DISABLE; 12517b3115f2SLuciano Coelho 12527b3115f2SLuciano Coelho acx->index = WL1271_ACX_TRIG_IDX_RSSI; 12537b3115f2SLuciano Coelho acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; 12547b3115f2SLuciano Coelho acx->threshold = cpu_to_le16(thold); 12557b3115f2SLuciano Coelho acx->hysteresis = hyst; 12567b3115f2SLuciano Coelho 12577b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx)); 12587b3115f2SLuciano Coelho if (ret < 0) { 12597b3115f2SLuciano Coelho wl1271_warning("acx rssi snr trigger setting failed: %d", ret); 12607b3115f2SLuciano Coelho goto out; 12617b3115f2SLuciano Coelho } 12627b3115f2SLuciano Coelho 12637b3115f2SLuciano Coelho out: 12647b3115f2SLuciano Coelho kfree(acx); 12657b3115f2SLuciano Coelho return ret; 12667b3115f2SLuciano Coelho } 12677b3115f2SLuciano Coelho 12687b3115f2SLuciano Coelho int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, 12697b3115f2SLuciano Coelho struct wl12xx_vif *wlvif) 12707b3115f2SLuciano Coelho { 12717b3115f2SLuciano Coelho struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; 12727b3115f2SLuciano Coelho struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; 12737b3115f2SLuciano Coelho int ret = 0; 12747b3115f2SLuciano Coelho 12757b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights"); 12767b3115f2SLuciano Coelho 12777b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 12787b3115f2SLuciano Coelho if (!acx) { 12797b3115f2SLuciano Coelho ret = -ENOMEM; 12807b3115f2SLuciano Coelho goto out; 12817b3115f2SLuciano Coelho } 12827b3115f2SLuciano Coelho 12837b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 12847b3115f2SLuciano Coelho acx->rssi_beacon = c->avg_weight_rssi_beacon; 12857b3115f2SLuciano Coelho acx->rssi_data = c->avg_weight_rssi_data; 12867b3115f2SLuciano Coelho acx->snr_beacon = c->avg_weight_snr_beacon; 12877b3115f2SLuciano Coelho acx->snr_data = c->avg_weight_snr_data; 12887b3115f2SLuciano Coelho 12897b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx)); 12907b3115f2SLuciano Coelho if (ret < 0) { 12917b3115f2SLuciano Coelho wl1271_warning("acx rssi snr trigger weights failed: %d", ret); 12927b3115f2SLuciano Coelho goto out; 12937b3115f2SLuciano Coelho } 12947b3115f2SLuciano Coelho 12957b3115f2SLuciano Coelho out: 12967b3115f2SLuciano Coelho kfree(acx); 12977b3115f2SLuciano Coelho return ret; 12987b3115f2SLuciano Coelho } 12997b3115f2SLuciano Coelho 13007b3115f2SLuciano Coelho int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, 13017b3115f2SLuciano Coelho struct ieee80211_sta_ht_cap *ht_cap, 13027b3115f2SLuciano Coelho bool allow_ht_operation, u8 hlid) 13037b3115f2SLuciano Coelho { 13047b3115f2SLuciano Coelho struct wl1271_acx_ht_capabilities *acx; 13057b3115f2SLuciano Coelho int ret = 0; 13067b3115f2SLuciano Coelho u32 ht_capabilites = 0; 13077b3115f2SLuciano Coelho 13087b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx ht capabilities setting " 13097b3115f2SLuciano Coelho "sta supp: %d sta cap: %d", ht_cap->ht_supported, 13107b3115f2SLuciano Coelho ht_cap->cap); 13117b3115f2SLuciano Coelho 13127b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 13137b3115f2SLuciano Coelho if (!acx) { 13147b3115f2SLuciano Coelho ret = -ENOMEM; 13157b3115f2SLuciano Coelho goto out; 13167b3115f2SLuciano Coelho } 13177b3115f2SLuciano Coelho 13187b3115f2SLuciano Coelho if (allow_ht_operation && ht_cap->ht_supported) { 13197b3115f2SLuciano Coelho /* no need to translate capabilities - use the spec values */ 13207b3115f2SLuciano Coelho ht_capabilites = ht_cap->cap; 13217b3115f2SLuciano Coelho 13227b3115f2SLuciano Coelho /* 13237b3115f2SLuciano Coelho * this bit is not employed by the spec but only by FW to 13247b3115f2SLuciano Coelho * indicate peer HT support 13257b3115f2SLuciano Coelho */ 13267b3115f2SLuciano Coelho ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; 13277b3115f2SLuciano Coelho 13287b3115f2SLuciano Coelho /* get data from A-MPDU parameters field */ 13297b3115f2SLuciano Coelho acx->ampdu_max_length = ht_cap->ampdu_factor; 13307b3115f2SLuciano Coelho acx->ampdu_min_spacing = ht_cap->ampdu_density; 13317b3115f2SLuciano Coelho } 13327b3115f2SLuciano Coelho 13337b3115f2SLuciano Coelho acx->hlid = hlid; 13347b3115f2SLuciano Coelho acx->ht_capabilites = cpu_to_le32(ht_capabilites); 13357b3115f2SLuciano Coelho 13367b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); 13377b3115f2SLuciano Coelho if (ret < 0) { 13387b3115f2SLuciano Coelho wl1271_warning("acx ht capabilities setting failed: %d", ret); 13397b3115f2SLuciano Coelho goto out; 13407b3115f2SLuciano Coelho } 13417b3115f2SLuciano Coelho 13427b3115f2SLuciano Coelho out: 13437b3115f2SLuciano Coelho kfree(acx); 13447b3115f2SLuciano Coelho return ret; 13457b3115f2SLuciano Coelho } 1346530abe19SEliad Peller EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities); 1347530abe19SEliad Peller 13487b3115f2SLuciano Coelho 13497b3115f2SLuciano Coelho int wl1271_acx_set_ht_information(struct wl1271 *wl, 13507b3115f2SLuciano Coelho struct wl12xx_vif *wlvif, 13517b3115f2SLuciano Coelho u16 ht_operation_mode) 13527b3115f2SLuciano Coelho { 13537b3115f2SLuciano Coelho struct wl1271_acx_ht_information *acx; 13547b3115f2SLuciano Coelho int ret = 0; 13557b3115f2SLuciano Coelho 13567b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx ht information setting"); 13577b3115f2SLuciano Coelho 13587b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 13597b3115f2SLuciano Coelho if (!acx) { 13607b3115f2SLuciano Coelho ret = -ENOMEM; 13617b3115f2SLuciano Coelho goto out; 13627b3115f2SLuciano Coelho } 13637b3115f2SLuciano Coelho 13647b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 13657b3115f2SLuciano Coelho acx->ht_protection = 13667b3115f2SLuciano Coelho (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); 13677b3115f2SLuciano Coelho acx->rifs_mode = 0; 13687b3115f2SLuciano Coelho acx->gf_protection = 13697b3115f2SLuciano Coelho !!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 13707b3115f2SLuciano Coelho acx->ht_tx_burst_limit = 0; 13717b3115f2SLuciano Coelho acx->dual_cts_protection = 0; 13727b3115f2SLuciano Coelho 13737b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); 13747b3115f2SLuciano Coelho 13757b3115f2SLuciano Coelho if (ret < 0) { 13767b3115f2SLuciano Coelho wl1271_warning("acx ht information setting failed: %d", ret); 13777b3115f2SLuciano Coelho goto out; 13787b3115f2SLuciano Coelho } 13797b3115f2SLuciano Coelho 13807b3115f2SLuciano Coelho out: 13817b3115f2SLuciano Coelho kfree(acx); 13827b3115f2SLuciano Coelho return ret; 13837b3115f2SLuciano Coelho } 13847b3115f2SLuciano Coelho 13857b3115f2SLuciano Coelho /* Configure BA session initiator/receiver parameters setting in the FW. */ 13867b3115f2SLuciano Coelho int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, 13877b3115f2SLuciano Coelho struct wl12xx_vif *wlvif) 13887b3115f2SLuciano Coelho { 13897b3115f2SLuciano Coelho struct wl1271_acx_ba_initiator_policy *acx; 13907b3115f2SLuciano Coelho int ret; 13917b3115f2SLuciano Coelho 13927b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx ba initiator policy"); 13937b3115f2SLuciano Coelho 13947b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 13957b3115f2SLuciano Coelho if (!acx) { 13967b3115f2SLuciano Coelho ret = -ENOMEM; 13977b3115f2SLuciano Coelho goto out; 13987b3115f2SLuciano Coelho } 13997b3115f2SLuciano Coelho 14007b3115f2SLuciano Coelho /* set for the current role */ 14017b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 14027b3115f2SLuciano Coelho acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap; 14037b3115f2SLuciano Coelho acx->win_size = wl->conf.ht.tx_ba_win_size; 14047b3115f2SLuciano Coelho acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; 14057b3115f2SLuciano Coelho 14067b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, 14077b3115f2SLuciano Coelho ACX_BA_SESSION_INIT_POLICY, 14087b3115f2SLuciano Coelho acx, 14097b3115f2SLuciano Coelho sizeof(*acx)); 14107b3115f2SLuciano Coelho if (ret < 0) { 14117b3115f2SLuciano Coelho wl1271_warning("acx ba initiator policy failed: %d", ret); 14127b3115f2SLuciano Coelho goto out; 14137b3115f2SLuciano Coelho } 14147b3115f2SLuciano Coelho 14157b3115f2SLuciano Coelho out: 14167b3115f2SLuciano Coelho kfree(acx); 14177b3115f2SLuciano Coelho return ret; 14187b3115f2SLuciano Coelho } 14197b3115f2SLuciano Coelho 14207b3115f2SLuciano Coelho /* setup BA session receiver setting in the FW. */ 14217b3115f2SLuciano Coelho int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, 14227b3115f2SLuciano Coelho u16 ssn, bool enable, u8 peer_hlid) 14237b3115f2SLuciano Coelho { 14247b3115f2SLuciano Coelho struct wl1271_acx_ba_receiver_setup *acx; 14257b3115f2SLuciano Coelho int ret; 14267b3115f2SLuciano Coelho 14277b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); 14287b3115f2SLuciano Coelho 14297b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 14307b3115f2SLuciano Coelho if (!acx) { 14317b3115f2SLuciano Coelho ret = -ENOMEM; 14327b3115f2SLuciano Coelho goto out; 14337b3115f2SLuciano Coelho } 14347b3115f2SLuciano Coelho 14357b3115f2SLuciano Coelho acx->hlid = peer_hlid; 14367b3115f2SLuciano Coelho acx->tid = tid_index; 14377b3115f2SLuciano Coelho acx->enable = enable; 14387b3115f2SLuciano Coelho acx->win_size = wl->conf.ht.rx_ba_win_size; 14397b3115f2SLuciano Coelho acx->ssn = ssn; 14407b3115f2SLuciano Coelho 14413b44b3b3SEliad Peller ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx, 14423b44b3b3SEliad Peller sizeof(*acx), 14433b44b3b3SEliad Peller BIT(CMD_STATUS_NO_RX_BA_SESSION)); 14447b3115f2SLuciano Coelho if (ret < 0) { 14457b3115f2SLuciano Coelho wl1271_warning("acx ba receiver session failed: %d", ret); 14467b3115f2SLuciano Coelho goto out; 14477b3115f2SLuciano Coelho } 14487b3115f2SLuciano Coelho 14493b44b3b3SEliad Peller /* sometimes we can't start the session */ 14503b44b3b3SEliad Peller if (ret == CMD_STATUS_NO_RX_BA_SESSION) { 14513b44b3b3SEliad Peller wl1271_warning("no fw rx ba on tid %d", tid_index); 14523b44b3b3SEliad Peller ret = -EBUSY; 14533b44b3b3SEliad Peller goto out; 14543b44b3b3SEliad Peller } 14553b44b3b3SEliad Peller 14563b44b3b3SEliad Peller ret = 0; 14577b3115f2SLuciano Coelho out: 14587b3115f2SLuciano Coelho kfree(acx); 14597b3115f2SLuciano Coelho return ret; 14607b3115f2SLuciano Coelho } 14617b3115f2SLuciano Coelho 14627b3115f2SLuciano Coelho int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, 14637b3115f2SLuciano Coelho u64 *mactime) 14647b3115f2SLuciano Coelho { 14657b3115f2SLuciano Coelho struct wl12xx_acx_fw_tsf_information *tsf_info; 14667b3115f2SLuciano Coelho int ret; 14677b3115f2SLuciano Coelho 14687b3115f2SLuciano Coelho tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); 14697b3115f2SLuciano Coelho if (!tsf_info) { 14707b3115f2SLuciano Coelho ret = -ENOMEM; 14717b3115f2SLuciano Coelho goto out; 14727b3115f2SLuciano Coelho } 14737b3115f2SLuciano Coelho 14747b3115f2SLuciano Coelho tsf_info->role_id = wlvif->role_id; 14757b3115f2SLuciano Coelho 14764b674144SIgal Chernobelsky ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, tsf_info, 14774b674144SIgal Chernobelsky sizeof(struct acx_header), sizeof(*tsf_info)); 14787b3115f2SLuciano Coelho if (ret < 0) { 14797b3115f2SLuciano Coelho wl1271_warning("acx tsf info interrogate failed"); 14807b3115f2SLuciano Coelho goto out; 14817b3115f2SLuciano Coelho } 14827b3115f2SLuciano Coelho 14837b3115f2SLuciano Coelho *mactime = le32_to_cpu(tsf_info->current_tsf_low) | 14847b3115f2SLuciano Coelho ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32); 14857b3115f2SLuciano Coelho 14867b3115f2SLuciano Coelho out: 14877b3115f2SLuciano Coelho kfree(tsf_info); 14887b3115f2SLuciano Coelho return ret; 14897b3115f2SLuciano Coelho } 14907b3115f2SLuciano Coelho 14917b3115f2SLuciano Coelho int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, 14927b3115f2SLuciano Coelho bool enable) 14937b3115f2SLuciano Coelho { 14947b3115f2SLuciano Coelho struct wl1271_acx_ps_rx_streaming *rx_streaming; 14957b3115f2SLuciano Coelho u32 conf_queues, enable_queues; 14967b3115f2SLuciano Coelho int i, ret = 0; 14977b3115f2SLuciano Coelho 14987b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx ps rx streaming"); 14997b3115f2SLuciano Coelho 15007b3115f2SLuciano Coelho rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL); 15017b3115f2SLuciano Coelho if (!rx_streaming) { 15027b3115f2SLuciano Coelho ret = -ENOMEM; 15037b3115f2SLuciano Coelho goto out; 15047b3115f2SLuciano Coelho } 15057b3115f2SLuciano Coelho 15067b3115f2SLuciano Coelho conf_queues = wl->conf.rx_streaming.queues; 15077b3115f2SLuciano Coelho if (enable) 15087b3115f2SLuciano Coelho enable_queues = conf_queues; 15097b3115f2SLuciano Coelho else 15107b3115f2SLuciano Coelho enable_queues = 0; 15117b3115f2SLuciano Coelho 15127b3115f2SLuciano Coelho for (i = 0; i < 8; i++) { 15137b3115f2SLuciano Coelho /* 15147b3115f2SLuciano Coelho * Skip non-changed queues, to avoid redundant acxs. 15157b3115f2SLuciano Coelho * this check assumes conf.rx_streaming.queues can't 15167b3115f2SLuciano Coelho * be changed while rx_streaming is enabled. 15177b3115f2SLuciano Coelho */ 15187b3115f2SLuciano Coelho if (!(conf_queues & BIT(i))) 15197b3115f2SLuciano Coelho continue; 15207b3115f2SLuciano Coelho 15217b3115f2SLuciano Coelho rx_streaming->role_id = wlvif->role_id; 15227b3115f2SLuciano Coelho rx_streaming->tid = i; 15237b3115f2SLuciano Coelho rx_streaming->enable = enable_queues & BIT(i); 15247b3115f2SLuciano Coelho rx_streaming->period = wl->conf.rx_streaming.interval; 15257b3115f2SLuciano Coelho rx_streaming->timeout = wl->conf.rx_streaming.interval; 15267b3115f2SLuciano Coelho 15277b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING, 15287b3115f2SLuciano Coelho rx_streaming, 15297b3115f2SLuciano Coelho sizeof(*rx_streaming)); 15307b3115f2SLuciano Coelho if (ret < 0) { 15317b3115f2SLuciano Coelho wl1271_warning("acx ps rx streaming failed: %d", ret); 15327b3115f2SLuciano Coelho goto out; 15337b3115f2SLuciano Coelho } 15347b3115f2SLuciano Coelho } 15357b3115f2SLuciano Coelho out: 15367b3115f2SLuciano Coelho kfree(rx_streaming); 15377b3115f2SLuciano Coelho return ret; 15387b3115f2SLuciano Coelho } 15397b3115f2SLuciano Coelho 15407b3115f2SLuciano Coelho int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif) 15417b3115f2SLuciano Coelho { 15427b3115f2SLuciano Coelho struct wl1271_acx_ap_max_tx_retry *acx = NULL; 15437b3115f2SLuciano Coelho int ret; 15447b3115f2SLuciano Coelho 15457b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); 15467b3115f2SLuciano Coelho 15477b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 15487b3115f2SLuciano Coelho if (!acx) 15497b3115f2SLuciano Coelho return -ENOMEM; 15507b3115f2SLuciano Coelho 15517b3115f2SLuciano Coelho acx->role_id = wlvif->role_id; 15527b3115f2SLuciano Coelho acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); 15537b3115f2SLuciano Coelho 15547b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); 15557b3115f2SLuciano Coelho if (ret < 0) { 15567b3115f2SLuciano Coelho wl1271_warning("acx ap max tx retry failed: %d", ret); 15577b3115f2SLuciano Coelho goto out; 15587b3115f2SLuciano Coelho } 15597b3115f2SLuciano Coelho 15607b3115f2SLuciano Coelho out: 15617b3115f2SLuciano Coelho kfree(acx); 15627b3115f2SLuciano Coelho return ret; 15637b3115f2SLuciano Coelho } 15647b3115f2SLuciano Coelho 15657b3115f2SLuciano Coelho int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif) 15667b3115f2SLuciano Coelho { 15677b3115f2SLuciano Coelho struct wl1271_acx_config_ps *config_ps; 15687b3115f2SLuciano Coelho int ret; 15697b3115f2SLuciano Coelho 15707b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx config ps"); 15717b3115f2SLuciano Coelho 15727b3115f2SLuciano Coelho config_ps = kzalloc(sizeof(*config_ps), GFP_KERNEL); 15737b3115f2SLuciano Coelho if (!config_ps) { 15747b3115f2SLuciano Coelho ret = -ENOMEM; 15757b3115f2SLuciano Coelho goto out; 15767b3115f2SLuciano Coelho } 15777b3115f2SLuciano Coelho 15787b3115f2SLuciano Coelho config_ps->exit_retries = wl->conf.conn.psm_exit_retries; 15797b3115f2SLuciano Coelho config_ps->enter_retries = wl->conf.conn.psm_entry_retries; 15807b3115f2SLuciano Coelho config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate); 15817b3115f2SLuciano Coelho 15827b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps, 15837b3115f2SLuciano Coelho sizeof(*config_ps)); 15847b3115f2SLuciano Coelho 15857b3115f2SLuciano Coelho if (ret < 0) { 15867b3115f2SLuciano Coelho wl1271_warning("acx config ps failed: %d", ret); 15877b3115f2SLuciano Coelho goto out; 15887b3115f2SLuciano Coelho } 15897b3115f2SLuciano Coelho 15907b3115f2SLuciano Coelho out: 15917b3115f2SLuciano Coelho kfree(config_ps); 15927b3115f2SLuciano Coelho return ret; 15937b3115f2SLuciano Coelho } 15947b3115f2SLuciano Coelho 1595028e7243SEliad Peller int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, 1596028e7243SEliad Peller struct wl12xx_vif *wlvif, u8 *addr) 15977b3115f2SLuciano Coelho { 15987b3115f2SLuciano Coelho struct wl1271_acx_inconnection_sta *acx = NULL; 15997b3115f2SLuciano Coelho int ret; 16007b3115f2SLuciano Coelho 16017b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr); 16027b3115f2SLuciano Coelho 16037b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 16047b3115f2SLuciano Coelho if (!acx) 16057b3115f2SLuciano Coelho return -ENOMEM; 16067b3115f2SLuciano Coelho 16077b3115f2SLuciano Coelho memcpy(acx->addr, addr, ETH_ALEN); 1608028e7243SEliad Peller acx->role_id = wlvif->role_id; 16097b3115f2SLuciano Coelho 16107b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST, 16117b3115f2SLuciano Coelho acx, sizeof(*acx)); 16127b3115f2SLuciano Coelho if (ret < 0) { 16137b3115f2SLuciano Coelho wl1271_warning("acx set inconnaction sta failed: %d", ret); 16147b3115f2SLuciano Coelho goto out; 16157b3115f2SLuciano Coelho } 16167b3115f2SLuciano Coelho 16177b3115f2SLuciano Coelho out: 16187b3115f2SLuciano Coelho kfree(acx); 16197b3115f2SLuciano Coelho return ret; 16207b3115f2SLuciano Coelho } 16217b3115f2SLuciano Coelho 16227b3115f2SLuciano Coelho int wl1271_acx_fm_coex(struct wl1271 *wl) 16237b3115f2SLuciano Coelho { 16247b3115f2SLuciano Coelho struct wl1271_acx_fm_coex *acx; 16257b3115f2SLuciano Coelho int ret; 16267b3115f2SLuciano Coelho 16277b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx fm coex setting"); 16287b3115f2SLuciano Coelho 16297b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 16307b3115f2SLuciano Coelho if (!acx) { 16317b3115f2SLuciano Coelho ret = -ENOMEM; 16327b3115f2SLuciano Coelho goto out; 16337b3115f2SLuciano Coelho } 16347b3115f2SLuciano Coelho 16357b3115f2SLuciano Coelho acx->enable = wl->conf.fm_coex.enable; 16367b3115f2SLuciano Coelho acx->swallow_period = wl->conf.fm_coex.swallow_period; 16377b3115f2SLuciano Coelho acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1; 16387b3115f2SLuciano Coelho acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2; 16397b3115f2SLuciano Coelho acx->m_divider_fref_set_1 = 16407b3115f2SLuciano Coelho cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1); 16417b3115f2SLuciano Coelho acx->m_divider_fref_set_2 = 16427b3115f2SLuciano Coelho cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2); 16437b3115f2SLuciano Coelho acx->coex_pll_stabilization_time = 16447b3115f2SLuciano Coelho cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time); 16457b3115f2SLuciano Coelho acx->ldo_stabilization_time = 16467b3115f2SLuciano Coelho cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time); 16477b3115f2SLuciano Coelho acx->fm_disturbed_band_margin = 16487b3115f2SLuciano Coelho wl->conf.fm_coex.fm_disturbed_band_margin; 16497b3115f2SLuciano Coelho acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff; 16507b3115f2SLuciano Coelho 16517b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx)); 16527b3115f2SLuciano Coelho if (ret < 0) { 16537b3115f2SLuciano Coelho wl1271_warning("acx fm coex setting failed: %d", ret); 16547b3115f2SLuciano Coelho goto out; 16557b3115f2SLuciano Coelho } 16567b3115f2SLuciano Coelho 16577b3115f2SLuciano Coelho out: 16587b3115f2SLuciano Coelho kfree(acx); 16597b3115f2SLuciano Coelho return ret; 16607b3115f2SLuciano Coelho } 16617b3115f2SLuciano Coelho 16627b3115f2SLuciano Coelho int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl) 16637b3115f2SLuciano Coelho { 16647b3115f2SLuciano Coelho struct wl12xx_acx_set_rate_mgmt_params *acx = NULL; 16657b3115f2SLuciano Coelho struct conf_rate_policy_settings *conf = &wl->conf.rate; 16667b3115f2SLuciano Coelho int ret; 16677b3115f2SLuciano Coelho 16687b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx set rate mgmt params"); 16697b3115f2SLuciano Coelho 16707b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 16717b3115f2SLuciano Coelho if (!acx) 16727b3115f2SLuciano Coelho return -ENOMEM; 16737b3115f2SLuciano Coelho 16747b3115f2SLuciano Coelho acx->index = ACX_RATE_MGMT_ALL_PARAMS; 16757b3115f2SLuciano Coelho acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score); 16767b3115f2SLuciano Coelho acx->per_add = cpu_to_le16(conf->per_add); 16777b3115f2SLuciano Coelho acx->per_th1 = cpu_to_le16(conf->per_th1); 16787b3115f2SLuciano Coelho acx->per_th2 = cpu_to_le16(conf->per_th2); 16797b3115f2SLuciano Coelho acx->max_per = cpu_to_le16(conf->max_per); 16807b3115f2SLuciano Coelho acx->inverse_curiosity_factor = conf->inverse_curiosity_factor; 16817b3115f2SLuciano Coelho acx->tx_fail_low_th = conf->tx_fail_low_th; 16827b3115f2SLuciano Coelho acx->tx_fail_high_th = conf->tx_fail_high_th; 16837b3115f2SLuciano Coelho acx->per_alpha_shift = conf->per_alpha_shift; 16847b3115f2SLuciano Coelho acx->per_add_shift = conf->per_add_shift; 16857b3115f2SLuciano Coelho acx->per_beta1_shift = conf->per_beta1_shift; 16867b3115f2SLuciano Coelho acx->per_beta2_shift = conf->per_beta2_shift; 16877b3115f2SLuciano Coelho acx->rate_check_up = conf->rate_check_up; 16887b3115f2SLuciano Coelho acx->rate_check_down = conf->rate_check_down; 16897b3115f2SLuciano Coelho memcpy(acx->rate_retry_policy, conf->rate_retry_policy, 16907b3115f2SLuciano Coelho sizeof(acx->rate_retry_policy)); 16917b3115f2SLuciano Coelho 16927b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MGMT_PARAMS, 16937b3115f2SLuciano Coelho acx, sizeof(*acx)); 16947b3115f2SLuciano Coelho if (ret < 0) { 16957b3115f2SLuciano Coelho wl1271_warning("acx set rate mgmt params failed: %d", ret); 16967b3115f2SLuciano Coelho goto out; 16977b3115f2SLuciano Coelho } 16987b3115f2SLuciano Coelho 16997b3115f2SLuciano Coelho out: 17007b3115f2SLuciano Coelho kfree(acx); 17017b3115f2SLuciano Coelho return ret; 17027b3115f2SLuciano Coelho } 17037b3115f2SLuciano Coelho 17047b3115f2SLuciano Coelho int wl12xx_acx_config_hangover(struct wl1271 *wl) 17057b3115f2SLuciano Coelho { 17067b3115f2SLuciano Coelho struct wl12xx_acx_config_hangover *acx; 17077b3115f2SLuciano Coelho struct conf_hangover_settings *conf = &wl->conf.hangover; 17087b3115f2SLuciano Coelho int ret; 17097b3115f2SLuciano Coelho 17107b3115f2SLuciano Coelho wl1271_debug(DEBUG_ACX, "acx config hangover"); 17117b3115f2SLuciano Coelho 17127b3115f2SLuciano Coelho acx = kzalloc(sizeof(*acx), GFP_KERNEL); 17137b3115f2SLuciano Coelho if (!acx) { 17147b3115f2SLuciano Coelho ret = -ENOMEM; 17157b3115f2SLuciano Coelho goto out; 17167b3115f2SLuciano Coelho } 17177b3115f2SLuciano Coelho 17187b3115f2SLuciano Coelho acx->recover_time = cpu_to_le32(conf->recover_time); 17197b3115f2SLuciano Coelho acx->hangover_period = conf->hangover_period; 17207b3115f2SLuciano Coelho acx->dynamic_mode = conf->dynamic_mode; 17217b3115f2SLuciano Coelho acx->early_termination_mode = conf->early_termination_mode; 17227b3115f2SLuciano Coelho acx->max_period = conf->max_period; 17237b3115f2SLuciano Coelho acx->min_period = conf->min_period; 17247b3115f2SLuciano Coelho acx->increase_delta = conf->increase_delta; 17257b3115f2SLuciano Coelho acx->decrease_delta = conf->decrease_delta; 17267b3115f2SLuciano Coelho acx->quiet_time = conf->quiet_time; 17277b3115f2SLuciano Coelho acx->increase_time = conf->increase_time; 172896dae591SGiel van Schijndel acx->window_size = conf->window_size; 17297b3115f2SLuciano Coelho 17307b3115f2SLuciano Coelho ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, 17317b3115f2SLuciano Coelho sizeof(*acx)); 17327b3115f2SLuciano Coelho 17337b3115f2SLuciano Coelho if (ret < 0) { 17347b3115f2SLuciano Coelho wl1271_warning("acx config hangover failed: %d", ret); 17357b3115f2SLuciano Coelho goto out; 17367b3115f2SLuciano Coelho } 17377b3115f2SLuciano Coelho 17387b3115f2SLuciano Coelho out: 17397b3115f2SLuciano Coelho kfree(acx); 17407b3115f2SLuciano Coelho return ret; 17417b3115f2SLuciano Coelho 17427b3115f2SLuciano Coelho } 1743c21eebb5SEyal Shapira 17440a9ffac0SNadim Zubidat int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif, 17450a9ffac0SNadim Zubidat s8 *avg_rssi) 17460a9ffac0SNadim Zubidat { 17470a9ffac0SNadim Zubidat struct acx_roaming_stats *acx; 17480a9ffac0SNadim Zubidat int ret = 0; 17490a9ffac0SNadim Zubidat 17500a9ffac0SNadim Zubidat wl1271_debug(DEBUG_ACX, "acx roaming statistics"); 17510a9ffac0SNadim Zubidat 17520a9ffac0SNadim Zubidat acx = kzalloc(sizeof(*acx), GFP_KERNEL); 17530a9ffac0SNadim Zubidat if (!acx) { 17540a9ffac0SNadim Zubidat ret = -ENOMEM; 17550a9ffac0SNadim Zubidat goto out; 17560a9ffac0SNadim Zubidat } 17570a9ffac0SNadim Zubidat 17580a9ffac0SNadim Zubidat acx->role_id = wlvif->role_id; 17590a9ffac0SNadim Zubidat ret = wl1271_cmd_interrogate(wl, ACX_ROAMING_STATISTICS_TBL, 17604b674144SIgal Chernobelsky acx, sizeof(*acx), sizeof(*acx)); 17610a9ffac0SNadim Zubidat if (ret < 0) { 17620a9ffac0SNadim Zubidat wl1271_warning("acx roaming statistics failed: %d", ret); 17630a9ffac0SNadim Zubidat ret = -ENOMEM; 17640a9ffac0SNadim Zubidat goto out; 17650a9ffac0SNadim Zubidat } 17660a9ffac0SNadim Zubidat 17670a9ffac0SNadim Zubidat *avg_rssi = acx->rssi_beacon; 17680a9ffac0SNadim Zubidat out: 17690a9ffac0SNadim Zubidat kfree(acx); 17700a9ffac0SNadim Zubidat return ret; 17710a9ffac0SNadim Zubidat } 17720a9ffac0SNadim Zubidat 17734161923aSEyal Shapira #ifdef CONFIG_PM 1774c21eebb5SEyal Shapira /* Set the global behaviour of RX filters - On/Off + default action */ 1775c21eebb5SEyal Shapira int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, 1776c21eebb5SEyal Shapira enum rx_filter_action action) 1777c21eebb5SEyal Shapira { 1778c21eebb5SEyal Shapira struct acx_default_rx_filter *acx; 1779c21eebb5SEyal Shapira int ret; 1780c21eebb5SEyal Shapira 1781c21eebb5SEyal Shapira wl1271_debug(DEBUG_ACX, "acx default rx filter en: %d act: %d", 1782c21eebb5SEyal Shapira enable, action); 1783c21eebb5SEyal Shapira 1784c21eebb5SEyal Shapira acx = kzalloc(sizeof(*acx), GFP_KERNEL); 1785c21eebb5SEyal Shapira if (!acx) 1786c21eebb5SEyal Shapira return -ENOMEM; 1787c21eebb5SEyal Shapira 1788c21eebb5SEyal Shapira acx->enable = enable; 1789c21eebb5SEyal Shapira acx->default_action = action; 1790c21eebb5SEyal Shapira 1791c21eebb5SEyal Shapira ret = wl1271_cmd_configure(wl, ACX_ENABLE_RX_DATA_FILTER, acx, 1792c21eebb5SEyal Shapira sizeof(*acx)); 1793c21eebb5SEyal Shapira if (ret < 0) { 1794c21eebb5SEyal Shapira wl1271_warning("acx default rx filter enable failed: %d", ret); 1795c21eebb5SEyal Shapira goto out; 1796c21eebb5SEyal Shapira } 1797c21eebb5SEyal Shapira 1798c21eebb5SEyal Shapira out: 1799c21eebb5SEyal Shapira kfree(acx); 1800c21eebb5SEyal Shapira return ret; 1801c21eebb5SEyal Shapira } 1802c21eebb5SEyal Shapira 1803c21eebb5SEyal Shapira /* Configure or disable a specific RX filter pattern */ 1804c21eebb5SEyal Shapira int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable, 1805c21eebb5SEyal Shapira struct wl12xx_rx_filter *filter) 1806c21eebb5SEyal Shapira { 1807c21eebb5SEyal Shapira struct acx_rx_filter_cfg *acx; 1808c21eebb5SEyal Shapira int fields_size = 0; 1809c21eebb5SEyal Shapira int acx_size; 1810c21eebb5SEyal Shapira int ret; 1811c21eebb5SEyal Shapira 1812c21eebb5SEyal Shapira WARN_ON(enable && !filter); 1813c21eebb5SEyal Shapira WARN_ON(index >= WL1271_MAX_RX_FILTERS); 1814c21eebb5SEyal Shapira 18153246a7fbSLuciano Coelho wl1271_debug(DEBUG_ACX, 18163246a7fbSLuciano Coelho "acx set rx filter idx: %d enable: %d filter: %p", 18173246a7fbSLuciano Coelho index, enable, filter); 1818c21eebb5SEyal Shapira 1819c21eebb5SEyal Shapira if (enable) { 1820c21eebb5SEyal Shapira fields_size = wl1271_rx_filter_get_fields_size(filter); 1821c21eebb5SEyal Shapira 1822c21eebb5SEyal Shapira wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d", 1823c21eebb5SEyal Shapira filter->action, filter->num_fields, fields_size); 1824c21eebb5SEyal Shapira } 1825c21eebb5SEyal Shapira 1826c21eebb5SEyal Shapira acx_size = ALIGN(sizeof(*acx) + fields_size, 4); 1827c21eebb5SEyal Shapira acx = kzalloc(acx_size, GFP_KERNEL); 1828c21eebb5SEyal Shapira 1829c21eebb5SEyal Shapira if (!acx) 1830c21eebb5SEyal Shapira return -ENOMEM; 1831c21eebb5SEyal Shapira 1832c21eebb5SEyal Shapira acx->enable = enable; 1833c21eebb5SEyal Shapira acx->index = index; 1834c21eebb5SEyal Shapira 1835c21eebb5SEyal Shapira if (enable) { 1836c21eebb5SEyal Shapira acx->num_fields = filter->num_fields; 1837c21eebb5SEyal Shapira acx->action = filter->action; 1838c21eebb5SEyal Shapira wl1271_rx_filter_flatten_fields(filter, acx->fields); 1839c21eebb5SEyal Shapira } 1840c21eebb5SEyal Shapira 1841c21eebb5SEyal Shapira wl1271_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size); 1842c21eebb5SEyal Shapira 1843c21eebb5SEyal Shapira ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx, acx_size); 1844c21eebb5SEyal Shapira if (ret < 0) { 1845c21eebb5SEyal Shapira wl1271_warning("setting rx filter failed: %d", ret); 1846c21eebb5SEyal Shapira goto out; 1847c21eebb5SEyal Shapira } 1848c21eebb5SEyal Shapira 1849c21eebb5SEyal Shapira out: 1850c21eebb5SEyal Shapira kfree(acx); 1851c21eebb5SEyal Shapira return ret; 1852c21eebb5SEyal Shapira } 18534161923aSEyal Shapira #endif /* CONFIG_PM */ 1854