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