1 /* 2 * This file is part of wl18xx 3 * 4 * Copyright (C) 2011 Texas Instruments Inc. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * version 2 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 * 02110-1301 USA 19 * 20 */ 21 22 #include "../wlcore/cmd.h" 23 #include "../wlcore/debug.h" 24 #include "../wlcore/acx.h" 25 26 #include "acx.h" 27 #include "wl18xx.h" 28 29 int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, 30 u32 sdio_blk_size, u32 extra_mem_blks, 31 u32 len_field_size) 32 { 33 struct wl18xx_acx_host_config_bitmap *bitmap_conf; 34 int ret; 35 36 wl1271_debug(DEBUG_ACX, "acx cfg bitmap %d blk %d spare %d field %d", 37 host_cfg_bitmap, sdio_blk_size, extra_mem_blks, 38 len_field_size); 39 40 bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL); 41 if (!bitmap_conf) { 42 ret = -ENOMEM; 43 goto out; 44 } 45 46 bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap); 47 bitmap_conf->host_sdio_block_size = cpu_to_le32(sdio_blk_size); 48 bitmap_conf->extra_mem_blocks = cpu_to_le32(extra_mem_blks); 49 bitmap_conf->length_field_size = cpu_to_le32(len_field_size); 50 51 ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP, 52 bitmap_conf, sizeof(*bitmap_conf)); 53 if (ret < 0) { 54 wl1271_warning("wl1271 bitmap config opt failed: %d", ret); 55 goto out; 56 } 57 58 out: 59 kfree(bitmap_conf); 60 61 return ret; 62 } 63 64 int wl18xx_acx_set_checksum_state(struct wl1271 *wl) 65 { 66 struct wl18xx_acx_checksum_state *acx; 67 int ret; 68 69 wl1271_debug(DEBUG_ACX, "acx checksum state"); 70 71 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 72 if (!acx) { 73 ret = -ENOMEM; 74 goto out; 75 } 76 77 acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED; 78 79 ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx)); 80 if (ret < 0) { 81 wl1271_warning("failed to set Tx checksum state: %d", ret); 82 goto out; 83 } 84 85 out: 86 kfree(acx); 87 return ret; 88 } 89 90 int wl18xx_acx_clear_statistics(struct wl1271 *wl) 91 { 92 struct wl18xx_acx_clear_statistics *acx; 93 int ret = 0; 94 95 wl1271_debug(DEBUG_ACX, "acx clear statistics"); 96 97 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 98 if (!acx) { 99 ret = -ENOMEM; 100 goto out; 101 } 102 103 ret = wl1271_cmd_configure(wl, ACX_CLEAR_STATISTICS, acx, sizeof(*acx)); 104 if (ret < 0) { 105 wl1271_warning("failed to clear firmware statistics: %d", ret); 106 goto out; 107 } 108 109 out: 110 kfree(acx); 111 return ret; 112 } 113 114 int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide) 115 { 116 struct wlcore_peer_ht_operation_mode *acx; 117 int ret; 118 119 wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d", 120 hlid, wide); 121 122 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 123 if (!acx) { 124 ret = -ENOMEM; 125 goto out; 126 } 127 128 acx->hlid = hlid; 129 acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ; 130 131 ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx, 132 sizeof(*acx)); 133 134 if (ret < 0) { 135 wl1271_warning("acx peer ht operation mode failed: %d", ret); 136 goto out; 137 } 138 139 out: 140 kfree(acx); 141 return ret; 142 143 } 144 145 /* 146 * this command is basically the same as wl1271_acx_ht_capabilities, 147 * with the addition of supported rates. they should be unified in 148 * the next fw api change 149 */ 150 int wl18xx_acx_set_peer_cap(struct wl1271 *wl, 151 struct ieee80211_sta_ht_cap *ht_cap, 152 bool allow_ht_operation, 153 u32 rate_set, u8 hlid) 154 { 155 struct wlcore_acx_peer_cap *acx; 156 int ret = 0; 157 u32 ht_capabilites = 0; 158 159 wl1271_debug(DEBUG_ACX, 160 "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x", 161 ht_cap->ht_supported, ht_cap->cap, rate_set); 162 163 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 164 if (!acx) { 165 ret = -ENOMEM; 166 goto out; 167 } 168 169 if (allow_ht_operation && ht_cap->ht_supported) { 170 /* no need to translate capabilities - use the spec values */ 171 ht_capabilites = ht_cap->cap; 172 173 /* 174 * this bit is not employed by the spec but only by FW to 175 * indicate peer HT support 176 */ 177 ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; 178 179 /* get data from A-MPDU parameters field */ 180 acx->ampdu_max_length = ht_cap->ampdu_factor; 181 acx->ampdu_min_spacing = ht_cap->ampdu_density; 182 } 183 184 acx->hlid = hlid; 185 acx->ht_capabilites = cpu_to_le32(ht_capabilites); 186 acx->supported_rates = cpu_to_le32(rate_set); 187 188 ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx)); 189 if (ret < 0) { 190 wl1271_warning("acx ht capabilities setting failed: %d", ret); 191 goto out; 192 } 193 194 out: 195 kfree(acx); 196 return ret; 197 } 198 199 /* 200 * When the host is suspended, we don't want to get any fast-link/PSM 201 * notifications 202 */ 203 int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, 204 bool action) 205 { 206 struct wl18xx_acx_interrupt_notify *acx; 207 int ret = 0; 208 209 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 210 if (!acx) { 211 ret = -ENOMEM; 212 goto out; 213 } 214 215 acx->enable = action; 216 ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx)); 217 if (ret < 0) { 218 wl1271_warning("acx interrupt notify setting failed: %d", ret); 219 goto out; 220 } 221 222 out: 223 kfree(acx); 224 return ret; 225 } 226 227 /* 228 * When the host is suspended, we can configure the FW to disable RX BA 229 * notifications. 230 */ 231 int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action) 232 { 233 struct wl18xx_acx_rx_ba_filter *acx; 234 int ret = 0; 235 236 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 237 if (!acx) { 238 ret = -ENOMEM; 239 goto out; 240 } 241 242 acx->enable = (u32)action; 243 ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx)); 244 if (ret < 0) { 245 wl1271_warning("acx rx ba activity filter setting failed: %d", 246 ret); 247 goto out; 248 } 249 250 out: 251 kfree(acx); 252 return ret; 253 } 254 255 int wl18xx_acx_ap_sleep(struct wl1271 *wl) 256 { 257 struct wl18xx_priv *priv = wl->priv; 258 struct acx_ap_sleep_cfg *acx; 259 struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep; 260 int ret; 261 262 wl1271_debug(DEBUG_ACX, "acx config ap sleep"); 263 264 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 265 if (!acx) { 266 ret = -ENOMEM; 267 goto out; 268 } 269 270 acx->idle_duty_cycle = conf->idle_duty_cycle; 271 acx->connected_duty_cycle = conf->connected_duty_cycle; 272 acx->max_stations_thresh = conf->max_stations_thresh; 273 acx->idle_conn_thresh = conf->idle_conn_thresh; 274 275 ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx)); 276 if (ret < 0) { 277 wl1271_warning("acx config ap-sleep failed: %d", ret); 278 goto out; 279 } 280 281 out: 282 kfree(acx); 283 return ret; 284 } 285 286 int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl) 287 { 288 struct acx_dynamic_fw_traces_cfg *acx; 289 int ret; 290 291 wl1271_debug(DEBUG_ACX, "acx dynamic fw traces config %d", 292 wl->dynamic_fw_traces); 293 294 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 295 if (!acx) { 296 ret = -ENOMEM; 297 goto out; 298 } 299 300 acx->dynamic_fw_traces = cpu_to_le32(wl->dynamic_fw_traces); 301 302 ret = wl1271_cmd_configure(wl, ACX_DYNAMIC_TRACES_CFG, 303 acx, sizeof(*acx)); 304 if (ret < 0) { 305 wl1271_warning("acx config dynamic fw traces failed: %d", ret); 306 goto out; 307 } 308 out: 309 kfree(acx); 310 return ret; 311 } 312 313 int wl18xx_acx_time_sync_cfg(struct wl1271 *wl) 314 { 315 struct acx_time_sync_cfg *acx; 316 int ret; 317 318 wl1271_debug(DEBUG_ACX, "acx time sync cfg: mode %d, addr: %pM", 319 wl->conf.sg.params[WL18XX_CONF_SG_TIME_SYNC], 320 wl->zone_master_mac_addr); 321 322 acx = kzalloc(sizeof(*acx), GFP_KERNEL); 323 if (!acx) { 324 ret = -ENOMEM; 325 goto out; 326 } 327 328 acx->sync_mode = wl->conf.sg.params[WL18XX_CONF_SG_TIME_SYNC]; 329 memcpy(acx->zone_mac_addr, wl->zone_master_mac_addr, ETH_ALEN); 330 331 ret = wl1271_cmd_configure(wl, ACX_TIME_SYNC_CFG, 332 acx, sizeof(*acx)); 333 if (ret < 0) { 334 wl1271_warning("acx time sync cfg failed: %d", ret); 335 goto out; 336 } 337 out: 338 kfree(acx); 339 return ret; 340 } 341