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