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