| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 1 | /* | 
|  | 2 | * This file is part of wl1271 | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2008-2009 Nokia Corporation | 
|  | 5 | * | 
|  | 6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | 
|  | 7 | * | 
|  | 8 | * This program is free software; you can redistribute it and/or | 
|  | 9 | * modify it under the terms of the GNU General Public License | 
|  | 10 | * version 2 as published by the Free Software Foundation. | 
|  | 11 | * | 
|  | 12 | * This program is distributed in the hope that it will be useful, but | 
|  | 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 15 | * General Public License for more details. | 
|  | 16 | * | 
|  | 17 | * You should have received a copy of the GNU General Public License | 
|  | 18 | * along with this program; if not, write to the Free Software | 
|  | 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 
|  | 20 | * 02110-1301 USA | 
|  | 21 | * | 
|  | 22 | */ | 
|  | 23 |  | 
| Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 24 | #include "acx.h" | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 25 |  | 
|  | 26 | #include <linux/module.h> | 
|  | 27 | #include <linux/platform_device.h> | 
|  | 28 | #include <linux/crc7.h> | 
|  | 29 | #include <linux/spi/spi.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 30 | #include <linux/slab.h> | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 31 |  | 
| Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 32 | #include "wl12xx.h" | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 33 | #include "wl12xx_80211.h" | 
| Shahar Levi | 00d2010 | 2010-11-08 11:20:10 +0000 | [diff] [blame] | 34 | #include "reg.h" | 
|  | 35 | #include "ps.h" | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 36 |  | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 37 | int wl1271_acx_wake_up_conditions(struct wl1271 *wl) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 38 | { | 
|  | 39 | struct acx_wake_up_condition *wake_up; | 
|  | 40 | int ret; | 
|  | 41 |  | 
|  | 42 | wl1271_debug(DEBUG_ACX, "acx wake up conditions"); | 
|  | 43 |  | 
|  | 44 | wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); | 
|  | 45 | if (!wake_up) { | 
|  | 46 | ret = -ENOMEM; | 
|  | 47 | goto out; | 
|  | 48 | } | 
|  | 49 |  | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 50 | wake_up->wake_up_event = wl->conf.conn.wake_up_event; | 
|  | 51 | wake_up->listen_interval = wl->conf.conn.listen_interval; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 52 |  | 
|  | 53 | ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, | 
|  | 54 | wake_up, sizeof(*wake_up)); | 
|  | 55 | if (ret < 0) { | 
|  | 56 | wl1271_warning("could not set wake up conditions: %d", ret); | 
|  | 57 | goto out; | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | out: | 
|  | 61 | kfree(wake_up); | 
|  | 62 | return ret; | 
|  | 63 | } | 
|  | 64 |  | 
|  | 65 | int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) | 
|  | 66 | { | 
|  | 67 | struct acx_sleep_auth *auth; | 
|  | 68 | int ret; | 
|  | 69 |  | 
|  | 70 | wl1271_debug(DEBUG_ACX, "acx sleep auth"); | 
|  | 71 |  | 
|  | 72 | auth = kzalloc(sizeof(*auth), GFP_KERNEL); | 
|  | 73 | if (!auth) { | 
|  | 74 | ret = -ENOMEM; | 
|  | 75 | goto out; | 
|  | 76 | } | 
|  | 77 |  | 
|  | 78 | auth->sleep_auth = sleep_auth; | 
|  | 79 |  | 
|  | 80 | ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); | 
|  | 81 | if (ret < 0) | 
|  | 82 | return ret; | 
|  | 83 |  | 
|  | 84 | out: | 
|  | 85 | kfree(auth); | 
|  | 86 | return ret; | 
|  | 87 | } | 
|  | 88 |  | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 89 | int wl1271_acx_tx_power(struct wl1271 *wl, int power) | 
|  | 90 | { | 
|  | 91 | struct acx_current_tx_power *acx; | 
|  | 92 | int ret; | 
|  | 93 |  | 
|  | 94 | wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); | 
|  | 95 |  | 
|  | 96 | if (power < 0 || power > 25) | 
|  | 97 | return -EINVAL; | 
|  | 98 |  | 
|  | 99 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 100 | if (!acx) { | 
|  | 101 | ret = -ENOMEM; | 
|  | 102 | goto out; | 
|  | 103 | } | 
|  | 104 |  | 
| Juuso Oikarinen | 6f6b5d4 | 2010-02-22 08:38:42 +0200 | [diff] [blame] | 105 | acx->current_tx_power = power * 10; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 106 |  | 
|  | 107 | ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); | 
|  | 108 | if (ret < 0) { | 
|  | 109 | wl1271_warning("configure of tx power failed: %d", ret); | 
|  | 110 | goto out; | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | out: | 
|  | 114 | kfree(acx); | 
|  | 115 | return ret; | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 | int wl1271_acx_feature_cfg(struct wl1271 *wl) | 
|  | 119 | { | 
|  | 120 | struct acx_feature_config *feature; | 
|  | 121 | int ret; | 
|  | 122 |  | 
|  | 123 | wl1271_debug(DEBUG_ACX, "acx feature cfg"); | 
|  | 124 |  | 
|  | 125 | feature = kzalloc(sizeof(*feature), GFP_KERNEL); | 
|  | 126 | if (!feature) { | 
|  | 127 | ret = -ENOMEM; | 
|  | 128 | goto out; | 
|  | 129 | } | 
|  | 130 |  | 
|  | 131 | /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ | 
|  | 132 | feature->data_flow_options = 0; | 
|  | 133 | feature->options = 0; | 
|  | 134 |  | 
|  | 135 | ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, | 
|  | 136 | feature, sizeof(*feature)); | 
|  | 137 | if (ret < 0) { | 
|  | 138 | wl1271_error("Couldnt set HW encryption"); | 
|  | 139 | goto out; | 
|  | 140 | } | 
|  | 141 |  | 
|  | 142 | out: | 
|  | 143 | kfree(feature); | 
|  | 144 | return ret; | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 | int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, | 
|  | 148 | size_t len) | 
|  | 149 | { | 
|  | 150 | int ret; | 
|  | 151 |  | 
|  | 152 | wl1271_debug(DEBUG_ACX, "acx mem map"); | 
|  | 153 |  | 
|  | 154 | ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); | 
|  | 155 | if (ret < 0) | 
|  | 156 | return ret; | 
|  | 157 |  | 
|  | 158 | return 0; | 
|  | 159 | } | 
|  | 160 |  | 
| Juuso Oikarinen | 8793f9b | 2009-10-13 12:47:40 +0300 | [diff] [blame] | 161 | int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 162 | { | 
|  | 163 | struct acx_rx_msdu_lifetime *acx; | 
|  | 164 | int ret; | 
|  | 165 |  | 
|  | 166 | wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); | 
|  | 167 |  | 
|  | 168 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 169 | if (!acx) { | 
|  | 170 | ret = -ENOMEM; | 
|  | 171 | goto out; | 
|  | 172 | } | 
|  | 173 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 174 | acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 175 | ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, | 
|  | 176 | acx, sizeof(*acx)); | 
|  | 177 | if (ret < 0) { | 
|  | 178 | wl1271_warning("failed to set rx msdu life time: %d", ret); | 
|  | 179 | goto out; | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | out: | 
|  | 183 | kfree(acx); | 
|  | 184 | return ret; | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) | 
|  | 188 | { | 
|  | 189 | struct acx_rx_config *rx_config; | 
|  | 190 | int ret; | 
|  | 191 |  | 
|  | 192 | wl1271_debug(DEBUG_ACX, "acx rx config"); | 
|  | 193 |  | 
|  | 194 | rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); | 
|  | 195 | if (!rx_config) { | 
|  | 196 | ret = -ENOMEM; | 
|  | 197 | goto out; | 
|  | 198 | } | 
|  | 199 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 200 | rx_config->config_options = cpu_to_le32(config); | 
|  | 201 | rx_config->filter_options = cpu_to_le32(filter); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 202 |  | 
|  | 203 | ret = wl1271_cmd_configure(wl, ACX_RX_CFG, | 
|  | 204 | rx_config, sizeof(*rx_config)); | 
|  | 205 | if (ret < 0) { | 
|  | 206 | wl1271_warning("failed to set rx config: %d", ret); | 
|  | 207 | goto out; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | out: | 
|  | 211 | kfree(rx_config); | 
|  | 212 | return ret; | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | int wl1271_acx_pd_threshold(struct wl1271 *wl) | 
|  | 216 | { | 
|  | 217 | struct acx_packet_detection *pd; | 
|  | 218 | int ret; | 
|  | 219 |  | 
|  | 220 | wl1271_debug(DEBUG_ACX, "acx data pd threshold"); | 
|  | 221 |  | 
|  | 222 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | 
|  | 223 | if (!pd) { | 
|  | 224 | ret = -ENOMEM; | 
|  | 225 | goto out; | 
|  | 226 | } | 
|  | 227 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 228 | pd->threshold = cpu_to_le32(wl->conf.rx.packet_detection_threshold); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 229 |  | 
|  | 230 | ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); | 
|  | 231 | if (ret < 0) { | 
|  | 232 | wl1271_warning("failed to set pd threshold: %d", ret); | 
|  | 233 | goto out; | 
|  | 234 | } | 
|  | 235 |  | 
|  | 236 | out: | 
|  | 237 | kfree(pd); | 
| Julia Lawall | 36d3441 | 2010-08-16 18:27:30 +0200 | [diff] [blame] | 238 | return ret; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 239 | } | 
|  | 240 |  | 
|  | 241 | int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) | 
|  | 242 | { | 
|  | 243 | struct acx_slot *slot; | 
|  | 244 | int ret; | 
|  | 245 |  | 
|  | 246 | wl1271_debug(DEBUG_ACX, "acx slot"); | 
|  | 247 |  | 
|  | 248 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | 
|  | 249 | if (!slot) { | 
|  | 250 | ret = -ENOMEM; | 
|  | 251 | goto out; | 
|  | 252 | } | 
|  | 253 |  | 
|  | 254 | slot->wone_index = STATION_WONE_INDEX; | 
|  | 255 | slot->slot_time = slot_time; | 
|  | 256 |  | 
|  | 257 | ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); | 
|  | 258 | if (ret < 0) { | 
|  | 259 | wl1271_warning("failed to set slot time: %d", ret); | 
|  | 260 | goto out; | 
|  | 261 | } | 
|  | 262 |  | 
|  | 263 | out: | 
|  | 264 | kfree(slot); | 
|  | 265 | return ret; | 
|  | 266 | } | 
|  | 267 |  | 
| Juuso Oikarinen | c87dec9 | 2009-10-08 21:56:31 +0300 | [diff] [blame] | 268 | int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, | 
|  | 269 | void *mc_list, u32 mc_list_len) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 270 | { | 
|  | 271 | struct acx_dot11_grp_addr_tbl *acx; | 
|  | 272 | int ret; | 
|  | 273 |  | 
|  | 274 | wl1271_debug(DEBUG_ACX, "acx group address tbl"); | 
|  | 275 |  | 
|  | 276 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 277 | if (!acx) { | 
|  | 278 | ret = -ENOMEM; | 
|  | 279 | goto out; | 
|  | 280 | } | 
|  | 281 |  | 
|  | 282 | /* MAC filtering */ | 
| Juuso Oikarinen | c87dec9 | 2009-10-08 21:56:31 +0300 | [diff] [blame] | 283 | acx->enabled = enable; | 
|  | 284 | acx->num_groups = mc_list_len; | 
|  | 285 | memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 286 |  | 
|  | 287 | ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, | 
|  | 288 | acx, sizeof(*acx)); | 
|  | 289 | if (ret < 0) { | 
|  | 290 | wl1271_warning("failed to set group addr table: %d", ret); | 
|  | 291 | goto out; | 
|  | 292 | } | 
|  | 293 |  | 
|  | 294 | out: | 
|  | 295 | kfree(acx); | 
|  | 296 | return ret; | 
|  | 297 | } | 
|  | 298 |  | 
|  | 299 | int wl1271_acx_service_period_timeout(struct wl1271 *wl) | 
|  | 300 | { | 
|  | 301 | struct acx_rx_timeout *rx_timeout; | 
|  | 302 | int ret; | 
|  | 303 |  | 
|  | 304 | rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); | 
|  | 305 | if (!rx_timeout) { | 
|  | 306 | ret = -ENOMEM; | 
|  | 307 | goto out; | 
|  | 308 | } | 
|  | 309 |  | 
|  | 310 | wl1271_debug(DEBUG_ACX, "acx service period timeout"); | 
|  | 311 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 312 | rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); | 
|  | 313 | rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 314 |  | 
|  | 315 | ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, | 
|  | 316 | rx_timeout, sizeof(*rx_timeout)); | 
|  | 317 | if (ret < 0) { | 
|  | 318 | wl1271_warning("failed to set service period timeout: %d", | 
|  | 319 | ret); | 
|  | 320 | goto out; | 
|  | 321 | } | 
|  | 322 |  | 
|  | 323 | out: | 
|  | 324 | kfree(rx_timeout); | 
|  | 325 | return ret; | 
|  | 326 | } | 
|  | 327 |  | 
|  | 328 | int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) | 
|  | 329 | { | 
|  | 330 | struct acx_rts_threshold *rts; | 
|  | 331 | int ret; | 
|  | 332 |  | 
|  | 333 | wl1271_debug(DEBUG_ACX, "acx rts threshold"); | 
|  | 334 |  | 
|  | 335 | rts = kzalloc(sizeof(*rts), GFP_KERNEL); | 
|  | 336 | if (!rts) { | 
|  | 337 | ret = -ENOMEM; | 
|  | 338 | goto out; | 
|  | 339 | } | 
|  | 340 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 341 | rts->threshold = cpu_to_le16(rts_threshold); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 342 |  | 
|  | 343 | ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); | 
|  | 344 | if (ret < 0) { | 
|  | 345 | wl1271_warning("failed to set rts threshold: %d", ret); | 
|  | 346 | goto out; | 
|  | 347 | } | 
|  | 348 |  | 
|  | 349 | out: | 
|  | 350 | kfree(rts); | 
|  | 351 | return ret; | 
|  | 352 | } | 
|  | 353 |  | 
| Luciano Coelho | 6e92b41 | 2009-12-11 15:40:50 +0200 | [diff] [blame] | 354 | int wl1271_acx_dco_itrim_params(struct wl1271 *wl) | 
|  | 355 | { | 
|  | 356 | struct acx_dco_itrim_params *dco; | 
|  | 357 | struct conf_itrim_settings *c = &wl->conf.itrim; | 
|  | 358 | int ret; | 
|  | 359 |  | 
|  | 360 | wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); | 
|  | 361 |  | 
|  | 362 | dco = kzalloc(sizeof(*dco), GFP_KERNEL); | 
|  | 363 | if (!dco) { | 
|  | 364 | ret = -ENOMEM; | 
|  | 365 | goto out; | 
|  | 366 | } | 
|  | 367 |  | 
|  | 368 | dco->enable = c->enable; | 
|  | 369 | dco->timeout = cpu_to_le32(c->timeout); | 
|  | 370 |  | 
|  | 371 | ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, | 
|  | 372 | dco, sizeof(*dco)); | 
|  | 373 | if (ret < 0) { | 
|  | 374 | wl1271_warning("failed to set dco itrim parameters: %d", ret); | 
|  | 375 | goto out; | 
|  | 376 | } | 
|  | 377 |  | 
|  | 378 | out: | 
|  | 379 | kfree(dco); | 
|  | 380 | return ret; | 
|  | 381 | } | 
|  | 382 |  | 
| Juuso Oikarinen | 1922167 | 2009-10-08 21:56:35 +0300 | [diff] [blame] | 383 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 384 | { | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 385 | struct acx_beacon_filter_option *beacon_filter = NULL; | 
|  | 386 | int ret = 0; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 387 |  | 
|  | 388 | wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); | 
|  | 389 |  | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 390 | if (enable_filter && | 
|  | 391 | wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) | 
|  | 392 | goto out; | 
|  | 393 |  | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 394 | beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); | 
|  | 395 | if (!beacon_filter) { | 
|  | 396 | ret = -ENOMEM; | 
|  | 397 | goto out; | 
|  | 398 | } | 
|  | 399 |  | 
| Juuso Oikarinen | 1922167 | 2009-10-08 21:56:35 +0300 | [diff] [blame] | 400 | beacon_filter->enable = enable_filter; | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 401 |  | 
|  | 402 | /* | 
|  | 403 | * When set to zero, and the filter is enabled, beacons | 
|  | 404 | * without the unicast TIM bit set are dropped. | 
|  | 405 | */ | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 406 | beacon_filter->max_num_beacons = 0; | 
|  | 407 |  | 
|  | 408 | ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, | 
|  | 409 | beacon_filter, sizeof(*beacon_filter)); | 
|  | 410 | if (ret < 0) { | 
|  | 411 | wl1271_warning("failed to set beacon filter opt: %d", ret); | 
|  | 412 | goto out; | 
|  | 413 | } | 
|  | 414 |  | 
|  | 415 | out: | 
|  | 416 | kfree(beacon_filter); | 
|  | 417 | return ret; | 
|  | 418 | } | 
|  | 419 |  | 
|  | 420 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl) | 
|  | 421 | { | 
|  | 422 | struct acx_beacon_filter_ie_table *ie_table; | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 423 | int i, idx = 0; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 424 | int ret; | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 425 | bool vendor_spec = false; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 426 |  | 
|  | 427 | wl1271_debug(DEBUG_ACX, "acx beacon filter table"); | 
|  | 428 |  | 
|  | 429 | ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); | 
|  | 430 | if (!ie_table) { | 
|  | 431 | ret = -ENOMEM; | 
|  | 432 | goto out; | 
|  | 433 | } | 
|  | 434 |  | 
| Juuso Oikarinen | 1922167 | 2009-10-08 21:56:35 +0300 | [diff] [blame] | 435 | /* configure default beacon pass-through rules */ | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 436 | ie_table->num_ie = 0; | 
|  | 437 | for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { | 
|  | 438 | struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); | 
|  | 439 | ie_table->table[idx++] = r->ie; | 
|  | 440 | ie_table->table[idx++] = r->rule; | 
|  | 441 |  | 
|  | 442 | if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { | 
|  | 443 | /* only one vendor specific ie allowed */ | 
|  | 444 | if (vendor_spec) | 
|  | 445 | continue; | 
|  | 446 |  | 
|  | 447 | /* for vendor specific rules configure the | 
|  | 448 | additional fields */ | 
|  | 449 | memcpy(&(ie_table->table[idx]), r->oui, | 
|  | 450 | CONF_BCN_IE_OUI_LEN); | 
|  | 451 | idx += CONF_BCN_IE_OUI_LEN; | 
|  | 452 | ie_table->table[idx++] = r->type; | 
|  | 453 | memcpy(&(ie_table->table[idx]), r->version, | 
|  | 454 | CONF_BCN_IE_VER_LEN); | 
|  | 455 | idx += CONF_BCN_IE_VER_LEN; | 
|  | 456 | vendor_spec = true; | 
|  | 457 | } | 
|  | 458 |  | 
|  | 459 | ie_table->num_ie++; | 
|  | 460 | } | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 461 |  | 
|  | 462 | ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, | 
|  | 463 | ie_table, sizeof(*ie_table)); | 
|  | 464 | if (ret < 0) { | 
|  | 465 | wl1271_warning("failed to set beacon filter table: %d", ret); | 
|  | 466 | goto out; | 
|  | 467 | } | 
|  | 468 |  | 
|  | 469 | out: | 
|  | 470 | kfree(ie_table); | 
|  | 471 | return ret; | 
|  | 472 | } | 
|  | 473 |  | 
| Juuso Oikarinen | 6ccbb92 | 2010-03-26 12:53:23 +0200 | [diff] [blame] | 474 | #define ACX_CONN_MONIT_DISABLE_VALUE  0xffffffff | 
|  | 475 |  | 
|  | 476 | int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable) | 
| Juuso Oikarinen | 3441523 | 2009-10-08 21:56:33 +0300 | [diff] [blame] | 477 | { | 
|  | 478 | struct acx_conn_monit_params *acx; | 
| Juuso Oikarinen | 6ccbb92 | 2010-03-26 12:53:23 +0200 | [diff] [blame] | 479 | u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; | 
|  | 480 | u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; | 
| Juuso Oikarinen | 3441523 | 2009-10-08 21:56:33 +0300 | [diff] [blame] | 481 | int ret; | 
|  | 482 |  | 
| Juuso Oikarinen | 6ccbb92 | 2010-03-26 12:53:23 +0200 | [diff] [blame] | 483 | wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s", | 
|  | 484 | enable ? "enabled" : "disabled"); | 
| Juuso Oikarinen | 3441523 | 2009-10-08 21:56:33 +0300 | [diff] [blame] | 485 |  | 
|  | 486 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 487 | if (!acx) { | 
|  | 488 | ret = -ENOMEM; | 
|  | 489 | goto out; | 
|  | 490 | } | 
|  | 491 |  | 
| Juuso Oikarinen | 6ccbb92 | 2010-03-26 12:53:23 +0200 | [diff] [blame] | 492 | if (enable) { | 
|  | 493 | threshold = wl->conf.conn.synch_fail_thold; | 
|  | 494 | timeout = wl->conf.conn.bss_lose_timeout; | 
|  | 495 | } | 
|  | 496 |  | 
|  | 497 | acx->synch_fail_thold = cpu_to_le32(threshold); | 
|  | 498 | acx->bss_lose_timeout = cpu_to_le32(timeout); | 
| Juuso Oikarinen | 3441523 | 2009-10-08 21:56:33 +0300 | [diff] [blame] | 499 |  | 
|  | 500 | ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, | 
|  | 501 | acx, sizeof(*acx)); | 
|  | 502 | if (ret < 0) { | 
|  | 503 | wl1271_warning("failed to set connection monitor " | 
|  | 504 | "parameters: %d", ret); | 
|  | 505 | goto out; | 
|  | 506 | } | 
|  | 507 |  | 
|  | 508 | out: | 
|  | 509 | kfree(acx); | 
|  | 510 | return ret; | 
|  | 511 | } | 
|  | 512 |  | 
|  | 513 |  | 
| Juuso Oikarinen | 7fc3a86 | 2010-03-18 12:26:32 +0200 | [diff] [blame] | 514 | int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 515 | { | 
|  | 516 | struct acx_bt_wlan_coex *pta; | 
|  | 517 | int ret; | 
|  | 518 |  | 
|  | 519 | wl1271_debug(DEBUG_ACX, "acx sg enable"); | 
|  | 520 |  | 
|  | 521 | pta = kzalloc(sizeof(*pta), GFP_KERNEL); | 
|  | 522 | if (!pta) { | 
|  | 523 | ret = -ENOMEM; | 
|  | 524 | goto out; | 
|  | 525 | } | 
|  | 526 |  | 
| Juuso Oikarinen | 7fc3a86 | 2010-03-18 12:26:32 +0200 | [diff] [blame] | 527 | if (enable) | 
|  | 528 | pta->enable = wl->conf.sg.state; | 
|  | 529 | else | 
|  | 530 | pta->enable = CONF_SG_DISABLE; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 531 |  | 
|  | 532 | ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); | 
|  | 533 | if (ret < 0) { | 
|  | 534 | wl1271_warning("failed to set softgemini enable: %d", ret); | 
|  | 535 | goto out; | 
|  | 536 | } | 
|  | 537 |  | 
|  | 538 | out: | 
|  | 539 | kfree(pta); | 
|  | 540 | return ret; | 
|  | 541 | } | 
|  | 542 |  | 
|  | 543 | int wl1271_acx_sg_cfg(struct wl1271 *wl) | 
|  | 544 | { | 
|  | 545 | struct acx_bt_wlan_coex_param *param; | 
| Juuso Oikarinen | 2b60100b | 2009-10-13 12:47:39 +0300 | [diff] [blame] | 546 | struct conf_sg_settings *c = &wl->conf.sg; | 
| Juuso Oikarinen | 1b00f54 | 2010-03-18 12:26:30 +0200 | [diff] [blame] | 547 | int i, ret; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 548 |  | 
|  | 549 | wl1271_debug(DEBUG_ACX, "acx sg cfg"); | 
|  | 550 |  | 
|  | 551 | param = kzalloc(sizeof(*param), GFP_KERNEL); | 
|  | 552 | if (!param) { | 
|  | 553 | ret = -ENOMEM; | 
|  | 554 | goto out; | 
|  | 555 | } | 
|  | 556 |  | 
|  | 557 | /* BT-WLAN coext parameters */ | 
| Juuso Oikarinen | 1b00f54 | 2010-03-18 12:26:30 +0200 | [diff] [blame] | 558 | for (i = 0; i < CONF_SG_PARAMS_MAX; i++) | 
| Luciano Coelho | 23a7a51 | 2010-04-28 09:50:02 +0300 | [diff] [blame] | 559 | param->params[i] = cpu_to_le32(c->params[i]); | 
| Juuso Oikarinen | 1b00f54 | 2010-03-18 12:26:30 +0200 | [diff] [blame] | 560 | param->param_idx = CONF_SG_PARAMS_ALL; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 561 |  | 
|  | 562 | ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); | 
|  | 563 | if (ret < 0) { | 
|  | 564 | wl1271_warning("failed to set sg config: %d", ret); | 
|  | 565 | goto out; | 
|  | 566 | } | 
|  | 567 |  | 
|  | 568 | out: | 
|  | 569 | kfree(param); | 
|  | 570 | return ret; | 
|  | 571 | } | 
|  | 572 |  | 
|  | 573 | int wl1271_acx_cca_threshold(struct wl1271 *wl) | 
|  | 574 | { | 
|  | 575 | struct acx_energy_detection *detection; | 
|  | 576 | int ret; | 
|  | 577 |  | 
|  | 578 | wl1271_debug(DEBUG_ACX, "acx cca threshold"); | 
|  | 579 |  | 
|  | 580 | detection = kzalloc(sizeof(*detection), GFP_KERNEL); | 
|  | 581 | if (!detection) { | 
|  | 582 | ret = -ENOMEM; | 
|  | 583 | goto out; | 
|  | 584 | } | 
|  | 585 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 586 | detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); | 
| Juuso Oikarinen | 45b531a | 2009-10-13 12:47:41 +0300 | [diff] [blame] | 587 | detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 588 |  | 
|  | 589 | ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, | 
|  | 590 | detection, sizeof(*detection)); | 
|  | 591 | if (ret < 0) { | 
|  | 592 | wl1271_warning("failed to set cca threshold: %d", ret); | 
|  | 593 | return ret; | 
|  | 594 | } | 
|  | 595 |  | 
|  | 596 | out: | 
|  | 597 | kfree(detection); | 
|  | 598 | return ret; | 
|  | 599 | } | 
|  | 600 |  | 
|  | 601 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) | 
|  | 602 | { | 
|  | 603 | struct acx_beacon_broadcast *bb; | 
|  | 604 | int ret; | 
|  | 605 |  | 
|  | 606 | wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); | 
|  | 607 |  | 
|  | 608 | bb = kzalloc(sizeof(*bb), GFP_KERNEL); | 
|  | 609 | if (!bb) { | 
|  | 610 | ret = -ENOMEM; | 
|  | 611 | goto out; | 
|  | 612 | } | 
|  | 613 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 614 | bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); | 
|  | 615 | bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); | 
| Juuso Oikarinen | 51f2be2 | 2009-10-13 12:47:42 +0300 | [diff] [blame] | 616 | bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; | 
|  | 617 | bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 618 |  | 
|  | 619 | ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); | 
|  | 620 | if (ret < 0) { | 
|  | 621 | wl1271_warning("failed to set rx config: %d", ret); | 
|  | 622 | goto out; | 
|  | 623 | } | 
|  | 624 |  | 
|  | 625 | out: | 
|  | 626 | kfree(bb); | 
|  | 627 | return ret; | 
|  | 628 | } | 
|  | 629 |  | 
|  | 630 | int wl1271_acx_aid(struct wl1271 *wl, u16 aid) | 
|  | 631 | { | 
|  | 632 | struct acx_aid *acx_aid; | 
|  | 633 | int ret; | 
|  | 634 |  | 
|  | 635 | wl1271_debug(DEBUG_ACX, "acx aid"); | 
|  | 636 |  | 
|  | 637 | acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); | 
|  | 638 | if (!acx_aid) { | 
|  | 639 | ret = -ENOMEM; | 
|  | 640 | goto out; | 
|  | 641 | } | 
|  | 642 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 643 | acx_aid->aid = cpu_to_le16(aid); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 644 |  | 
|  | 645 | ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); | 
|  | 646 | if (ret < 0) { | 
|  | 647 | wl1271_warning("failed to set aid: %d", ret); | 
|  | 648 | goto out; | 
|  | 649 | } | 
|  | 650 |  | 
|  | 651 | out: | 
|  | 652 | kfree(acx_aid); | 
|  | 653 | return ret; | 
|  | 654 | } | 
|  | 655 |  | 
|  | 656 | int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) | 
|  | 657 | { | 
|  | 658 | struct acx_event_mask *mask; | 
|  | 659 | int ret; | 
|  | 660 |  | 
|  | 661 | wl1271_debug(DEBUG_ACX, "acx event mbox mask"); | 
|  | 662 |  | 
|  | 663 | mask = kzalloc(sizeof(*mask), GFP_KERNEL); | 
|  | 664 | if (!mask) { | 
|  | 665 | ret = -ENOMEM; | 
|  | 666 | goto out; | 
|  | 667 | } | 
|  | 668 |  | 
|  | 669 | /* high event mask is unused */ | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 670 | mask->high_event_mask = cpu_to_le32(0xffffffff); | 
|  | 671 | mask->event_mask = cpu_to_le32(event_mask); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 672 |  | 
|  | 673 | ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, | 
|  | 674 | mask, sizeof(*mask)); | 
|  | 675 | if (ret < 0) { | 
|  | 676 | wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); | 
|  | 677 | goto out; | 
|  | 678 | } | 
|  | 679 |  | 
|  | 680 | out: | 
|  | 681 | kfree(mask); | 
|  | 682 | return ret; | 
|  | 683 | } | 
|  | 684 |  | 
|  | 685 | int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) | 
|  | 686 | { | 
|  | 687 | struct acx_preamble *acx; | 
|  | 688 | int ret; | 
|  | 689 |  | 
|  | 690 | wl1271_debug(DEBUG_ACX, "acx_set_preamble"); | 
|  | 691 |  | 
|  | 692 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 693 | if (!acx) { | 
|  | 694 | ret = -ENOMEM; | 
|  | 695 | goto out; | 
|  | 696 | } | 
|  | 697 |  | 
|  | 698 | acx->preamble = preamble; | 
|  | 699 |  | 
|  | 700 | ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); | 
|  | 701 | if (ret < 0) { | 
|  | 702 | wl1271_warning("Setting of preamble failed: %d", ret); | 
|  | 703 | goto out; | 
|  | 704 | } | 
|  | 705 |  | 
|  | 706 | out: | 
|  | 707 | kfree(acx); | 
|  | 708 | return ret; | 
|  | 709 | } | 
|  | 710 |  | 
|  | 711 | int wl1271_acx_cts_protect(struct wl1271 *wl, | 
|  | 712 | enum acx_ctsprotect_type ctsprotect) | 
|  | 713 | { | 
|  | 714 | struct acx_ctsprotect *acx; | 
|  | 715 | int ret; | 
|  | 716 |  | 
|  | 717 | wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); | 
|  | 718 |  | 
|  | 719 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 720 | if (!acx) { | 
|  | 721 | ret = -ENOMEM; | 
|  | 722 | goto out; | 
|  | 723 | } | 
|  | 724 |  | 
|  | 725 | acx->ctsprotect = ctsprotect; | 
|  | 726 |  | 
|  | 727 | ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); | 
|  | 728 | if (ret < 0) { | 
|  | 729 | wl1271_warning("Setting of ctsprotect failed: %d", ret); | 
|  | 730 | goto out; | 
|  | 731 | } | 
|  | 732 |  | 
|  | 733 | out: | 
|  | 734 | kfree(acx); | 
|  | 735 | return ret; | 
|  | 736 | } | 
|  | 737 |  | 
|  | 738 | int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) | 
|  | 739 | { | 
|  | 740 | int ret; | 
|  | 741 |  | 
|  | 742 | wl1271_debug(DEBUG_ACX, "acx statistics"); | 
|  | 743 |  | 
|  | 744 | ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, | 
|  | 745 | sizeof(*stats)); | 
|  | 746 | if (ret < 0) { | 
|  | 747 | wl1271_warning("acx statistics failed: %d", ret); | 
|  | 748 | return -ENOMEM; | 
|  | 749 | } | 
|  | 750 |  | 
|  | 751 | return 0; | 
|  | 752 | } | 
|  | 753 |  | 
| Arik Nemtsov | 79b223f | 2010-10-16 17:52:59 +0200 | [diff] [blame] | 754 | int wl1271_acx_sta_rate_policies(struct wl1271 *wl) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 755 | { | 
| Arik Nemtsov | 79b223f | 2010-10-16 17:52:59 +0200 | [diff] [blame] | 756 | struct acx_sta_rate_policy *acx; | 
| Arik Nemtsov | 1e05a81 | 2010-10-16 17:44:51 +0200 | [diff] [blame] | 757 | struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; | 
| Juuso Oikarinen | 830fb67 | 2009-12-11 15:41:06 +0200 | [diff] [blame] | 758 | int idx = 0; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 759 | int ret = 0; | 
|  | 760 |  | 
|  | 761 | wl1271_debug(DEBUG_ACX, "acx rate policies"); | 
|  | 762 |  | 
|  | 763 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 764 |  | 
|  | 765 | if (!acx) { | 
|  | 766 | ret = -ENOMEM; | 
|  | 767 | goto out; | 
|  | 768 | } | 
|  | 769 |  | 
| Juuso Oikarinen | 830fb67 | 2009-12-11 15:41:06 +0200 | [diff] [blame] | 770 | /* configure one basic rate class */ | 
|  | 771 | idx = ACX_TX_BASIC_RATE; | 
| Juuso Oikarinen | ebba60c | 2010-04-01 11:38:20 +0300 | [diff] [blame] | 772 | acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate); | 
| Juuso Oikarinen | 830fb67 | 2009-12-11 15:41:06 +0200 | [diff] [blame] | 773 | acx->rate_class[idx].short_retry_limit = c->short_retry_limit; | 
|  | 774 | acx->rate_class[idx].long_retry_limit = c->long_retry_limit; | 
|  | 775 | acx->rate_class[idx].aflags = c->aflags; | 
|  | 776 |  | 
|  | 777 | /* configure one AP supported rate class */ | 
|  | 778 | idx = ACX_TX_AP_FULL_RATE; | 
|  | 779 | acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set); | 
|  | 780 | acx->rate_class[idx].short_retry_limit = c->short_retry_limit; | 
|  | 781 | acx->rate_class[idx].long_retry_limit = c->long_retry_limit; | 
|  | 782 | acx->rate_class[idx].aflags = c->aflags; | 
|  | 783 |  | 
|  | 784 | acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 785 |  | 
| Eliad Peller | 72c2d9e | 2011-02-02 09:59:37 +0200 | [diff] [blame] | 786 | wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", | 
|  | 787 | acx->rate_class[ACX_TX_BASIC_RATE].enabled_rates, | 
|  | 788 | acx->rate_class[ACX_TX_AP_FULL_RATE].enabled_rates); | 
|  | 789 |  | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 790 | ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | 
|  | 791 | if (ret < 0) { | 
|  | 792 | wl1271_warning("Setting of rate policies failed: %d", ret); | 
|  | 793 | goto out; | 
|  | 794 | } | 
|  | 795 |  | 
|  | 796 | out: | 
|  | 797 | kfree(acx); | 
|  | 798 | return ret; | 
|  | 799 | } | 
|  | 800 |  | 
| Arik Nemtsov | 79b223f | 2010-10-16 17:52:59 +0200 | [diff] [blame] | 801 | int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, | 
|  | 802 | u8 idx) | 
|  | 803 | { | 
|  | 804 | struct acx_ap_rate_policy *acx; | 
|  | 805 | int ret = 0; | 
|  | 806 |  | 
|  | 807 | wl1271_debug(DEBUG_ACX, "acx ap rate policy"); | 
|  | 808 |  | 
|  | 809 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 810 | if (!acx) { | 
|  | 811 | ret = -ENOMEM; | 
|  | 812 | goto out; | 
|  | 813 | } | 
|  | 814 |  | 
|  | 815 | acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); | 
|  | 816 | acx->rate_policy.short_retry_limit = c->short_retry_limit; | 
|  | 817 | acx->rate_policy.long_retry_limit = c->long_retry_limit; | 
|  | 818 | acx->rate_policy.aflags = c->aflags; | 
|  | 819 |  | 
| Eliad Peller | 1d4801f | 2011-01-16 10:07:10 +0100 | [diff] [blame] | 820 | acx->rate_policy_idx = cpu_to_le32(idx); | 
| Arik Nemtsov | 79b223f | 2010-10-16 17:52:59 +0200 | [diff] [blame] | 821 |  | 
|  | 822 | ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | 
|  | 823 | if (ret < 0) { | 
|  | 824 | wl1271_warning("Setting of ap rate policy failed: %d", ret); | 
|  | 825 | goto out; | 
|  | 826 | } | 
|  | 827 |  | 
|  | 828 | out: | 
|  | 829 | kfree(acx); | 
|  | 830 | return ret; | 
|  | 831 | } | 
|  | 832 |  | 
| Kalle Valo | 243eeb5 | 2010-02-18 13:25:39 +0200 | [diff] [blame] | 833 | int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, | 
|  | 834 | u8 aifsn, u16 txop) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 835 | { | 
|  | 836 | struct acx_ac_cfg *acx; | 
| Kalle Valo | 243eeb5 | 2010-02-18 13:25:39 +0200 | [diff] [blame] | 837 | int ret = 0; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 838 |  | 
| Kalle Valo | 243eeb5 | 2010-02-18 13:25:39 +0200 | [diff] [blame] | 839 | wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " | 
|  | 840 | "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 841 |  | 
|  | 842 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 843 |  | 
|  | 844 | if (!acx) { | 
|  | 845 | ret = -ENOMEM; | 
|  | 846 | goto out; | 
|  | 847 | } | 
|  | 848 |  | 
| Kalle Valo | 243eeb5 | 2010-02-18 13:25:39 +0200 | [diff] [blame] | 849 | acx->ac = ac; | 
|  | 850 | acx->cw_min = cw_min; | 
|  | 851 | acx->cw_max = cpu_to_le16(cw_max); | 
|  | 852 | acx->aifsn = aifsn; | 
|  | 853 | acx->tx_op_limit = cpu_to_le16(txop); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 854 |  | 
| Kalle Valo | 243eeb5 | 2010-02-18 13:25:39 +0200 | [diff] [blame] | 855 | ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); | 
|  | 856 | if (ret < 0) { | 
|  | 857 | wl1271_warning("acx ac cfg failed: %d", ret); | 
|  | 858 | goto out; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 859 | } | 
|  | 860 |  | 
|  | 861 | out: | 
|  | 862 | kfree(acx); | 
|  | 863 | return ret; | 
|  | 864 | } | 
|  | 865 |  | 
| Kalle Valo | f2054df | 2010-02-18 13:25:40 +0200 | [diff] [blame] | 866 | int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, | 
|  | 867 | u8 tsid, u8 ps_scheme, u8 ack_policy, | 
|  | 868 | u32 apsd_conf0, u32 apsd_conf1) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 869 | { | 
|  | 870 | struct acx_tid_config *acx; | 
| Kalle Valo | f2054df | 2010-02-18 13:25:40 +0200 | [diff] [blame] | 871 | int ret = 0; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 872 |  | 
|  | 873 | wl1271_debug(DEBUG_ACX, "acx tid config"); | 
|  | 874 |  | 
|  | 875 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 876 |  | 
|  | 877 | if (!acx) { | 
|  | 878 | ret = -ENOMEM; | 
|  | 879 | goto out; | 
|  | 880 | } | 
|  | 881 |  | 
| Kalle Valo | f2054df | 2010-02-18 13:25:40 +0200 | [diff] [blame] | 882 | acx->queue_id = queue_id; | 
|  | 883 | acx->channel_type = channel_type; | 
|  | 884 | acx->tsid = tsid; | 
|  | 885 | acx->ps_scheme = ps_scheme; | 
|  | 886 | acx->ack_policy = ack_policy; | 
|  | 887 | acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); | 
|  | 888 | acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 889 |  | 
| Kalle Valo | f2054df | 2010-02-18 13:25:40 +0200 | [diff] [blame] | 890 | ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); | 
|  | 891 | if (ret < 0) { | 
|  | 892 | wl1271_warning("Setting of tid config failed: %d", ret); | 
|  | 893 | goto out; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 894 | } | 
|  | 895 |  | 
|  | 896 | out: | 
|  | 897 | kfree(acx); | 
|  | 898 | return ret; | 
|  | 899 | } | 
|  | 900 |  | 
| Arik Nemtsov | 68d069c | 2010-11-08 10:51:07 +0100 | [diff] [blame] | 901 | int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 902 | { | 
|  | 903 | struct acx_frag_threshold *acx; | 
|  | 904 | int ret = 0; | 
|  | 905 |  | 
|  | 906 | wl1271_debug(DEBUG_ACX, "acx frag threshold"); | 
|  | 907 |  | 
|  | 908 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 909 |  | 
|  | 910 | if (!acx) { | 
|  | 911 | ret = -ENOMEM; | 
|  | 912 | goto out; | 
|  | 913 | } | 
|  | 914 |  | 
| Arik Nemtsov | 68d069c | 2010-11-08 10:51:07 +0100 | [diff] [blame] | 915 | acx->frag_threshold = cpu_to_le16(frag_threshold); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 916 | ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); | 
|  | 917 | if (ret < 0) { | 
|  | 918 | wl1271_warning("Setting of frag threshold failed: %d", ret); | 
|  | 919 | goto out; | 
|  | 920 | } | 
|  | 921 |  | 
|  | 922 | out: | 
|  | 923 | kfree(acx); | 
|  | 924 | return ret; | 
|  | 925 | } | 
|  | 926 |  | 
|  | 927 | int wl1271_acx_tx_config_options(struct wl1271 *wl) | 
|  | 928 | { | 
|  | 929 | struct acx_tx_config_options *acx; | 
|  | 930 | int ret = 0; | 
|  | 931 |  | 
|  | 932 | wl1271_debug(DEBUG_ACX, "acx tx config options"); | 
|  | 933 |  | 
|  | 934 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 935 |  | 
|  | 936 | if (!acx) { | 
|  | 937 | ret = -ENOMEM; | 
|  | 938 | goto out; | 
|  | 939 | } | 
|  | 940 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 941 | acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); | 
|  | 942 | acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 943 | ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); | 
|  | 944 | if (ret < 0) { | 
|  | 945 | wl1271_warning("Setting of tx options failed: %d", ret); | 
|  | 946 | goto out; | 
|  | 947 | } | 
|  | 948 |  | 
|  | 949 | out: | 
|  | 950 | kfree(acx); | 
|  | 951 | return ret; | 
|  | 952 | } | 
|  | 953 |  | 
| Eliad Peller | c8bde24 | 2011-02-02 09:59:35 +0200 | [diff] [blame] | 954 | int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 955 | { | 
| Eliad Peller | c8bde24 | 2011-02-02 09:59:35 +0200 | [diff] [blame] | 956 | struct wl1271_acx_ap_config_memory *mem_conf; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 957 | int ret; | 
|  | 958 |  | 
|  | 959 | wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); | 
|  | 960 |  | 
|  | 961 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | 
|  | 962 | if (!mem_conf) { | 
|  | 963 | ret = -ENOMEM; | 
|  | 964 | goto out; | 
|  | 965 | } | 
|  | 966 |  | 
|  | 967 | /* memory config */ | 
| Eliad Peller | fe5ef09 | 2011-02-02 09:59:36 +0200 | [diff] [blame] | 968 | mem_conf->num_stations = wl->conf.mem.num_stations; | 
|  | 969 | mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; | 
|  | 970 | mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; | 
|  | 971 | mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 972 | mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 973 |  | 
|  | 974 | ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | 
|  | 975 | sizeof(*mem_conf)); | 
|  | 976 | if (ret < 0) { | 
|  | 977 | wl1271_warning("wl1271 mem config failed: %d", ret); | 
|  | 978 | goto out; | 
|  | 979 | } | 
|  | 980 |  | 
|  | 981 | out: | 
|  | 982 | kfree(mem_conf); | 
|  | 983 | return ret; | 
|  | 984 | } | 
|  | 985 |  | 
| Eliad Peller | c8bde24 | 2011-02-02 09:59:35 +0200 | [diff] [blame] | 986 | int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) | 
|  | 987 | { | 
|  | 988 | struct wl1271_acx_sta_config_memory *mem_conf; | 
|  | 989 | int ret; | 
|  | 990 |  | 
|  | 991 | wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); | 
|  | 992 |  | 
|  | 993 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | 
|  | 994 | if (!mem_conf) { | 
|  | 995 | ret = -ENOMEM; | 
|  | 996 | goto out; | 
|  | 997 | } | 
|  | 998 |  | 
|  | 999 | /* memory config */ | 
| Eliad Peller | fe5ef09 | 2011-02-02 09:59:36 +0200 | [diff] [blame] | 1000 | mem_conf->num_stations = wl->conf.mem.num_stations; | 
|  | 1001 | mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; | 
|  | 1002 | mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; | 
|  | 1003 | mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; | 
| Eliad Peller | c8bde24 | 2011-02-02 09:59:35 +0200 | [diff] [blame] | 1004 | mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); | 
|  | 1005 | mem_conf->dyn_mem_enable = wl->conf.mem.dynamic_memory; | 
|  | 1006 | mem_conf->tx_free_req = wl->conf.mem.min_req_tx_blocks; | 
|  | 1007 | mem_conf->rx_free_req = wl->conf.mem.min_req_rx_blocks; | 
|  | 1008 | mem_conf->tx_min = wl->conf.mem.tx_min; | 
|  | 1009 |  | 
|  | 1010 | ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | 
|  | 1011 | sizeof(*mem_conf)); | 
|  | 1012 | if (ret < 0) { | 
|  | 1013 | wl1271_warning("wl1271 mem config failed: %d", ret); | 
|  | 1014 | goto out; | 
|  | 1015 | } | 
|  | 1016 |  | 
|  | 1017 | out: | 
|  | 1018 | kfree(mem_conf); | 
|  | 1019 | return ret; | 
|  | 1020 | } | 
|  | 1021 |  | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 1022 | int wl1271_acx_init_mem_config(struct wl1271 *wl) | 
|  | 1023 | { | 
|  | 1024 | int ret; | 
|  | 1025 |  | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 1026 | wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), | 
| Juuso Oikarinen | 45b531a | 2009-10-13 12:47:41 +0300 | [diff] [blame] | 1027 | GFP_KERNEL); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 1028 | if (!wl->target_mem_map) { | 
|  | 1029 | wl1271_error("couldn't allocate target memory map"); | 
|  | 1030 | return -ENOMEM; | 
|  | 1031 | } | 
|  | 1032 |  | 
|  | 1033 | /* we now ask for the firmware built memory map */ | 
|  | 1034 | ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, | 
|  | 1035 | sizeof(struct wl1271_acx_mem_map)); | 
|  | 1036 | if (ret < 0) { | 
|  | 1037 | wl1271_error("couldn't retrieve firmware memory map"); | 
|  | 1038 | kfree(wl->target_mem_map); | 
|  | 1039 | wl->target_mem_map = NULL; | 
|  | 1040 | return ret; | 
|  | 1041 | } | 
|  | 1042 |  | 
|  | 1043 | /* initialize TX block book keeping */ | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 1044 | wl->tx_blocks_available = | 
|  | 1045 | le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 1046 | wl1271_debug(DEBUG_TX, "available tx blocks: %d", | 
|  | 1047 | wl->tx_blocks_available); | 
|  | 1048 |  | 
|  | 1049 | return 0; | 
|  | 1050 | } | 
|  | 1051 |  | 
|  | 1052 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) | 
|  | 1053 | { | 
|  | 1054 | struct wl1271_acx_rx_config_opt *rx_conf; | 
|  | 1055 | int ret; | 
|  | 1056 |  | 
|  | 1057 | wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); | 
|  | 1058 |  | 
|  | 1059 | rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); | 
|  | 1060 | if (!rx_conf) { | 
|  | 1061 | ret = -ENOMEM; | 
|  | 1062 | goto out; | 
|  | 1063 | } | 
|  | 1064 |  | 
| Luciano Coelho | d0f63b2 | 2009-10-15 10:33:29 +0300 | [diff] [blame] | 1065 | rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); | 
|  | 1066 | rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); | 
|  | 1067 | rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); | 
| Juuso Oikarinen | 8793f9b | 2009-10-13 12:47:40 +0300 | [diff] [blame] | 1068 | rx_conf->queue_type = wl->conf.rx.queue_type; | 
| Luciano Coelho | f5fc0f8 | 2009-08-06 16:25:28 +0300 | [diff] [blame] | 1069 |  | 
|  | 1070 | ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, | 
|  | 1071 | sizeof(*rx_conf)); | 
|  | 1072 | if (ret < 0) { | 
|  | 1073 | wl1271_warning("wl1271 rx config opt failed: %d", ret); | 
|  | 1074 | goto out; | 
|  | 1075 | } | 
|  | 1076 |  | 
|  | 1077 | out: | 
|  | 1078 | kfree(rx_conf); | 
|  | 1079 | return ret; | 
|  | 1080 | } | 
| Juuso Oikarinen | 3cfd6cf | 2009-10-12 15:08:52 +0300 | [diff] [blame] | 1081 |  | 
| Juuso Oikarinen | 11f70f9 | 2009-10-13 12:47:46 +0300 | [diff] [blame] | 1082 | int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) | 
|  | 1083 | { | 
|  | 1084 | struct wl1271_acx_bet_enable *acx = NULL; | 
|  | 1085 | int ret = 0; | 
|  | 1086 |  | 
|  | 1087 | wl1271_debug(DEBUG_ACX, "acx bet enable"); | 
|  | 1088 |  | 
|  | 1089 | if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) | 
|  | 1090 | goto out; | 
|  | 1091 |  | 
|  | 1092 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1093 | if (!acx) { | 
|  | 1094 | ret = -ENOMEM; | 
|  | 1095 | goto out; | 
|  | 1096 | } | 
|  | 1097 |  | 
|  | 1098 | acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; | 
|  | 1099 | acx->max_consecutive = wl->conf.conn.bet_max_consecutive; | 
|  | 1100 |  | 
|  | 1101 | ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); | 
|  | 1102 | if (ret < 0) { | 
|  | 1103 | wl1271_warning("acx bet enable failed: %d", ret); | 
|  | 1104 | goto out; | 
|  | 1105 | } | 
|  | 1106 |  | 
|  | 1107 | out: | 
|  | 1108 | kfree(acx); | 
|  | 1109 | return ret; | 
|  | 1110 | } | 
| Juuso Oikarinen | 01c0916 | 2009-10-13 12:47:55 +0300 | [diff] [blame] | 1111 |  | 
| Eliad Peller | c531277 | 2010-12-09 11:31:27 +0200 | [diff] [blame] | 1112 | int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address) | 
| Juuso Oikarinen | 01c0916 | 2009-10-13 12:47:55 +0300 | [diff] [blame] | 1113 | { | 
|  | 1114 | struct wl1271_acx_arp_filter *acx; | 
|  | 1115 | int ret; | 
|  | 1116 |  | 
| Juuso Oikarinen | ca52a5e | 2010-07-08 17:50:02 +0300 | [diff] [blame] | 1117 | wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); | 
| Juuso Oikarinen | 01c0916 | 2009-10-13 12:47:55 +0300 | [diff] [blame] | 1118 |  | 
|  | 1119 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1120 | if (!acx) { | 
|  | 1121 | ret = -ENOMEM; | 
|  | 1122 | goto out; | 
|  | 1123 | } | 
|  | 1124 |  | 
| Juuso Oikarinen | eb887df | 2010-07-08 17:49:58 +0300 | [diff] [blame] | 1125 | acx->version = ACX_IPV4_VERSION; | 
| Juuso Oikarinen | ca52a5e | 2010-07-08 17:50:02 +0300 | [diff] [blame] | 1126 | acx->enable = enable; | 
| Juuso Oikarinen | 01c0916 | 2009-10-13 12:47:55 +0300 | [diff] [blame] | 1127 |  | 
| Eliad Peller | c531277 | 2010-12-09 11:31:27 +0200 | [diff] [blame] | 1128 | if (enable) | 
| Juuso Oikarinen | ca52a5e | 2010-07-08 17:50:02 +0300 | [diff] [blame] | 1129 | memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); | 
| Juuso Oikarinen | 01c0916 | 2009-10-13 12:47:55 +0300 | [diff] [blame] | 1130 |  | 
|  | 1131 | ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, | 
|  | 1132 | acx, sizeof(*acx)); | 
|  | 1133 | if (ret < 0) { | 
|  | 1134 | wl1271_warning("failed to set arp ip filter: %d", ret); | 
|  | 1135 | goto out; | 
|  | 1136 | } | 
|  | 1137 |  | 
|  | 1138 | out: | 
|  | 1139 | kfree(acx); | 
|  | 1140 | return ret; | 
|  | 1141 | } | 
| Juuso Oikarinen | 38ad2d8 | 2009-12-11 15:41:08 +0200 | [diff] [blame] | 1142 |  | 
|  | 1143 | int wl1271_acx_pm_config(struct wl1271 *wl) | 
|  | 1144 | { | 
|  | 1145 | struct wl1271_acx_pm_config *acx = NULL; | 
|  | 1146 | struct  conf_pm_config_settings *c = &wl->conf.pm_config; | 
|  | 1147 | int ret = 0; | 
|  | 1148 |  | 
|  | 1149 | wl1271_debug(DEBUG_ACX, "acx pm config"); | 
|  | 1150 |  | 
|  | 1151 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1152 | if (!acx) { | 
|  | 1153 | ret = -ENOMEM; | 
|  | 1154 | goto out; | 
|  | 1155 | } | 
|  | 1156 |  | 
|  | 1157 | acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); | 
|  | 1158 | acx->host_fast_wakeup_support = c->host_fast_wakeup_support; | 
|  | 1159 |  | 
|  | 1160 | ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); | 
|  | 1161 | if (ret < 0) { | 
|  | 1162 | wl1271_warning("acx pm config failed: %d", ret); | 
|  | 1163 | goto out; | 
|  | 1164 | } | 
|  | 1165 |  | 
|  | 1166 | out: | 
|  | 1167 | kfree(acx); | 
|  | 1168 | return ret; | 
|  | 1169 | } | 
| Juuso Oikarinen | c189955 | 2010-03-26 12:53:32 +0200 | [diff] [blame] | 1170 |  | 
|  | 1171 | int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable) | 
|  | 1172 | { | 
|  | 1173 | struct wl1271_acx_keep_alive_mode *acx = NULL; | 
|  | 1174 | int ret = 0; | 
|  | 1175 |  | 
|  | 1176 | wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable); | 
|  | 1177 |  | 
|  | 1178 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1179 | if (!acx) { | 
|  | 1180 | ret = -ENOMEM; | 
|  | 1181 | goto out; | 
|  | 1182 | } | 
|  | 1183 |  | 
|  | 1184 | acx->enabled = enable; | 
|  | 1185 |  | 
|  | 1186 | ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); | 
|  | 1187 | if (ret < 0) { | 
|  | 1188 | wl1271_warning("acx keep alive mode failed: %d", ret); | 
|  | 1189 | goto out; | 
|  | 1190 | } | 
|  | 1191 |  | 
|  | 1192 | out: | 
|  | 1193 | kfree(acx); | 
|  | 1194 | return ret; | 
|  | 1195 | } | 
| Juuso Oikarinen | 00236aed | 2010-04-09 11:07:30 +0300 | [diff] [blame] | 1196 |  | 
| Juuso Oikarinen | c189955 | 2010-03-26 12:53:32 +0200 | [diff] [blame] | 1197 | int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) | 
|  | 1198 | { | 
|  | 1199 | struct wl1271_acx_keep_alive_config *acx = NULL; | 
|  | 1200 | int ret = 0; | 
|  | 1201 |  | 
|  | 1202 | wl1271_debug(DEBUG_ACX, "acx keep alive config"); | 
|  | 1203 |  | 
|  | 1204 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1205 | if (!acx) { | 
|  | 1206 | ret = -ENOMEM; | 
|  | 1207 | goto out; | 
|  | 1208 | } | 
|  | 1209 |  | 
|  | 1210 | acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); | 
|  | 1211 | acx->index = index; | 
|  | 1212 | acx->tpl_validation = tpl_valid; | 
|  | 1213 | acx->trigger = ACX_KEEP_ALIVE_NO_TX; | 
|  | 1214 |  | 
|  | 1215 | ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG, | 
|  | 1216 | acx, sizeof(*acx)); | 
|  | 1217 | if (ret < 0) { | 
|  | 1218 | wl1271_warning("acx keep alive config failed: %d", ret); | 
|  | 1219 | goto out; | 
|  | 1220 | } | 
|  | 1221 |  | 
|  | 1222 | out: | 
|  | 1223 | kfree(acx); | 
|  | 1224 | return ret; | 
|  | 1225 | } | 
| Juuso Oikarinen | 00236aed | 2010-04-09 11:07:30 +0300 | [diff] [blame] | 1226 |  | 
|  | 1227 | int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, | 
|  | 1228 | s16 thold, u8 hyst) | 
|  | 1229 | { | 
|  | 1230 | struct wl1271_acx_rssi_snr_trigger *acx = NULL; | 
|  | 1231 | int ret = 0; | 
|  | 1232 |  | 
|  | 1233 | wl1271_debug(DEBUG_ACX, "acx rssi snr trigger"); | 
|  | 1234 |  | 
|  | 1235 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1236 | if (!acx) { | 
|  | 1237 | ret = -ENOMEM; | 
|  | 1238 | goto out; | 
|  | 1239 | } | 
|  | 1240 |  | 
|  | 1241 | wl->last_rssi_event = -1; | 
|  | 1242 |  | 
|  | 1243 | acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); | 
|  | 1244 | acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; | 
|  | 1245 | acx->type = WL1271_ACX_TRIG_TYPE_EDGE; | 
|  | 1246 | if (enable) | 
|  | 1247 | acx->enable = WL1271_ACX_TRIG_ENABLE; | 
|  | 1248 | else | 
|  | 1249 | acx->enable = WL1271_ACX_TRIG_DISABLE; | 
|  | 1250 |  | 
|  | 1251 | acx->index = WL1271_ACX_TRIG_IDX_RSSI; | 
|  | 1252 | acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; | 
|  | 1253 | acx->threshold = cpu_to_le16(thold); | 
|  | 1254 | acx->hysteresis = hyst; | 
|  | 1255 |  | 
|  | 1256 | ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx)); | 
|  | 1257 | if (ret < 0) { | 
|  | 1258 | wl1271_warning("acx rssi snr trigger setting failed: %d", ret); | 
|  | 1259 | goto out; | 
|  | 1260 | } | 
|  | 1261 |  | 
|  | 1262 | out: | 
|  | 1263 | kfree(acx); | 
|  | 1264 | return ret; | 
|  | 1265 | } | 
|  | 1266 |  | 
|  | 1267 | int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl) | 
|  | 1268 | { | 
|  | 1269 | struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; | 
|  | 1270 | struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; | 
|  | 1271 | int ret = 0; | 
|  | 1272 |  | 
|  | 1273 | wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights"); | 
|  | 1274 |  | 
|  | 1275 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1276 | if (!acx) { | 
|  | 1277 | ret = -ENOMEM; | 
|  | 1278 | goto out; | 
|  | 1279 | } | 
|  | 1280 |  | 
|  | 1281 | acx->rssi_beacon = c->avg_weight_rssi_beacon; | 
|  | 1282 | acx->rssi_data = c->avg_weight_rssi_data; | 
|  | 1283 | acx->snr_beacon = c->avg_weight_snr_beacon; | 
|  | 1284 | acx->snr_data = c->avg_weight_snr_data; | 
|  | 1285 |  | 
|  | 1286 | ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx)); | 
|  | 1287 | if (ret < 0) { | 
|  | 1288 | wl1271_warning("acx rssi snr trigger weights failed: %d", ret); | 
|  | 1289 | goto out; | 
|  | 1290 | } | 
|  | 1291 |  | 
|  | 1292 | out: | 
|  | 1293 | kfree(acx); | 
|  | 1294 | return ret; | 
|  | 1295 | } | 
| Juuso Oikarinen | bbbb538 | 2010-07-08 17:49:57 +0300 | [diff] [blame] | 1296 |  | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1297 | int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, | 
|  | 1298 | struct ieee80211_sta_ht_cap *ht_cap, | 
|  | 1299 | bool allow_ht_operation) | 
|  | 1300 | { | 
|  | 1301 | struct wl1271_acx_ht_capabilities *acx; | 
|  | 1302 | u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 
|  | 1303 | int ret = 0; | 
| Eliad Peller | 6177eae | 2010-12-22 12:38:52 +0100 | [diff] [blame] | 1304 | u32 ht_capabilites = 0; | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1305 |  | 
|  | 1306 | wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); | 
|  | 1307 |  | 
|  | 1308 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1309 | if (!acx) { | 
|  | 1310 | ret = -ENOMEM; | 
|  | 1311 | goto out; | 
|  | 1312 | } | 
|  | 1313 |  | 
|  | 1314 | /* Allow HT Operation ? */ | 
|  | 1315 | if (allow_ht_operation) { | 
| Eliad Peller | 6177eae | 2010-12-22 12:38:52 +0100 | [diff] [blame] | 1316 | ht_capabilites = | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1317 | WL1271_ACX_FW_CAP_HT_OPERATION; | 
|  | 1318 | if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) | 
| Eliad Peller | 6177eae | 2010-12-22 12:38:52 +0100 | [diff] [blame] | 1319 | ht_capabilites |= | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1320 | WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; | 
|  | 1321 | if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) | 
| Eliad Peller | 6177eae | 2010-12-22 12:38:52 +0100 | [diff] [blame] | 1322 | ht_capabilites |= | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1323 | WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; | 
|  | 1324 | if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) | 
| Eliad Peller | 6177eae | 2010-12-22 12:38:52 +0100 | [diff] [blame] | 1325 | ht_capabilites |= | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1326 | WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; | 
|  | 1327 |  | 
|  | 1328 | /* get data from A-MPDU parameters field */ | 
|  | 1329 | acx->ampdu_max_length = ht_cap->ampdu_factor; | 
|  | 1330 | acx->ampdu_min_spacing = ht_cap->ampdu_density; | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1331 | } | 
|  | 1332 |  | 
| Eliad Peller | 6dc9fb3 | 2011-02-23 00:27:07 +0200 | [diff] [blame] | 1333 | memcpy(acx->mac_address, mac_address, ETH_ALEN); | 
| Eliad Peller | 6177eae | 2010-12-22 12:38:52 +0100 | [diff] [blame] | 1334 | acx->ht_capabilites = cpu_to_le32(ht_capabilites); | 
|  | 1335 |  | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1336 | ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); | 
|  | 1337 | if (ret < 0) { | 
|  | 1338 | wl1271_warning("acx ht capabilities setting failed: %d", ret); | 
|  | 1339 | goto out; | 
|  | 1340 | } | 
|  | 1341 |  | 
|  | 1342 | out: | 
|  | 1343 | kfree(acx); | 
|  | 1344 | return ret; | 
|  | 1345 | } | 
|  | 1346 |  | 
|  | 1347 | int wl1271_acx_set_ht_information(struct wl1271 *wl, | 
|  | 1348 | u16 ht_operation_mode) | 
|  | 1349 | { | 
|  | 1350 | struct wl1271_acx_ht_information *acx; | 
|  | 1351 | int ret = 0; | 
|  | 1352 |  | 
|  | 1353 | wl1271_debug(DEBUG_ACX, "acx ht information setting"); | 
|  | 1354 |  | 
|  | 1355 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1356 | if (!acx) { | 
|  | 1357 | ret = -ENOMEM; | 
|  | 1358 | goto out; | 
|  | 1359 | } | 
|  | 1360 |  | 
|  | 1361 | acx->ht_protection = | 
|  | 1362 | (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); | 
|  | 1363 | acx->rifs_mode = 0; | 
| Helmut Schaa | 95a7761 | 2011-03-02 10:46:46 +0100 | [diff] [blame] | 1364 | acx->gf_protection = | 
|  | 1365 | !!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | 
| Shahar Levi | c4db1c8 | 2010-10-13 16:09:40 +0200 | [diff] [blame] | 1366 | acx->ht_tx_burst_limit = 0; | 
|  | 1367 | acx->dual_cts_protection = 0; | 
|  | 1368 |  | 
|  | 1369 | ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); | 
|  | 1370 |  | 
|  | 1371 | if (ret < 0) { | 
|  | 1372 | wl1271_warning("acx ht information setting failed: %d", ret); | 
|  | 1373 | goto out; | 
|  | 1374 | } | 
|  | 1375 |  | 
|  | 1376 | out: | 
|  | 1377 | kfree(acx); | 
|  | 1378 | return ret; | 
|  | 1379 | } | 
|  | 1380 |  | 
| Levi, Shahar | 4b7fac7 | 2011-01-23 07:27:22 +0100 | [diff] [blame] | 1381 | /* Configure BA session initiator/receiver parameters setting in the FW. */ | 
|  | 1382 | int wl1271_acx_set_ba_session(struct wl1271 *wl, | 
|  | 1383 | enum ieee80211_back_parties direction, | 
|  | 1384 | u8 tid_index, u8 policy) | 
|  | 1385 | { | 
|  | 1386 | struct wl1271_acx_ba_session_policy *acx; | 
|  | 1387 | int ret; | 
|  | 1388 |  | 
|  | 1389 | wl1271_debug(DEBUG_ACX, "acx ba session setting"); | 
|  | 1390 |  | 
|  | 1391 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1392 | if (!acx) { | 
|  | 1393 | ret = -ENOMEM; | 
|  | 1394 | goto out; | 
|  | 1395 | } | 
|  | 1396 |  | 
|  | 1397 | /* ANY role */ | 
|  | 1398 | acx->role_id = 0xff; | 
|  | 1399 | acx->tid = tid_index; | 
|  | 1400 | acx->enable = policy; | 
|  | 1401 | acx->ba_direction = direction; | 
|  | 1402 |  | 
|  | 1403 | switch (direction) { | 
|  | 1404 | case WLAN_BACK_INITIATOR: | 
|  | 1405 | acx->win_size = wl->conf.ht.tx_ba_win_size; | 
|  | 1406 | acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; | 
|  | 1407 | break; | 
|  | 1408 | case WLAN_BACK_RECIPIENT: | 
|  | 1409 | acx->win_size = RX_BA_WIN_SIZE; | 
|  | 1410 | acx->inactivity_timeout = 0; | 
|  | 1411 | break; | 
|  | 1412 | default: | 
|  | 1413 | wl1271_error("Incorrect acx command id=%x\n", direction); | 
|  | 1414 | ret = -EINVAL; | 
|  | 1415 | goto out; | 
|  | 1416 | } | 
|  | 1417 |  | 
|  | 1418 | ret = wl1271_cmd_configure(wl, | 
|  | 1419 | ACX_BA_SESSION_POLICY_CFG, | 
|  | 1420 | acx, | 
|  | 1421 | sizeof(*acx)); | 
|  | 1422 | if (ret < 0) { | 
|  | 1423 | wl1271_warning("acx ba session setting failed: %d", ret); | 
|  | 1424 | goto out; | 
|  | 1425 | } | 
|  | 1426 |  | 
|  | 1427 | out: | 
|  | 1428 | kfree(acx); | 
|  | 1429 | return ret; | 
|  | 1430 | } | 
|  | 1431 |  | 
| Levi, Shahar | bbba3e6 | 2011-01-23 07:27:23 +0100 | [diff] [blame] | 1432 | /* setup BA session receiver setting in the FW. */ | 
|  | 1433 | int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, | 
|  | 1434 | bool enable) | 
|  | 1435 | { | 
|  | 1436 | struct wl1271_acx_ba_receiver_setup *acx; | 
|  | 1437 | int ret; | 
|  | 1438 |  | 
|  | 1439 | wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); | 
|  | 1440 |  | 
|  | 1441 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1442 | if (!acx) { | 
|  | 1443 | ret = -ENOMEM; | 
|  | 1444 | goto out; | 
|  | 1445 | } | 
|  | 1446 |  | 
|  | 1447 | /* Single link for now */ | 
|  | 1448 | acx->link_id = 1; | 
|  | 1449 | acx->tid = tid_index; | 
|  | 1450 | acx->enable = enable; | 
|  | 1451 | acx->win_size = 0; | 
|  | 1452 | acx->ssn = ssn; | 
|  | 1453 |  | 
|  | 1454 | ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, | 
|  | 1455 | sizeof(*acx)); | 
|  | 1456 | if (ret < 0) { | 
|  | 1457 | wl1271_warning("acx ba receiver session failed: %d", ret); | 
|  | 1458 | goto out; | 
|  | 1459 | } | 
|  | 1460 |  | 
|  | 1461 | out: | 
|  | 1462 | kfree(acx); | 
|  | 1463 | return ret; | 
|  | 1464 | } | 
|  | 1465 |  | 
| Juuso Oikarinen | bbbb538 | 2010-07-08 17:49:57 +0300 | [diff] [blame] | 1466 | int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) | 
|  | 1467 | { | 
|  | 1468 | struct wl1271_acx_fw_tsf_information *tsf_info; | 
|  | 1469 | int ret; | 
|  | 1470 |  | 
|  | 1471 | tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); | 
|  | 1472 | if (!tsf_info) { | 
|  | 1473 | ret = -ENOMEM; | 
|  | 1474 | goto out; | 
|  | 1475 | } | 
|  | 1476 |  | 
|  | 1477 | ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, | 
|  | 1478 | tsf_info, sizeof(*tsf_info)); | 
|  | 1479 | if (ret < 0) { | 
|  | 1480 | wl1271_warning("acx tsf info interrogate failed"); | 
|  | 1481 | goto out; | 
|  | 1482 | } | 
|  | 1483 |  | 
|  | 1484 | *mactime = le32_to_cpu(tsf_info->current_tsf_low) | | 
|  | 1485 | ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32); | 
|  | 1486 |  | 
|  | 1487 | out: | 
|  | 1488 | kfree(tsf_info); | 
|  | 1489 | return ret; | 
|  | 1490 | } | 
| Arik Nemtsov | 79b223f | 2010-10-16 17:52:59 +0200 | [diff] [blame] | 1491 |  | 
|  | 1492 | int wl1271_acx_max_tx_retry(struct wl1271 *wl) | 
|  | 1493 | { | 
|  | 1494 | struct wl1271_acx_max_tx_retry *acx = NULL; | 
|  | 1495 | int ret; | 
|  | 1496 |  | 
|  | 1497 | wl1271_debug(DEBUG_ACX, "acx max tx retry"); | 
|  | 1498 |  | 
|  | 1499 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1500 | if (!acx) | 
|  | 1501 | return -ENOMEM; | 
|  | 1502 |  | 
|  | 1503 | acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); | 
|  | 1504 |  | 
|  | 1505 | ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); | 
|  | 1506 | if (ret < 0) { | 
|  | 1507 | wl1271_warning("acx max tx retry failed: %d", ret); | 
|  | 1508 | goto out; | 
|  | 1509 | } | 
|  | 1510 |  | 
|  | 1511 | out: | 
|  | 1512 | kfree(acx); | 
|  | 1513 | return ret; | 
|  | 1514 | } | 
| Eliad Peller | ee60833 | 2011-02-02 09:59:34 +0200 | [diff] [blame] | 1515 |  | 
|  | 1516 | int wl1271_acx_config_ps(struct wl1271 *wl) | 
|  | 1517 | { | 
|  | 1518 | struct wl1271_acx_config_ps *config_ps; | 
|  | 1519 | int ret; | 
|  | 1520 |  | 
|  | 1521 | wl1271_debug(DEBUG_ACX, "acx config ps"); | 
|  | 1522 |  | 
|  | 1523 | config_ps = kzalloc(sizeof(*config_ps), GFP_KERNEL); | 
|  | 1524 | if (!config_ps) { | 
|  | 1525 | ret = -ENOMEM; | 
|  | 1526 | goto out; | 
|  | 1527 | } | 
|  | 1528 |  | 
|  | 1529 | config_ps->exit_retries = wl->conf.conn.psm_exit_retries; | 
|  | 1530 | config_ps->enter_retries = wl->conf.conn.psm_entry_retries; | 
|  | 1531 | config_ps->null_data_rate = cpu_to_le32(wl->basic_rate); | 
|  | 1532 |  | 
|  | 1533 | ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps, | 
|  | 1534 | sizeof(*config_ps)); | 
|  | 1535 |  | 
|  | 1536 | if (ret < 0) { | 
|  | 1537 | wl1271_warning("acx config ps failed: %d", ret); | 
|  | 1538 | goto out; | 
|  | 1539 | } | 
|  | 1540 |  | 
|  | 1541 | out: | 
|  | 1542 | kfree(config_ps); | 
|  | 1543 | return ret; | 
|  | 1544 | } | 
| Arik Nemtsov | 99a2775 | 2011-02-23 00:22:25 +0200 | [diff] [blame] | 1545 |  | 
|  | 1546 | int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr) | 
|  | 1547 | { | 
|  | 1548 | struct wl1271_acx_inconnection_sta *acx = NULL; | 
|  | 1549 | int ret; | 
|  | 1550 |  | 
|  | 1551 | wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr); | 
|  | 1552 |  | 
|  | 1553 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | 
|  | 1554 | if (!acx) | 
|  | 1555 | return -ENOMEM; | 
|  | 1556 |  | 
|  | 1557 | memcpy(acx->addr, addr, ETH_ALEN); | 
|  | 1558 |  | 
|  | 1559 | ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST, | 
|  | 1560 | acx, sizeof(*acx)); | 
|  | 1561 | if (ret < 0) { | 
|  | 1562 | wl1271_warning("acx set inconnaction sta failed: %d", ret); | 
|  | 1563 | goto out; | 
|  | 1564 | } | 
|  | 1565 |  | 
|  | 1566 | out: | 
|  | 1567 | kfree(acx); | 
|  | 1568 | return ret; | 
|  | 1569 | } |