diff options
Diffstat (limited to 'drivers/net/wireless/wl1251')
29 files changed, 10680 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl1251/Kconfig b/drivers/net/wireless/wl1251/Kconfig new file mode 100644 index 00000000000..1fb65849414 --- /dev/null +++ b/drivers/net/wireless/wl1251/Kconfig | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | menuconfig WL1251 | ||
| 2 | tristate "TI wl1251 driver support" | ||
| 3 | depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS | ||
| 4 | select FW_LOADER | ||
| 5 | select CRC7 | ||
| 6 | ---help--- | ||
| 7 | This will enable TI wl1251 driver support. The drivers make | ||
| 8 | use of the mac80211 stack. | ||
| 9 | |||
| 10 | If you choose to build a module, it'll be called wl1251. Say | ||
| 11 | N if unsure. | ||
| 12 | |||
| 13 | config WL1251_SPI | ||
| 14 | tristate "TI wl1251 SPI support" | ||
| 15 | depends on WL1251 && SPI_MASTER | ||
| 16 | ---help--- | ||
| 17 | This module adds support for the SPI interface of adapters using | ||
| 18 | TI wl1251 chipset. Select this if your platform is using | ||
| 19 | the SPI bus. | ||
| 20 | |||
| 21 | If you choose to build a module, it'll be called wl1251_spi. | ||
| 22 | Say N if unsure. | ||
| 23 | |||
| 24 | config WL1251_SDIO | ||
| 25 | tristate "TI wl1251 SDIO support" | ||
| 26 | depends on WL1251 && MMC | ||
| 27 | ---help--- | ||
| 28 | This module adds support for the SDIO interface of adapters using | ||
| 29 | TI wl1251 chipset. Select this if your platform is using | ||
| 30 | the SDIO bus. | ||
| 31 | |||
| 32 | If you choose to build a module, it'll be called | ||
| 33 | wl1251_sdio. Say N if unsure. | ||
diff --git a/drivers/net/wireless/wl1251/Makefile b/drivers/net/wireless/wl1251/Makefile new file mode 100644 index 00000000000..58b4f935a3f --- /dev/null +++ b/drivers/net/wireless/wl1251/Makefile | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | wl1251-objs = main.o event.o tx.o rx.o ps.o cmd.o \ | ||
| 2 | acx.o boot.o init.o debugfs.o io.o | ||
| 3 | wl1251_spi-objs += spi.o | ||
| 4 | wl1251_sdio-objs += sdio.o | ||
| 5 | |||
| 6 | obj-$(CONFIG_WL1251) += wl1251.o | ||
| 7 | obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o | ||
| 8 | obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o | ||
diff --git a/drivers/net/wireless/wl1251/acx.c b/drivers/net/wireless/wl1251/acx.c new file mode 100644 index 00000000000..ad87a1ac646 --- /dev/null +++ b/drivers/net/wireless/wl1251/acx.c | |||
| @@ -0,0 +1,1097 @@ | |||
| 1 | #include "acx.h" | ||
| 2 | |||
| 3 | #include <linux/module.h> | ||
| 4 | #include <linux/slab.h> | ||
| 5 | #include <linux/crc7.h> | ||
| 6 | |||
| 7 | #include "wl1251.h" | ||
| 8 | #include "reg.h" | ||
| 9 | #include "cmd.h" | ||
| 10 | #include "ps.h" | ||
| 11 | |||
| 12 | int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, | ||
| 13 | u8 mgt_rate, u8 mgt_mod) | ||
| 14 | { | ||
| 15 | struct acx_fw_gen_frame_rates *rates; | ||
| 16 | int ret; | ||
| 17 | |||
| 18 | wl1251_debug(DEBUG_ACX, "acx frame rates"); | ||
| 19 | |||
| 20 | rates = kzalloc(sizeof(*rates), GFP_KERNEL); | ||
| 21 | if (!rates) { | ||
| 22 | ret = -ENOMEM; | ||
| 23 | goto out; | ||
| 24 | } | ||
| 25 | |||
| 26 | rates->tx_ctrl_frame_rate = ctrl_rate; | ||
| 27 | rates->tx_ctrl_frame_mod = ctrl_mod; | ||
| 28 | rates->tx_mgt_frame_rate = mgt_rate; | ||
| 29 | rates->tx_mgt_frame_mod = mgt_mod; | ||
| 30 | |||
| 31 | ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES, | ||
| 32 | rates, sizeof(*rates)); | ||
| 33 | if (ret < 0) { | ||
| 34 | wl1251_error("Failed to set FW rates and modulation"); | ||
| 35 | goto out; | ||
| 36 | } | ||
| 37 | |||
| 38 | out: | ||
| 39 | kfree(rates); | ||
| 40 | return ret; | ||
| 41 | } | ||
| 42 | |||
| 43 | |||
| 44 | int wl1251_acx_station_id(struct wl1251 *wl) | ||
| 45 | { | ||
| 46 | struct acx_dot11_station_id *mac; | ||
| 47 | int ret, i; | ||
| 48 | |||
| 49 | wl1251_debug(DEBUG_ACX, "acx dot11_station_id"); | ||
| 50 | |||
| 51 | mac = kzalloc(sizeof(*mac), GFP_KERNEL); | ||
| 52 | if (!mac) { | ||
| 53 | ret = -ENOMEM; | ||
| 54 | goto out; | ||
| 55 | } | ||
| 56 | |||
| 57 | for (i = 0; i < ETH_ALEN; i++) | ||
| 58 | mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i]; | ||
| 59 | |||
| 60 | ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac)); | ||
| 61 | if (ret < 0) | ||
| 62 | goto out; | ||
| 63 | |||
| 64 | out: | ||
| 65 | kfree(mac); | ||
| 66 | return ret; | ||
| 67 | } | ||
| 68 | |||
| 69 | int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id) | ||
| 70 | { | ||
| 71 | struct acx_dot11_default_key *default_key; | ||
| 72 | int ret; | ||
| 73 | |||
| 74 | wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id); | ||
| 75 | |||
| 76 | default_key = kzalloc(sizeof(*default_key), GFP_KERNEL); | ||
| 77 | if (!default_key) { | ||
| 78 | ret = -ENOMEM; | ||
| 79 | goto out; | ||
| 80 | } | ||
| 81 | |||
| 82 | default_key->id = key_id; | ||
| 83 | |||
| 84 | ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, | ||
| 85 | default_key, sizeof(*default_key)); | ||
| 86 | if (ret < 0) { | ||
| 87 | wl1251_error("Couldn't set default key"); | ||
| 88 | goto out; | ||
| 89 | } | ||
| 90 | |||
| 91 | wl->default_key = key_id; | ||
| 92 | |||
| 93 | out: | ||
| 94 | kfree(default_key); | ||
| 95 | return ret; | ||
| 96 | } | ||
| 97 | |||
| 98 | int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, | ||
| 99 | u8 listen_interval) | ||
| 100 | { | ||
| 101 | struct acx_wake_up_condition *wake_up; | ||
| 102 | int ret; | ||
| 103 | |||
| 104 | wl1251_debug(DEBUG_ACX, "acx wake up conditions"); | ||
| 105 | |||
| 106 | wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); | ||
| 107 | if (!wake_up) { | ||
| 108 | ret = -ENOMEM; | ||
| 109 | goto out; | ||
| 110 | } | ||
| 111 | |||
| 112 | wake_up->wake_up_event = wake_up_event; | ||
| 113 | wake_up->listen_interval = listen_interval; | ||
| 114 | |||
| 115 | ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, | ||
| 116 | wake_up, sizeof(*wake_up)); | ||
| 117 | if (ret < 0) { | ||
| 118 | wl1251_warning("could not set wake up conditions: %d", ret); | ||
| 119 | goto out; | ||
| 120 | } | ||
| 121 | |||
| 122 | out: | ||
| 123 | kfree(wake_up); | ||
| 124 | return ret; | ||
| 125 | } | ||
| 126 | |||
| 127 | int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth) | ||
| 128 | { | ||
| 129 | struct acx_sleep_auth *auth; | ||
| 130 | int ret; | ||
| 131 | |||
| 132 | wl1251_debug(DEBUG_ACX, "acx sleep auth"); | ||
| 133 | |||
| 134 | auth = kzalloc(sizeof(*auth), GFP_KERNEL); | ||
| 135 | if (!auth) { | ||
| 136 | ret = -ENOMEM; | ||
| 137 | goto out; | ||
| 138 | } | ||
| 139 | |||
| 140 | auth->sleep_auth = sleep_auth; | ||
| 141 | |||
| 142 | ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); | ||
| 143 | |||
| 144 | out: | ||
| 145 | kfree(auth); | ||
| 146 | return ret; | ||
| 147 | } | ||
| 148 | |||
| 149 | int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len) | ||
| 150 | { | ||
| 151 | struct acx_revision *rev; | ||
| 152 | int ret; | ||
| 153 | |||
| 154 | wl1251_debug(DEBUG_ACX, "acx fw rev"); | ||
| 155 | |||
| 156 | rev = kzalloc(sizeof(*rev), GFP_KERNEL); | ||
| 157 | if (!rev) { | ||
| 158 | ret = -ENOMEM; | ||
| 159 | goto out; | ||
| 160 | } | ||
| 161 | |||
| 162 | ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev)); | ||
| 163 | if (ret < 0) { | ||
| 164 | wl1251_warning("ACX_FW_REV interrogate failed"); | ||
| 165 | goto out; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* be careful with the buffer sizes */ | ||
| 169 | strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version))); | ||
| 170 | |||
| 171 | /* | ||
| 172 | * if the firmware version string is exactly | ||
| 173 | * sizeof(rev->fw_version) long or fw_len is less than | ||
| 174 | * sizeof(rev->fw_version) it won't be null terminated | ||
| 175 | */ | ||
| 176 | buf[min(len, sizeof(rev->fw_version)) - 1] = '\0'; | ||
| 177 | |||
| 178 | out: | ||
| 179 | kfree(rev); | ||
| 180 | return ret; | ||
| 181 | } | ||
| 182 | |||
| 183 | int wl1251_acx_tx_power(struct wl1251 *wl, int power) | ||
| 184 | { | ||
| 185 | struct acx_current_tx_power *acx; | ||
| 186 | int ret; | ||
| 187 | |||
| 188 | wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr"); | ||
| 189 | |||
| 190 | if (power < 0 || power > 25) | ||
| 191 | return -EINVAL; | ||
| 192 | |||
| 193 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 194 | if (!acx) { | ||
| 195 | ret = -ENOMEM; | ||
| 196 | goto out; | ||
| 197 | } | ||
| 198 | |||
| 199 | acx->current_tx_power = power * 10; | ||
| 200 | |||
| 201 | ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); | ||
| 202 | if (ret < 0) { | ||
| 203 | wl1251_warning("configure of tx power failed: %d", ret); | ||
| 204 | goto out; | ||
| 205 | } | ||
| 206 | |||
| 207 | out: | ||
| 208 | kfree(acx); | ||
| 209 | return ret; | ||
| 210 | } | ||
| 211 | |||
| 212 | int wl1251_acx_feature_cfg(struct wl1251 *wl) | ||
| 213 | { | ||
| 214 | struct acx_feature_config *feature; | ||
| 215 | int ret; | ||
| 216 | |||
| 217 | wl1251_debug(DEBUG_ACX, "acx feature cfg"); | ||
| 218 | |||
| 219 | feature = kzalloc(sizeof(*feature), GFP_KERNEL); | ||
| 220 | if (!feature) { | ||
| 221 | ret = -ENOMEM; | ||
| 222 | goto out; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ | ||
| 226 | feature->data_flow_options = 0; | ||
| 227 | feature->options = 0; | ||
| 228 | |||
| 229 | ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, | ||
| 230 | feature, sizeof(*feature)); | ||
| 231 | if (ret < 0) { | ||
| 232 | wl1251_error("Couldn't set HW encryption"); | ||
| 233 | goto out; | ||
| 234 | } | ||
| 235 | |||
| 236 | out: | ||
| 237 | kfree(feature); | ||
| 238 | return ret; | ||
| 239 | } | ||
| 240 | |||
| 241 | int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, | ||
| 242 | size_t len) | ||
| 243 | { | ||
| 244 | int ret; | ||
| 245 | |||
| 246 | wl1251_debug(DEBUG_ACX, "acx mem map"); | ||
| 247 | |||
| 248 | ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); | ||
| 249 | if (ret < 0) | ||
| 250 | return ret; | ||
| 251 | |||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | int wl1251_acx_data_path_params(struct wl1251 *wl, | ||
| 256 | struct acx_data_path_params_resp *resp) | ||
| 257 | { | ||
| 258 | struct acx_data_path_params *params; | ||
| 259 | int ret; | ||
| 260 | |||
| 261 | wl1251_debug(DEBUG_ACX, "acx data path params"); | ||
| 262 | |||
| 263 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
| 264 | if (!params) { | ||
| 265 | ret = -ENOMEM; | ||
| 266 | goto out; | ||
| 267 | } | ||
| 268 | |||
| 269 | params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE; | ||
| 270 | params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE; | ||
| 271 | |||
| 272 | params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM; | ||
| 273 | params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM; | ||
| 274 | |||
| 275 | params->tx_complete_threshold = 1; | ||
| 276 | |||
| 277 | params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE; | ||
| 278 | |||
| 279 | params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT; | ||
| 280 | |||
| 281 | ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS, | ||
| 282 | params, sizeof(*params)); | ||
| 283 | if (ret < 0) | ||
| 284 | goto out; | ||
| 285 | |||
| 286 | /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */ | ||
| 287 | ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS, | ||
| 288 | resp, sizeof(*resp)); | ||
| 289 | |||
| 290 | if (ret < 0) { | ||
| 291 | wl1251_warning("failed to read data path parameters: %d", ret); | ||
| 292 | goto out; | ||
| 293 | } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) { | ||
| 294 | wl1251_warning("data path parameter acx status failed"); | ||
| 295 | ret = -EIO; | ||
| 296 | goto out; | ||
| 297 | } | ||
| 298 | |||
| 299 | out: | ||
| 300 | kfree(params); | ||
| 301 | return ret; | ||
| 302 | } | ||
| 303 | |||
| 304 | int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time) | ||
| 305 | { | ||
| 306 | struct acx_rx_msdu_lifetime *acx; | ||
| 307 | int ret; | ||
| 308 | |||
| 309 | wl1251_debug(DEBUG_ACX, "acx rx msdu life time"); | ||
| 310 | |||
| 311 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 312 | if (!acx) { | ||
| 313 | ret = -ENOMEM; | ||
| 314 | goto out; | ||
| 315 | } | ||
| 316 | |||
| 317 | acx->lifetime = life_time; | ||
| 318 | ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, | ||
| 319 | acx, sizeof(*acx)); | ||
| 320 | if (ret < 0) { | ||
| 321 | wl1251_warning("failed to set rx msdu life time: %d", ret); | ||
| 322 | goto out; | ||
| 323 | } | ||
| 324 | |||
| 325 | out: | ||
| 326 | kfree(acx); | ||
| 327 | return ret; | ||
| 328 | } | ||
| 329 | |||
| 330 | int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter) | ||
| 331 | { | ||
| 332 | struct acx_rx_config *rx_config; | ||
| 333 | int ret; | ||
| 334 | |||
| 335 | wl1251_debug(DEBUG_ACX, "acx rx config"); | ||
| 336 | |||
| 337 | rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); | ||
| 338 | if (!rx_config) { | ||
| 339 | ret = -ENOMEM; | ||
| 340 | goto out; | ||
| 341 | } | ||
| 342 | |||
| 343 | rx_config->config_options = config; | ||
| 344 | rx_config->filter_options = filter; | ||
| 345 | |||
| 346 | ret = wl1251_cmd_configure(wl, ACX_RX_CFG, | ||
| 347 | rx_config, sizeof(*rx_config)); | ||
| 348 | if (ret < 0) { | ||
| 349 | wl1251_warning("failed to set rx config: %d", ret); | ||
| 350 | goto out; | ||
| 351 | } | ||
| 352 | |||
| 353 | out: | ||
| 354 | kfree(rx_config); | ||
| 355 | return ret; | ||
| 356 | } | ||
| 357 | |||
| 358 | int wl1251_acx_pd_threshold(struct wl1251 *wl) | ||
| 359 | { | ||
| 360 | struct acx_packet_detection *pd; | ||
| 361 | int ret; | ||
| 362 | |||
| 363 | wl1251_debug(DEBUG_ACX, "acx data pd threshold"); | ||
| 364 | |||
| 365 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | ||
| 366 | if (!pd) { | ||
| 367 | ret = -ENOMEM; | ||
| 368 | goto out; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* FIXME: threshold value not set */ | ||
| 372 | |||
| 373 | ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); | ||
| 374 | if (ret < 0) { | ||
| 375 | wl1251_warning("failed to set pd threshold: %d", ret); | ||
| 376 | goto out; | ||
| 377 | } | ||
| 378 | |||
| 379 | out: | ||
| 380 | kfree(pd); | ||
| 381 | return ret; | ||
| 382 | } | ||
| 383 | |||
| 384 | int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time) | ||
| 385 | { | ||
| 386 | struct acx_slot *slot; | ||
| 387 | int ret; | ||
| 388 | |||
| 389 | wl1251_debug(DEBUG_ACX, "acx slot"); | ||
| 390 | |||
| 391 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
| 392 | if (!slot) { | ||
| 393 | ret = -ENOMEM; | ||
| 394 | goto out; | ||
| 395 | } | ||
| 396 | |||
| 397 | slot->wone_index = STATION_WONE_INDEX; | ||
| 398 | slot->slot_time = slot_time; | ||
| 399 | |||
| 400 | ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); | ||
| 401 | if (ret < 0) { | ||
| 402 | wl1251_warning("failed to set slot time: %d", ret); | ||
| 403 | goto out; | ||
| 404 | } | ||
| 405 | |||
| 406 | out: | ||
| 407 | kfree(slot); | ||
| 408 | return ret; | ||
| 409 | } | ||
| 410 | |||
| 411 | int wl1251_acx_group_address_tbl(struct wl1251 *wl) | ||
| 412 | { | ||
| 413 | struct acx_dot11_grp_addr_tbl *acx; | ||
| 414 | int ret; | ||
| 415 | |||
| 416 | wl1251_debug(DEBUG_ACX, "acx group address tbl"); | ||
| 417 | |||
| 418 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 419 | if (!acx) { | ||
| 420 | ret = -ENOMEM; | ||
| 421 | goto out; | ||
| 422 | } | ||
| 423 | |||
| 424 | /* MAC filtering */ | ||
| 425 | acx->enabled = 0; | ||
| 426 | acx->num_groups = 0; | ||
| 427 | memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); | ||
| 428 | |||
| 429 | ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, | ||
| 430 | acx, sizeof(*acx)); | ||
| 431 | if (ret < 0) { | ||
| 432 | wl1251_warning("failed to set group addr table: %d", ret); | ||
| 433 | goto out; | ||
| 434 | } | ||
| 435 | |||
| 436 | out: | ||
| 437 | kfree(acx); | ||
| 438 | return ret; | ||
| 439 | } | ||
| 440 | |||
| 441 | int wl1251_acx_service_period_timeout(struct wl1251 *wl) | ||
| 442 | { | ||
| 443 | struct acx_rx_timeout *rx_timeout; | ||
| 444 | int ret; | ||
| 445 | |||
| 446 | rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); | ||
| 447 | if (!rx_timeout) { | ||
| 448 | ret = -ENOMEM; | ||
| 449 | goto out; | ||
| 450 | } | ||
| 451 | |||
| 452 | wl1251_debug(DEBUG_ACX, "acx service period timeout"); | ||
| 453 | |||
| 454 | rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; | ||
| 455 | rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; | ||
| 456 | |||
| 457 | ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, | ||
| 458 | rx_timeout, sizeof(*rx_timeout)); | ||
| 459 | if (ret < 0) { | ||
| 460 | wl1251_warning("failed to set service period timeout: %d", | ||
| 461 | ret); | ||
| 462 | goto out; | ||
| 463 | } | ||
| 464 | |||
| 465 | out: | ||
| 466 | kfree(rx_timeout); | ||
| 467 | return ret; | ||
| 468 | } | ||
| 469 | |||
| 470 | int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold) | ||
| 471 | { | ||
| 472 | struct acx_rts_threshold *rts; | ||
| 473 | int ret; | ||
| 474 | |||
| 475 | wl1251_debug(DEBUG_ACX, "acx rts threshold"); | ||
| 476 | |||
| 477 | rts = kzalloc(sizeof(*rts), GFP_KERNEL); | ||
| 478 | if (!rts) { | ||
| 479 | ret = -ENOMEM; | ||
| 480 | goto out; | ||
| 481 | } | ||
| 482 | |||
| 483 | rts->threshold = rts_threshold; | ||
| 484 | |||
| 485 | ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); | ||
| 486 | if (ret < 0) { | ||
| 487 | wl1251_warning("failed to set rts threshold: %d", ret); | ||
| 488 | goto out; | ||
| 489 | } | ||
| 490 | |||
| 491 | out: | ||
| 492 | kfree(rts); | ||
| 493 | return ret; | ||
| 494 | } | ||
| 495 | |||
| 496 | int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter) | ||
| 497 | { | ||
| 498 | struct acx_beacon_filter_option *beacon_filter; | ||
| 499 | int ret; | ||
| 500 | |||
| 501 | wl1251_debug(DEBUG_ACX, "acx beacon filter opt"); | ||
| 502 | |||
| 503 | beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); | ||
| 504 | if (!beacon_filter) { | ||
| 505 | ret = -ENOMEM; | ||
| 506 | goto out; | ||
| 507 | } | ||
| 508 | |||
| 509 | beacon_filter->enable = enable_filter; | ||
| 510 | beacon_filter->max_num_beacons = 0; | ||
| 511 | |||
| 512 | ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, | ||
| 513 | beacon_filter, sizeof(*beacon_filter)); | ||
| 514 | if (ret < 0) { | ||
| 515 | wl1251_warning("failed to set beacon filter opt: %d", ret); | ||
| 516 | goto out; | ||
| 517 | } | ||
| 518 | |||
| 519 | out: | ||
| 520 | kfree(beacon_filter); | ||
| 521 | return ret; | ||
| 522 | } | ||
| 523 | |||
| 524 | int wl1251_acx_beacon_filter_table(struct wl1251 *wl) | ||
| 525 | { | ||
| 526 | struct acx_beacon_filter_ie_table *ie_table; | ||
| 527 | int idx = 0; | ||
| 528 | int ret; | ||
| 529 | |||
| 530 | wl1251_debug(DEBUG_ACX, "acx beacon filter table"); | ||
| 531 | |||
| 532 | ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); | ||
| 533 | if (!ie_table) { | ||
| 534 | ret = -ENOMEM; | ||
| 535 | goto out; | ||
| 536 | } | ||
| 537 | |||
| 538 | /* configure default beacon pass-through rules */ | ||
| 539 | ie_table->num_ie = 1; | ||
| 540 | ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; | ||
| 541 | ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; | ||
| 542 | |||
| 543 | ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, | ||
| 544 | ie_table, sizeof(*ie_table)); | ||
| 545 | if (ret < 0) { | ||
| 546 | wl1251_warning("failed to set beacon filter table: %d", ret); | ||
| 547 | goto out; | ||
| 548 | } | ||
| 549 | |||
| 550 | out: | ||
| 551 | kfree(ie_table); | ||
| 552 | return ret; | ||
| 553 | } | ||
| 554 | |||
| 555 | int wl1251_acx_conn_monit_params(struct wl1251 *wl) | ||
| 556 | { | ||
| 557 | struct acx_conn_monit_params *acx; | ||
| 558 | int ret; | ||
| 559 | |||
| 560 | wl1251_debug(DEBUG_ACX, "acx connection monitor parameters"); | ||
| 561 | |||
| 562 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 563 | if (!acx) { | ||
| 564 | ret = -ENOMEM; | ||
| 565 | goto out; | ||
| 566 | } | ||
| 567 | |||
| 568 | acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; | ||
| 569 | acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; | ||
| 570 | |||
| 571 | ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, | ||
| 572 | acx, sizeof(*acx)); | ||
| 573 | if (ret < 0) { | ||
| 574 | wl1251_warning("failed to set connection monitor " | ||
| 575 | "parameters: %d", ret); | ||
| 576 | goto out; | ||
| 577 | } | ||
| 578 | |||
| 579 | out: | ||
| 580 | kfree(acx); | ||
| 581 | return ret; | ||
| 582 | } | ||
| 583 | |||
| 584 | int wl1251_acx_sg_enable(struct wl1251 *wl) | ||
| 585 | { | ||
| 586 | struct acx_bt_wlan_coex *pta; | ||
| 587 | int ret; | ||
| 588 | |||
| 589 | wl1251_debug(DEBUG_ACX, "acx sg enable"); | ||
| 590 | |||
| 591 | pta = kzalloc(sizeof(*pta), GFP_KERNEL); | ||
| 592 | if (!pta) { | ||
| 593 | ret = -ENOMEM; | ||
| 594 | goto out; | ||
| 595 | } | ||
| 596 | |||
| 597 | pta->enable = SG_ENABLE; | ||
| 598 | |||
| 599 | ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); | ||
| 600 | if (ret < 0) { | ||
| 601 | wl1251_warning("failed to set softgemini enable: %d", ret); | ||
| 602 | goto out; | ||
| 603 | } | ||
| 604 | |||
| 605 | out: | ||
| 606 | kfree(pta); | ||
| 607 | return ret; | ||
| 608 | } | ||
| 609 | |||
| 610 | int wl1251_acx_sg_cfg(struct wl1251 *wl) | ||
| 611 | { | ||
| 612 | struct acx_bt_wlan_coex_param *param; | ||
| 613 | int ret; | ||
| 614 | |||
| 615 | wl1251_debug(DEBUG_ACX, "acx sg cfg"); | ||
| 616 | |||
| 617 | param = kzalloc(sizeof(*param), GFP_KERNEL); | ||
| 618 | if (!param) { | ||
| 619 | ret = -ENOMEM; | ||
| 620 | goto out; | ||
| 621 | } | ||
| 622 | |||
| 623 | /* BT-WLAN coext parameters */ | ||
| 624 | param->min_rate = RATE_INDEX_24MBPS; | ||
| 625 | param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; | ||
| 626 | param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; | ||
| 627 | param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; | ||
| 628 | param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; | ||
| 629 | param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; | ||
| 630 | param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; | ||
| 631 | param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; | ||
| 632 | param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; | ||
| 633 | param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; | ||
| 634 | param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; | ||
| 635 | param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; | ||
| 636 | param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; | ||
| 637 | param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; | ||
| 638 | param->antenna_type = PTA_ANTENNA_TYPE_DEF; | ||
| 639 | param->signal_type = PTA_SIGNALING_TYPE_DEF; | ||
| 640 | param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; | ||
| 641 | param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; | ||
| 642 | param->max_cts = PTA_MAX_NUM_CTS_DEF; | ||
| 643 | param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; | ||
| 644 | param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; | ||
| 645 | param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; | ||
| 646 | param->wlan_elp_hp = PTA_ELP_HP_DEF; | ||
| 647 | param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; | ||
| 648 | param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; | ||
| 649 | param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; | ||
| 650 | param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; | ||
| 651 | param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; | ||
| 652 | |||
| 653 | ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); | ||
| 654 | if (ret < 0) { | ||
| 655 | wl1251_warning("failed to set sg config: %d", ret); | ||
| 656 | goto out; | ||
| 657 | } | ||
| 658 | |||
| 659 | out: | ||
| 660 | kfree(param); | ||
| 661 | return ret; | ||
| 662 | } | ||
| 663 | |||
| 664 | int wl1251_acx_cca_threshold(struct wl1251 *wl) | ||
| 665 | { | ||
| 666 | struct acx_energy_detection *detection; | ||
| 667 | int ret; | ||
| 668 | |||
| 669 | wl1251_debug(DEBUG_ACX, "acx cca threshold"); | ||
| 670 | |||
| 671 | detection = kzalloc(sizeof(*detection), GFP_KERNEL); | ||
| 672 | if (!detection) { | ||
| 673 | ret = -ENOMEM; | ||
| 674 | goto out; | ||
| 675 | } | ||
| 676 | |||
| 677 | detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; | ||
| 678 | detection->tx_energy_detection = 0; | ||
| 679 | |||
| 680 | ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD, | ||
| 681 | detection, sizeof(*detection)); | ||
| 682 | if (ret < 0) | ||
| 683 | wl1251_warning("failed to set cca threshold: %d", ret); | ||
| 684 | |||
| 685 | out: | ||
| 686 | kfree(detection); | ||
| 687 | return ret; | ||
| 688 | } | ||
| 689 | |||
| 690 | int wl1251_acx_bcn_dtim_options(struct wl1251 *wl) | ||
| 691 | { | ||
| 692 | struct acx_beacon_broadcast *bb; | ||
| 693 | int ret; | ||
| 694 | |||
| 695 | wl1251_debug(DEBUG_ACX, "acx bcn dtim options"); | ||
| 696 | |||
| 697 | bb = kzalloc(sizeof(*bb), GFP_KERNEL); | ||
| 698 | if (!bb) { | ||
| 699 | ret = -ENOMEM; | ||
| 700 | goto out; | ||
| 701 | } | ||
| 702 | |||
| 703 | bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; | ||
| 704 | bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; | ||
| 705 | bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; | ||
| 706 | bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; | ||
| 707 | |||
| 708 | ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); | ||
| 709 | if (ret < 0) { | ||
| 710 | wl1251_warning("failed to set rx config: %d", ret); | ||
| 711 | goto out; | ||
| 712 | } | ||
| 713 | |||
| 714 | out: | ||
| 715 | kfree(bb); | ||
| 716 | return ret; | ||
| 717 | } | ||
| 718 | |||
| 719 | int wl1251_acx_aid(struct wl1251 *wl, u16 aid) | ||
| 720 | { | ||
| 721 | struct acx_aid *acx_aid; | ||
| 722 | int ret; | ||
| 723 | |||
| 724 | wl1251_debug(DEBUG_ACX, "acx aid"); | ||
| 725 | |||
| 726 | acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); | ||
| 727 | if (!acx_aid) { | ||
| 728 | ret = -ENOMEM; | ||
| 729 | goto out; | ||
| 730 | } | ||
| 731 | |||
| 732 | acx_aid->aid = aid; | ||
| 733 | |||
| 734 | ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); | ||
| 735 | if (ret < 0) { | ||
| 736 | wl1251_warning("failed to set aid: %d", ret); | ||
| 737 | goto out; | ||
| 738 | } | ||
| 739 | |||
| 740 | out: | ||
| 741 | kfree(acx_aid); | ||
| 742 | return ret; | ||
| 743 | } | ||
| 744 | |||
| 745 | int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask) | ||
| 746 | { | ||
| 747 | struct acx_event_mask *mask; | ||
| 748 | int ret; | ||
| 749 | |||
| 750 | wl1251_debug(DEBUG_ACX, "acx event mbox mask"); | ||
| 751 | |||
| 752 | mask = kzalloc(sizeof(*mask), GFP_KERNEL); | ||
| 753 | if (!mask) { | ||
| 754 | ret = -ENOMEM; | ||
| 755 | goto out; | ||
| 756 | } | ||
| 757 | |||
| 758 | /* high event mask is unused */ | ||
| 759 | mask->high_event_mask = 0xffffffff; | ||
| 760 | |||
| 761 | mask->event_mask = event_mask; | ||
| 762 | |||
| 763 | ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK, | ||
| 764 | mask, sizeof(*mask)); | ||
| 765 | if (ret < 0) { | ||
| 766 | wl1251_warning("failed to set acx_event_mbox_mask: %d", ret); | ||
| 767 | goto out; | ||
| 768 | } | ||
| 769 | |||
| 770 | out: | ||
| 771 | kfree(mask); | ||
| 772 | return ret; | ||
| 773 | } | ||
| 774 | |||
| 775 | int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, | ||
| 776 | u8 depth, enum wl1251_acx_low_rssi_type type) | ||
| 777 | { | ||
| 778 | struct acx_low_rssi *rssi; | ||
| 779 | int ret; | ||
| 780 | |||
| 781 | wl1251_debug(DEBUG_ACX, "acx low rssi"); | ||
| 782 | |||
| 783 | rssi = kzalloc(sizeof(*rssi), GFP_KERNEL); | ||
| 784 | if (!rssi) | ||
| 785 | return -ENOMEM; | ||
| 786 | |||
| 787 | rssi->threshold = threshold; | ||
| 788 | rssi->weight = weight; | ||
| 789 | rssi->depth = depth; | ||
| 790 | rssi->type = type; | ||
| 791 | |||
| 792 | ret = wl1251_cmd_configure(wl, ACX_LOW_RSSI, rssi, sizeof(*rssi)); | ||
| 793 | if (ret < 0) | ||
| 794 | wl1251_warning("failed to set low rssi threshold: %d", ret); | ||
| 795 | |||
| 796 | kfree(rssi); | ||
| 797 | return ret; | ||
| 798 | } | ||
| 799 | |||
| 800 | int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble) | ||
| 801 | { | ||
| 802 | struct acx_preamble *acx; | ||
| 803 | int ret; | ||
| 804 | |||
| 805 | wl1251_debug(DEBUG_ACX, "acx_set_preamble"); | ||
| 806 | |||
| 807 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 808 | if (!acx) { | ||
| 809 | ret = -ENOMEM; | ||
| 810 | goto out; | ||
| 811 | } | ||
| 812 | |||
| 813 | acx->preamble = preamble; | ||
| 814 | |||
| 815 | ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); | ||
| 816 | if (ret < 0) { | ||
| 817 | wl1251_warning("Setting of preamble failed: %d", ret); | ||
| 818 | goto out; | ||
| 819 | } | ||
| 820 | |||
| 821 | out: | ||
| 822 | kfree(acx); | ||
| 823 | return ret; | ||
| 824 | } | ||
| 825 | |||
| 826 | int wl1251_acx_cts_protect(struct wl1251 *wl, | ||
| 827 | enum acx_ctsprotect_type ctsprotect) | ||
| 828 | { | ||
| 829 | struct acx_ctsprotect *acx; | ||
| 830 | int ret; | ||
| 831 | |||
| 832 | wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect"); | ||
| 833 | |||
| 834 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 835 | if (!acx) { | ||
| 836 | ret = -ENOMEM; | ||
| 837 | goto out; | ||
| 838 | } | ||
| 839 | |||
| 840 | acx->ctsprotect = ctsprotect; | ||
| 841 | |||
| 842 | ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); | ||
| 843 | if (ret < 0) { | ||
| 844 | wl1251_warning("Setting of ctsprotect failed: %d", ret); | ||
| 845 | goto out; | ||
| 846 | } | ||
| 847 | |||
| 848 | out: | ||
| 849 | kfree(acx); | ||
| 850 | return ret; | ||
| 851 | } | ||
| 852 | |||
| 853 | int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) | ||
| 854 | { | ||
| 855 | struct acx_tsf_info *tsf_info; | ||
| 856 | int ret; | ||
| 857 | |||
| 858 | tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); | ||
| 859 | if (!tsf_info) { | ||
| 860 | ret = -ENOMEM; | ||
| 861 | goto out; | ||
| 862 | } | ||
| 863 | |||
| 864 | ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO, | ||
| 865 | tsf_info, sizeof(*tsf_info)); | ||
| 866 | if (ret < 0) { | ||
| 867 | wl1251_warning("ACX_FW_REV interrogate failed"); | ||
| 868 | goto out; | ||
| 869 | } | ||
| 870 | |||
| 871 | *mactime = tsf_info->current_tsf_lsb | | ||
| 872 | (tsf_info->current_tsf_msb << 31); | ||
| 873 | |||
| 874 | out: | ||
| 875 | kfree(tsf_info); | ||
| 876 | return ret; | ||
| 877 | } | ||
| 878 | |||
| 879 | int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) | ||
| 880 | { | ||
| 881 | int ret; | ||
| 882 | |||
| 883 | wl1251_debug(DEBUG_ACX, "acx statistics"); | ||
| 884 | |||
| 885 | ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats, | ||
| 886 | sizeof(*stats)); | ||
| 887 | if (ret < 0) { | ||
| 888 | wl1251_warning("acx statistics failed: %d", ret); | ||
| 889 | return -ENOMEM; | ||
| 890 | } | ||
| 891 | |||
| 892 | return 0; | ||
| 893 | } | ||
| 894 | |||
| 895 | int wl1251_acx_rate_policies(struct wl1251 *wl) | ||
| 896 | { | ||
| 897 | struct acx_rate_policy *acx; | ||
| 898 | int ret = 0; | ||
| 899 | |||
| 900 | wl1251_debug(DEBUG_ACX, "acx rate policies"); | ||
| 901 | |||
| 902 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 903 | |||
| 904 | if (!acx) { | ||
| 905 | ret = -ENOMEM; | ||
| 906 | goto out; | ||
| 907 | } | ||
| 908 | |||
| 909 | /* configure one default (one-size-fits-all) rate class */ | ||
| 910 | acx->rate_class_cnt = 1; | ||
| 911 | acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; | ||
| 912 | acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
| 913 | acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; | ||
| 914 | acx->rate_class[0].aflags = 0; | ||
| 915 | |||
| 916 | ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||
| 917 | if (ret < 0) { | ||
| 918 | wl1251_warning("Setting of rate policies failed: %d", ret); | ||
| 919 | goto out; | ||
| 920 | } | ||
| 921 | |||
| 922 | out: | ||
| 923 | kfree(acx); | ||
| 924 | return ret; | ||
| 925 | } | ||
| 926 | |||
| 927 | int wl1251_acx_mem_cfg(struct wl1251 *wl) | ||
| 928 | { | ||
| 929 | struct wl1251_acx_config_memory *mem_conf; | ||
| 930 | int ret, i; | ||
| 931 | |||
| 932 | wl1251_debug(DEBUG_ACX, "acx mem cfg"); | ||
| 933 | |||
| 934 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
| 935 | if (!mem_conf) { | ||
| 936 | ret = -ENOMEM; | ||
| 937 | goto out; | ||
| 938 | } | ||
| 939 | |||
| 940 | /* memory config */ | ||
| 941 | mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
| 942 | mem_conf->mem_config.rx_mem_block_num = 35; | ||
| 943 | mem_conf->mem_config.tx_min_mem_block_num = 64; | ||
| 944 | mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; | ||
| 945 | mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; | ||
| 946 | mem_conf->mem_config.num_ssid_profiles = 1; | ||
| 947 | mem_conf->mem_config.debug_buffer_size = | ||
| 948 | cpu_to_le16(TRACE_BUFFER_MAX_SIZE); | ||
| 949 | |||
| 950 | /* RX queue config */ | ||
| 951 | mem_conf->rx_queue_config.dma_address = 0; | ||
| 952 | mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; | ||
| 953 | mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; | ||
| 954 | mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; | ||
| 955 | |||
| 956 | /* TX queue config */ | ||
| 957 | for (i = 0; i < MAX_TX_QUEUES; i++) { | ||
| 958 | mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; | ||
| 959 | mem_conf->tx_queue_config[i].attributes = i; | ||
| 960 | } | ||
| 961 | |||
| 962 | ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
| 963 | sizeof(*mem_conf)); | ||
| 964 | if (ret < 0) { | ||
| 965 | wl1251_warning("wl1251 mem config failed: %d", ret); | ||
| 966 | goto out; | ||
| 967 | } | ||
| 968 | |||
| 969 | out: | ||
| 970 | kfree(mem_conf); | ||
| 971 | return ret; | ||
| 972 | } | ||
| 973 | |||
| 974 | int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) | ||
| 975 | { | ||
| 976 | struct wl1251_acx_wr_tbtt_and_dtim *acx; | ||
| 977 | int ret; | ||
| 978 | |||
| 979 | wl1251_debug(DEBUG_ACX, "acx tbtt and dtim"); | ||
| 980 | |||
| 981 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 982 | if (!acx) { | ||
| 983 | ret = -ENOMEM; | ||
| 984 | goto out; | ||
| 985 | } | ||
| 986 | |||
| 987 | acx->tbtt = tbtt; | ||
| 988 | acx->dtim = dtim; | ||
| 989 | |||
| 990 | ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM, | ||
| 991 | acx, sizeof(*acx)); | ||
| 992 | if (ret < 0) { | ||
| 993 | wl1251_warning("failed to set tbtt and dtim: %d", ret); | ||
| 994 | goto out; | ||
| 995 | } | ||
| 996 | |||
| 997 | out: | ||
| 998 | kfree(acx); | ||
| 999 | return ret; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, | ||
| 1003 | u8 max_consecutive) | ||
| 1004 | { | ||
| 1005 | struct wl1251_acx_bet_enable *acx; | ||
| 1006 | int ret; | ||
| 1007 | |||
| 1008 | wl1251_debug(DEBUG_ACX, "acx bet enable"); | ||
| 1009 | |||
| 1010 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 1011 | if (!acx) { | ||
| 1012 | ret = -ENOMEM; | ||
| 1013 | goto out; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | acx->enable = mode; | ||
| 1017 | acx->max_consecutive = max_consecutive; | ||
| 1018 | |||
| 1019 | ret = wl1251_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); | ||
| 1020 | if (ret < 0) { | ||
| 1021 | wl1251_warning("wl1251 acx bet enable failed: %d", ret); | ||
| 1022 | goto out; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | out: | ||
| 1026 | kfree(acx); | ||
| 1027 | return ret; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, | ||
| 1031 | u8 aifs, u16 txop) | ||
| 1032 | { | ||
| 1033 | struct wl1251_acx_ac_cfg *acx; | ||
| 1034 | int ret = 0; | ||
| 1035 | |||
| 1036 | wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " | ||
| 1037 | "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop); | ||
| 1038 | |||
| 1039 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 1040 | |||
| 1041 | if (!acx) { | ||
| 1042 | ret = -ENOMEM; | ||
| 1043 | goto out; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | acx->ac = ac; | ||
| 1047 | acx->cw_min = cw_min; | ||
| 1048 | acx->cw_max = cw_max; | ||
| 1049 | acx->aifsn = aifs; | ||
| 1050 | acx->txop_limit = txop; | ||
| 1051 | |||
| 1052 | ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); | ||
| 1053 | if (ret < 0) { | ||
| 1054 | wl1251_warning("acx ac cfg failed: %d", ret); | ||
| 1055 | goto out; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | out: | ||
| 1059 | kfree(acx); | ||
| 1060 | return ret; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, | ||
| 1064 | enum wl1251_acx_channel_type type, | ||
| 1065 | u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, | ||
| 1066 | enum wl1251_acx_ack_policy ack_policy) | ||
| 1067 | { | ||
| 1068 | struct wl1251_acx_tid_cfg *acx; | ||
| 1069 | int ret = 0; | ||
| 1070 | |||
| 1071 | wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d " | ||
| 1072 | "ps_scheme %d ack_policy %d", queue, type, tsid, | ||
| 1073 | ps_scheme, ack_policy); | ||
| 1074 | |||
| 1075 | acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||
| 1076 | |||
| 1077 | if (!acx) { | ||
| 1078 | ret = -ENOMEM; | ||
| 1079 | goto out; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | acx->queue = queue; | ||
| 1083 | acx->type = type; | ||
| 1084 | acx->tsid = tsid; | ||
| 1085 | acx->ps_scheme = ps_scheme; | ||
| 1086 | acx->ack_policy = ack_policy; | ||
| 1087 | |||
| 1088 | ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); | ||
| 1089 | if (ret < 0) { | ||
| 1090 | wl1251_warning("acx tid cfg failed: %d", ret); | ||
| 1091 | goto out; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | out: | ||
| 1095 | kfree(acx); | ||
| 1096 | return ret; | ||
| 1097 | } | ||
diff --git a/drivers/net/wireless/wl1251/acx.h b/drivers/net/wireless/wl1251/acx.h new file mode 100644 index 00000000000..c2ba100f9b1 --- /dev/null +++ b/drivers/net/wireless/wl1251/acx.h | |||
| @@ -0,0 +1,1483 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __WL1251_ACX_H__ | ||
| 24 | #define __WL1251_ACX_H__ | ||
| 25 | |||
| 26 | #include "wl1251.h" | ||
| 27 | #include "cmd.h" | ||
| 28 | |||
| 29 | /* Target's information element */ | ||
| 30 | struct acx_header { | ||
| 31 | struct wl1251_cmd_header cmd; | ||
| 32 | |||
| 33 | /* acx (or information element) header */ | ||
| 34 | u16 id; | ||
| 35 | |||
| 36 | /* payload length (not including headers */ | ||
| 37 | u16 len; | ||
| 38 | } __packed; | ||
| 39 | |||
| 40 | struct acx_error_counter { | ||
| 41 | struct acx_header header; | ||
| 42 | |||
| 43 | /* The number of PLCP errors since the last time this */ | ||
| 44 | /* information element was interrogated. This field is */ | ||
| 45 | /* automatically cleared when it is interrogated.*/ | ||
| 46 | u32 PLCP_error; | ||
| 47 | |||
| 48 | /* The number of FCS errors since the last time this */ | ||
| 49 | /* information element was interrogated. This field is */ | ||
| 50 | /* automatically cleared when it is interrogated.*/ | ||
| 51 | u32 FCS_error; | ||
| 52 | |||
| 53 | /* The number of MPDUs without PLCP header errors received*/ | ||
| 54 | /* since the last time this information element was interrogated. */ | ||
| 55 | /* This field is automatically cleared when it is interrogated.*/ | ||
| 56 | u32 valid_frame; | ||
| 57 | |||
| 58 | /* the number of missed sequence numbers in the squentially */ | ||
| 59 | /* values of frames seq numbers */ | ||
| 60 | u32 seq_num_miss; | ||
| 61 | } __packed; | ||
| 62 | |||
| 63 | struct acx_revision { | ||
| 64 | struct acx_header header; | ||
| 65 | |||
| 66 | /* | ||
| 67 | * The WiLink firmware version, an ASCII string x.x.x.x, | ||
| 68 | * that uniquely identifies the current firmware. | ||
| 69 | * The left most digit is incremented each time a | ||
| 70 | * significant change is made to the firmware, such as | ||
| 71 | * code redesign or new platform support. | ||
| 72 | * The second digit is incremented when major enhancements | ||
| 73 | * are added or major fixes are made. | ||
| 74 | * The third digit is incremented for each GA release. | ||
| 75 | * The fourth digit is incremented for each build. | ||
| 76 | * The first two digits identify a firmware release version, | ||
| 77 | * in other words, a unique set of features. | ||
| 78 | * The first three digits identify a GA release. | ||
| 79 | */ | ||
| 80 | char fw_version[20]; | ||
| 81 | |||
| 82 | /* | ||
| 83 | * This 4 byte field specifies the WiLink hardware version. | ||
| 84 | * bits 0 - 15: Reserved. | ||
| 85 | * bits 16 - 23: Version ID - The WiLink version ID | ||
| 86 | * (1 = first spin, 2 = second spin, and so on). | ||
| 87 | * bits 24 - 31: Chip ID - The WiLink chip ID. | ||
| 88 | */ | ||
| 89 | u32 hw_version; | ||
| 90 | } __packed; | ||
| 91 | |||
| 92 | enum wl1251_psm_mode { | ||
| 93 | /* Active mode */ | ||
| 94 | WL1251_PSM_CAM = 0, | ||
| 95 | |||
| 96 | /* Power save mode */ | ||
| 97 | WL1251_PSM_PS = 1, | ||
| 98 | |||
| 99 | /* Extreme low power */ | ||
| 100 | WL1251_PSM_ELP = 2, | ||
| 101 | }; | ||
| 102 | |||
| 103 | struct acx_sleep_auth { | ||
| 104 | struct acx_header header; | ||
| 105 | |||
| 106 | /* The sleep level authorization of the device. */ | ||
| 107 | /* 0 - Always active*/ | ||
| 108 | /* 1 - Power down mode: light / fast sleep*/ | ||
| 109 | /* 2 - ELP mode: Deep / Max sleep*/ | ||
| 110 | u8 sleep_auth; | ||
| 111 | u8 padding[3]; | ||
| 112 | } __packed; | ||
| 113 | |||
| 114 | enum { | ||
| 115 | HOSTIF_PCI_MASTER_HOST_INDIRECT, | ||
| 116 | HOSTIF_PCI_MASTER_HOST_DIRECT, | ||
| 117 | HOSTIF_SLAVE, | ||
| 118 | HOSTIF_PKT_RING, | ||
| 119 | HOSTIF_DONTCARE = 0xFF | ||
| 120 | }; | ||
| 121 | |||
| 122 | #define DEFAULT_UCAST_PRIORITY 0 | ||
| 123 | #define DEFAULT_RX_Q_PRIORITY 0 | ||
| 124 | #define DEFAULT_NUM_STATIONS 1 | ||
| 125 | #define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ | ||
| 126 | #define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ | ||
| 127 | #define TRACE_BUFFER_MAX_SIZE 256 | ||
| 128 | |||
| 129 | #define DP_RX_PACKET_RING_CHUNK_SIZE 1600 | ||
| 130 | #define DP_TX_PACKET_RING_CHUNK_SIZE 1600 | ||
| 131 | #define DP_RX_PACKET_RING_CHUNK_NUM 2 | ||
| 132 | #define DP_TX_PACKET_RING_CHUNK_NUM 2 | ||
| 133 | #define DP_TX_COMPLETE_TIME_OUT 20 | ||
| 134 | #define FW_TX_CMPLT_BLOCK_SIZE 16 | ||
| 135 | |||
| 136 | struct acx_data_path_params { | ||
| 137 | struct acx_header header; | ||
| 138 | |||
| 139 | u16 rx_packet_ring_chunk_size; | ||
| 140 | u16 tx_packet_ring_chunk_size; | ||
| 141 | |||
| 142 | u8 rx_packet_ring_chunk_num; | ||
| 143 | u8 tx_packet_ring_chunk_num; | ||
| 144 | |||
| 145 | /* | ||
| 146 | * Maximum number of packets that can be gathered | ||
| 147 | * in the TX complete ring before an interrupt | ||
| 148 | * is generated. | ||
| 149 | */ | ||
| 150 | u8 tx_complete_threshold; | ||
| 151 | |||
| 152 | /* Number of pending TX complete entries in cyclic ring.*/ | ||
| 153 | u8 tx_complete_ring_depth; | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Max num microseconds since a packet enters the TX | ||
| 157 | * complete ring until an interrupt is generated. | ||
| 158 | */ | ||
| 159 | u32 tx_complete_timeout; | ||
| 160 | } __packed; | ||
| 161 | |||
| 162 | |||
| 163 | struct acx_data_path_params_resp { | ||
| 164 | struct acx_header header; | ||
| 165 | |||
| 166 | u16 rx_packet_ring_chunk_size; | ||
| 167 | u16 tx_packet_ring_chunk_size; | ||
| 168 | |||
| 169 | u8 rx_packet_ring_chunk_num; | ||
| 170 | u8 tx_packet_ring_chunk_num; | ||
| 171 | |||
| 172 | u8 pad[2]; | ||
| 173 | |||
| 174 | u32 rx_packet_ring_addr; | ||
| 175 | u32 tx_packet_ring_addr; | ||
| 176 | |||
| 177 | u32 rx_control_addr; | ||
| 178 | u32 tx_control_addr; | ||
| 179 | |||
| 180 | u32 tx_complete_addr; | ||
| 181 | } __packed; | ||
| 182 | |||
| 183 | #define TX_MSDU_LIFETIME_MIN 0 | ||
| 184 | #define TX_MSDU_LIFETIME_MAX 3000 | ||
| 185 | #define TX_MSDU_LIFETIME_DEF 512 | ||
| 186 | #define RX_MSDU_LIFETIME_MIN 0 | ||
| 187 | #define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF | ||
| 188 | #define RX_MSDU_LIFETIME_DEF 512000 | ||
| 189 | |||
| 190 | struct acx_rx_msdu_lifetime { | ||
| 191 | struct acx_header header; | ||
| 192 | |||
| 193 | /* | ||
| 194 | * The maximum amount of time, in TU, before the | ||
| 195 | * firmware discards the MSDU. | ||
| 196 | */ | ||
| 197 | u32 lifetime; | ||
| 198 | } __packed; | ||
| 199 | |||
| 200 | /* | ||
| 201 | * RX Config Options Table | ||
| 202 | * Bit Definition | ||
| 203 | * === ========== | ||
| 204 | * 31:14 Reserved | ||
| 205 | * 13 Copy RX Status - when set, write three receive status words | ||
| 206 | * to top of rx'd MPDUs. | ||
| 207 | * When cleared, do not write three status words (added rev 1.5) | ||
| 208 | * 12 Reserved | ||
| 209 | * 11 RX Complete upon FCS error - when set, give rx complete | ||
| 210 | * interrupt for FCS errors, after the rx filtering, e.g. unicast | ||
| 211 | * frames not to us with FCS error will not generate an interrupt. | ||
| 212 | * 10 SSID Filter Enable - When set, the WiLink discards all beacon, | ||
| 213 | * probe request, and probe response frames with an SSID that does | ||
| 214 | * not match the SSID specified by the host in the START/JOIN | ||
| 215 | * command. | ||
| 216 | * When clear, the WiLink receives frames with any SSID. | ||
| 217 | * 9 Broadcast Filter Enable - When set, the WiLink discards all | ||
| 218 | * broadcast frames. When clear, the WiLink receives all received | ||
| 219 | * broadcast frames. | ||
| 220 | * 8:6 Reserved | ||
| 221 | * 5 BSSID Filter Enable - When set, the WiLink discards any frames | ||
| 222 | * with a BSSID that does not match the BSSID specified by the | ||
| 223 | * host. | ||
| 224 | * When clear, the WiLink receives frames from any BSSID. | ||
| 225 | * 4 MAC Addr Filter - When set, the WiLink discards any frames | ||
| 226 | * with a destination address that does not match the MAC address | ||
| 227 | * of the adaptor. | ||
| 228 | * When clear, the WiLink receives frames destined to any MAC | ||
| 229 | * address. | ||
| 230 | * 3 Promiscuous - When set, the WiLink receives all valid frames | ||
| 231 | * (i.e., all frames that pass the FCS check). | ||
| 232 | * When clear, only frames that pass the other filters specified | ||
| 233 | * are received. | ||
| 234 | * 2 FCS - When set, the WiLink includes the FCS with the received | ||
| 235 | * frame. | ||
| 236 | * When cleared, the FCS is discarded. | ||
| 237 | * 1 PLCP header - When set, write all data from baseband to frame | ||
| 238 | * buffer including PHY header. | ||
| 239 | * 0 Reserved - Always equal to 0. | ||
| 240 | * | ||
| 241 | * RX Filter Options Table | ||
| 242 | * Bit Definition | ||
| 243 | * === ========== | ||
| 244 | * 31:12 Reserved - Always equal to 0. | ||
| 245 | * 11 Association - When set, the WiLink receives all association | ||
| 246 | * related frames (association request/response, reassocation | ||
| 247 | * request/response, and disassociation). When clear, these frames | ||
| 248 | * are discarded. | ||
| 249 | * 10 Auth/De auth - When set, the WiLink receives all authentication | ||
| 250 | * and de-authentication frames. When clear, these frames are | ||
| 251 | * discarded. | ||
| 252 | * 9 Beacon - When set, the WiLink receives all beacon frames. | ||
| 253 | * When clear, these frames are discarded. | ||
| 254 | * 8 Contention Free - When set, the WiLink receives all contention | ||
| 255 | * free frames. | ||
| 256 | * When clear, these frames are discarded. | ||
| 257 | * 7 Control - When set, the WiLink receives all control frames. | ||
| 258 | * When clear, these frames are discarded. | ||
| 259 | * 6 Data - When set, the WiLink receives all data frames. | ||
| 260 | * When clear, these frames are discarded. | ||
| 261 | * 5 FCS Error - When set, the WiLink receives frames that have FCS | ||
| 262 | * errors. | ||
| 263 | * When clear, these frames are discarded. | ||
| 264 | * 4 Management - When set, the WiLink receives all management | ||
| 265 | * frames. | ||
| 266 | * When clear, these frames are discarded. | ||
| 267 | * 3 Probe Request - When set, the WiLink receives all probe request | ||
| 268 | * frames. | ||
| 269 | * When clear, these frames are discarded. | ||
| 270 | * 2 Probe Response - When set, the WiLink receives all probe | ||
| 271 | * response frames. | ||
| 272 | * When clear, these frames are discarded. | ||
| 273 | * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK | ||
| 274 | * frames. | ||
| 275 | * When clear, these frames are discarded. | ||
| 276 | * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames | ||
| 277 | * that have reserved frame types and sub types as defined by the | ||
| 278 | * 802.11 specification. | ||
| 279 | * When clear, these frames are discarded. | ||
| 280 | */ | ||
| 281 | struct acx_rx_config { | ||
| 282 | struct acx_header header; | ||
| 283 | |||
| 284 | u32 config_options; | ||
| 285 | u32 filter_options; | ||
| 286 | } __packed; | ||
| 287 | |||
| 288 | enum { | ||
| 289 | QOS_AC_BE = 0, | ||
| 290 | QOS_AC_BK, | ||
| 291 | QOS_AC_VI, | ||
| 292 | QOS_AC_VO, | ||
| 293 | QOS_HIGHEST_AC_INDEX = QOS_AC_VO, | ||
| 294 | }; | ||
| 295 | |||
| 296 | #define MAX_NUM_OF_AC (QOS_HIGHEST_AC_INDEX+1) | ||
| 297 | #define FIRST_AC_INDEX QOS_AC_BE | ||
| 298 | #define MAX_NUM_OF_802_1d_TAGS 8 | ||
| 299 | #define AC_PARAMS_MAX_TSID 15 | ||
| 300 | #define MAX_APSD_CONF 0xffff | ||
| 301 | |||
| 302 | #define QOS_TX_HIGH_MIN (0) | ||
| 303 | #define QOS_TX_HIGH_MAX (100) | ||
| 304 | |||
| 305 | #define QOS_TX_HIGH_BK_DEF (25) | ||
| 306 | #define QOS_TX_HIGH_BE_DEF (35) | ||
| 307 | #define QOS_TX_HIGH_VI_DEF (35) | ||
| 308 | #define QOS_TX_HIGH_VO_DEF (35) | ||
| 309 | |||
| 310 | #define QOS_TX_LOW_BK_DEF (15) | ||
| 311 | #define QOS_TX_LOW_BE_DEF (25) | ||
| 312 | #define QOS_TX_LOW_VI_DEF (25) | ||
| 313 | #define QOS_TX_LOW_VO_DEF (25) | ||
| 314 | |||
| 315 | struct acx_tx_queue_qos_config { | ||
| 316 | struct acx_header header; | ||
| 317 | |||
| 318 | u8 qid; | ||
| 319 | u8 pad[3]; | ||
| 320 | |||
| 321 | /* Max number of blocks allowd in the queue */ | ||
| 322 | u16 high_threshold; | ||
| 323 | |||
| 324 | /* Lowest memory blocks guaranteed for this queue */ | ||
| 325 | u16 low_threshold; | ||
| 326 | } __packed; | ||
| 327 | |||
| 328 | struct acx_packet_detection { | ||
| 329 | struct acx_header header; | ||
| 330 | |||
| 331 | u32 threshold; | ||
| 332 | } __packed; | ||
| 333 | |||
| 334 | |||
| 335 | enum acx_slot_type { | ||
| 336 | SLOT_TIME_LONG = 0, | ||
| 337 | SLOT_TIME_SHORT = 1, | ||
| 338 | DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, | ||
| 339 | MAX_SLOT_TIMES = 0xFF | ||
| 340 | }; | ||
| 341 | |||
| 342 | #define STATION_WONE_INDEX 0 | ||
| 343 | |||
| 344 | struct acx_slot { | ||
| 345 | struct acx_header header; | ||
| 346 | |||
| 347 | u8 wone_index; /* Reserved */ | ||
| 348 | u8 slot_time; | ||
| 349 | u8 reserved[6]; | ||
| 350 | } __packed; | ||
| 351 | |||
| 352 | |||
| 353 | #define ADDRESS_GROUP_MAX (8) | ||
| 354 | #define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) | ||
| 355 | |||
| 356 | struct acx_dot11_grp_addr_tbl { | ||
| 357 | struct acx_header header; | ||
| 358 | |||
| 359 | u8 enabled; | ||
| 360 | u8 num_groups; | ||
| 361 | u8 pad[2]; | ||
| 362 | u8 mac_table[ADDRESS_GROUP_MAX_LEN]; | ||
| 363 | } __packed; | ||
| 364 | |||
| 365 | |||
| 366 | #define RX_TIMEOUT_PS_POLL_MIN 0 | ||
| 367 | #define RX_TIMEOUT_PS_POLL_MAX (200000) | ||
| 368 | #define RX_TIMEOUT_PS_POLL_DEF (15) | ||
| 369 | #define RX_TIMEOUT_UPSD_MIN 0 | ||
| 370 | #define RX_TIMEOUT_UPSD_MAX (200000) | ||
| 371 | #define RX_TIMEOUT_UPSD_DEF (15) | ||
| 372 | |||
| 373 | struct acx_rx_timeout { | ||
| 374 | struct acx_header header; | ||
| 375 | |||
| 376 | /* | ||
| 377 | * The longest time the STA will wait to receive | ||
| 378 | * traffic from the AP after a PS-poll has been | ||
| 379 | * transmitted. | ||
| 380 | */ | ||
| 381 | u16 ps_poll_timeout; | ||
| 382 | |||
| 383 | /* | ||
| 384 | * The longest time the STA will wait to receive | ||
| 385 | * traffic from the AP after a frame has been sent | ||
| 386 | * from an UPSD enabled queue. | ||
| 387 | */ | ||
| 388 | u16 upsd_timeout; | ||
| 389 | } __packed; | ||
| 390 | |||
| 391 | #define RTS_THRESHOLD_MIN 0 | ||
| 392 | #define RTS_THRESHOLD_MAX 4096 | ||
| 393 | #define RTS_THRESHOLD_DEF 2347 | ||
| 394 | |||
| 395 | struct acx_rts_threshold { | ||
| 396 | struct acx_header header; | ||
| 397 | |||
| 398 | u16 threshold; | ||
| 399 | u8 pad[2]; | ||
| 400 | } __packed; | ||
| 401 | |||
| 402 | enum wl1251_acx_low_rssi_type { | ||
| 403 | /* | ||
| 404 | * The event is a "Level" indication which keeps triggering | ||
| 405 | * as long as the average RSSI is below the threshold. | ||
| 406 | */ | ||
| 407 | WL1251_ACX_LOW_RSSI_TYPE_LEVEL = 0, | ||
| 408 | |||
| 409 | /* | ||
| 410 | * The event is an "Edge" indication which triggers | ||
| 411 | * only when the RSSI threshold is crossed from above. | ||
| 412 | */ | ||
| 413 | WL1251_ACX_LOW_RSSI_TYPE_EDGE = 1, | ||
| 414 | }; | ||
| 415 | |||
| 416 | struct acx_low_rssi { | ||
| 417 | struct acx_header header; | ||
| 418 | |||
| 419 | /* | ||
| 420 | * The threshold (in dBm) below (or above after low rssi | ||
| 421 | * indication) which the firmware generates an interrupt to the | ||
| 422 | * host. This parameter is signed. | ||
| 423 | */ | ||
| 424 | s8 threshold; | ||
| 425 | |||
| 426 | /* | ||
| 427 | * The weight of the current RSSI sample, before adding the new | ||
| 428 | * sample, that is used to calculate the average RSSI. | ||
| 429 | */ | ||
| 430 | u8 weight; | ||
| 431 | |||
| 432 | /* | ||
| 433 | * The number of Beacons/Probe response frames that will be | ||
| 434 | * received before issuing the Low or Regained RSSI event. | ||
| 435 | */ | ||
| 436 | u8 depth; | ||
| 437 | |||
| 438 | /* | ||
| 439 | * Configures how the Low RSSI Event is triggered. Refer to | ||
| 440 | * enum wl1251_acx_low_rssi_type for more. | ||
| 441 | */ | ||
| 442 | u8 type; | ||
| 443 | } __packed; | ||
| 444 | |||
| 445 | struct acx_beacon_filter_option { | ||
| 446 | struct acx_header header; | ||
| 447 | |||
| 448 | u8 enable; | ||
| 449 | |||
| 450 | /* | ||
| 451 | * The number of beacons without the unicast TIM | ||
| 452 | * bit set that the firmware buffers before | ||
| 453 | * signaling the host about ready frames. | ||
| 454 | * When set to 0 and the filter is enabled, beacons | ||
| 455 | * without the unicast TIM bit set are dropped. | ||
| 456 | */ | ||
| 457 | u8 max_num_beacons; | ||
| 458 | u8 pad[2]; | ||
| 459 | } __packed; | ||
| 460 | |||
| 461 | /* | ||
| 462 | * ACXBeaconFilterEntry (not 221) | ||
| 463 | * Byte Offset Size (Bytes) Definition | ||
| 464 | * =========== ============ ========== | ||
| 465 | * 0 1 IE identifier | ||
| 466 | * 1 1 Treatment bit mask | ||
| 467 | * | ||
| 468 | * ACXBeaconFilterEntry (221) | ||
| 469 | * Byte Offset Size (Bytes) Definition | ||
| 470 | * =========== ============ ========== | ||
| 471 | * 0 1 IE identifier | ||
| 472 | * 1 1 Treatment bit mask | ||
| 473 | * 2 3 OUI | ||
| 474 | * 5 1 Type | ||
| 475 | * 6 2 Version | ||
| 476 | * | ||
| 477 | * | ||
| 478 | * Treatment bit mask - The information element handling: | ||
| 479 | * bit 0 - The information element is compared and transferred | ||
| 480 | * in case of change. | ||
| 481 | * bit 1 - The information element is transferred to the host | ||
| 482 | * with each appearance or disappearance. | ||
| 483 | * Note that both bits can be set at the same time. | ||
| 484 | */ | ||
| 485 | #define BEACON_FILTER_TABLE_MAX_IE_NUM (32) | ||
| 486 | #define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) | ||
| 487 | #define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) | ||
| 488 | #define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) | ||
| 489 | #define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ | ||
| 490 | BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ | ||
| 491 | (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ | ||
| 492 | BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) | ||
| 493 | |||
| 494 | #define BEACON_RULE_PASS_ON_CHANGE BIT(0) | ||
| 495 | #define BEACON_RULE_PASS_ON_APPEARANCE BIT(1) | ||
| 496 | |||
| 497 | #define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37) | ||
| 498 | |||
| 499 | struct acx_beacon_filter_ie_table { | ||
| 500 | struct acx_header header; | ||
| 501 | |||
| 502 | u8 num_ie; | ||
| 503 | u8 pad[3]; | ||
| 504 | u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; | ||
| 505 | } __packed; | ||
| 506 | |||
| 507 | #define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */ | ||
| 508 | #define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */ | ||
| 509 | |||
| 510 | struct acx_conn_monit_params { | ||
| 511 | struct acx_header header; | ||
| 512 | |||
| 513 | u32 synch_fail_thold; /* number of beacons missed */ | ||
| 514 | u32 bss_lose_timeout; /* number of TU's from synch fail */ | ||
| 515 | } __packed; | ||
| 516 | |||
| 517 | enum { | ||
| 518 | SG_ENABLE = 0, | ||
| 519 | SG_DISABLE, | ||
| 520 | SG_SENSE_NO_ACTIVITY, | ||
| 521 | SG_SENSE_ACTIVE | ||
| 522 | }; | ||
| 523 | |||
| 524 | struct acx_bt_wlan_coex { | ||
| 525 | struct acx_header header; | ||
| 526 | |||
| 527 | /* | ||
| 528 | * 0 -> PTA enabled | ||
| 529 | * 1 -> PTA disabled | ||
| 530 | * 2 -> sense no active mode, i.e. | ||
| 531 | * an interrupt is sent upon | ||
| 532 | * BT activity. | ||
| 533 | * 3 -> PTA is switched on in response | ||
| 534 | * to the interrupt sending. | ||
| 535 | */ | ||
| 536 | u8 enable; | ||
| 537 | u8 pad[3]; | ||
| 538 | } __packed; | ||
| 539 | |||
| 540 | #define PTA_ANTENNA_TYPE_DEF (0) | ||
| 541 | #define PTA_BT_HP_MAXTIME_DEF (2000) | ||
| 542 | #define PTA_WLAN_HP_MAX_TIME_DEF (5000) | ||
| 543 | #define PTA_SENSE_DISABLE_TIMER_DEF (1350) | ||
| 544 | #define PTA_PROTECTIVE_RX_TIME_DEF (1500) | ||
| 545 | #define PTA_PROTECTIVE_TX_TIME_DEF (1500) | ||
| 546 | #define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) | ||
| 547 | #define PTA_SIGNALING_TYPE_DEF (1) | ||
| 548 | #define PTA_AFH_LEVERAGE_ON_DEF (0) | ||
| 549 | #define PTA_NUMBER_QUIET_CYCLE_DEF (0) | ||
| 550 | #define PTA_MAX_NUM_CTS_DEF (3) | ||
| 551 | #define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) | ||
| 552 | #define PTA_NUMBER_OF_BT_PACKETS_DEF (2) | ||
| 553 | #define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) | ||
| 554 | #define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) | ||
| 555 | #define PTA_CYCLE_TIME_FAST_DEF (8700) | ||
| 556 | #define PTA_RX_FOR_AVALANCHE_DEF (5) | ||
| 557 | #define PTA_ELP_HP_DEF (0) | ||
| 558 | #define PTA_ANTI_STARVE_PERIOD_DEF (500) | ||
| 559 | #define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) | ||
| 560 | #define PTA_ALLOW_PA_SD_DEF (1) | ||
| 561 | #define PTA_TIME_BEFORE_BEACON_DEF (6300) | ||
| 562 | #define PTA_HPDM_MAX_TIME_DEF (1600) | ||
| 563 | #define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) | ||
| 564 | #define PTA_AUTO_MODE_NO_CTS_DEF (0) | ||
| 565 | #define PTA_BT_HP_RESPECTED_DEF (3) | ||
| 566 | #define PTA_WLAN_RX_MIN_RATE_DEF (24) | ||
| 567 | #define PTA_ACK_MODE_DEF (1) | ||
| 568 | |||
| 569 | struct acx_bt_wlan_coex_param { | ||
| 570 | struct acx_header header; | ||
| 571 | |||
| 572 | /* | ||
| 573 | * The minimum rate of a received WLAN packet in the STA, | ||
| 574 | * during protective mode, of which a new BT-HP request | ||
| 575 | * during this Rx will always be respected and gain the antenna. | ||
| 576 | */ | ||
| 577 | u32 min_rate; | ||
| 578 | |||
| 579 | /* Max time the BT HP will be respected. */ | ||
| 580 | u16 bt_hp_max_time; | ||
| 581 | |||
| 582 | /* Max time the WLAN HP will be respected. */ | ||
| 583 | u16 wlan_hp_max_time; | ||
| 584 | |||
| 585 | /* | ||
| 586 | * The time between the last BT activity | ||
| 587 | * and the moment when the sense mode returns | ||
| 588 | * to SENSE_INACTIVE. | ||
| 589 | */ | ||
| 590 | u16 sense_disable_timer; | ||
| 591 | |||
| 592 | /* Time before the next BT HP instance */ | ||
| 593 | u16 rx_time_bt_hp; | ||
| 594 | u16 tx_time_bt_hp; | ||
| 595 | |||
| 596 | /* range: 10-20000 default: 1500 */ | ||
| 597 | u16 rx_time_bt_hp_fast; | ||
| 598 | u16 tx_time_bt_hp_fast; | ||
| 599 | |||
| 600 | /* range: 2000-65535 default: 8700 */ | ||
| 601 | u16 wlan_cycle_fast; | ||
| 602 | |||
| 603 | /* range: 0 - 15000 (Msec) default: 1000 */ | ||
| 604 | u16 bt_anti_starvation_period; | ||
| 605 | |||
| 606 | /* range 400-10000(Usec) default: 3000 */ | ||
| 607 | u16 next_bt_lp_packet; | ||
| 608 | |||
| 609 | /* Deafult: worst case for BT DH5 traffic */ | ||
| 610 | u16 wake_up_beacon; | ||
| 611 | |||
| 612 | /* range: 0-50000(Usec) default: 1050 */ | ||
| 613 | u16 hp_dm_max_guard_time; | ||
| 614 | |||
| 615 | /* | ||
| 616 | * This is to prevent both BT & WLAN antenna | ||
| 617 | * starvation. | ||
| 618 | * Range: 100-50000(Usec) default:2550 | ||
| 619 | */ | ||
| 620 | u16 next_wlan_packet; | ||
| 621 | |||
| 622 | /* 0 -> shared antenna */ | ||
| 623 | u8 antenna_type; | ||
| 624 | |||
| 625 | /* | ||
| 626 | * 0 -> TI legacy | ||
| 627 | * 1 -> Palau | ||
| 628 | */ | ||
| 629 | u8 signal_type; | ||
| 630 | |||
| 631 | /* | ||
| 632 | * BT AFH status | ||
| 633 | * 0 -> no AFH | ||
| 634 | * 1 -> from dedicated GPIO | ||
| 635 | * 2 -> AFH on (from host) | ||
| 636 | */ | ||
| 637 | u8 afh_leverage_on; | ||
| 638 | |||
| 639 | /* | ||
| 640 | * The number of cycles during which no | ||
| 641 | * TX will be sent after 1 cycle of RX | ||
| 642 | * transaction in protective mode | ||
| 643 | */ | ||
| 644 | u8 quiet_cycle_num; | ||
| 645 | |||
| 646 | /* | ||
| 647 | * The maximum number of CTSs that will | ||
| 648 | * be sent for receiving RX packet in | ||
| 649 | * protective mode | ||
| 650 | */ | ||
| 651 | u8 max_cts; | ||
| 652 | |||
| 653 | /* | ||
| 654 | * The number of WLAN packets | ||
| 655 | * transferred in common mode before | ||
| 656 | * switching to BT. | ||
| 657 | */ | ||
| 658 | u8 wlan_packets_num; | ||
| 659 | |||
| 660 | /* | ||
| 661 | * The number of BT packets | ||
| 662 | * transferred in common mode before | ||
| 663 | * switching to WLAN. | ||
| 664 | */ | ||
| 665 | u8 bt_packets_num; | ||
| 666 | |||
| 667 | /* range: 1-255 default: 5 */ | ||
| 668 | u8 missed_rx_avalanche; | ||
| 669 | |||
| 670 | /* range: 0-1 default: 1 */ | ||
| 671 | u8 wlan_elp_hp; | ||
| 672 | |||
| 673 | /* range: 0 - 15 default: 4 */ | ||
| 674 | u8 bt_anti_starvation_cycles; | ||
| 675 | |||
| 676 | u8 ack_mode_dual_ant; | ||
| 677 | |||
| 678 | /* | ||
| 679 | * Allow PA_SD assertion/de-assertion | ||
| 680 | * during enabled BT activity. | ||
| 681 | */ | ||
| 682 | u8 pa_sd_enable; | ||
| 683 | |||
| 684 | /* | ||
| 685 | * Enable/Disable PTA in auto mode: | ||
| 686 | * Support Both Active & P.S modes | ||
| 687 | */ | ||
| 688 | u8 pta_auto_mode_enable; | ||
| 689 | |||
| 690 | /* range: 0 - 20 default: 1 */ | ||
| 691 | u8 bt_hp_respected_num; | ||
| 692 | } __packed; | ||
| 693 | |||
| 694 | #define CCA_THRSH_ENABLE_ENERGY_D 0x140A | ||
| 695 | #define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF | ||
| 696 | |||
| 697 | struct acx_energy_detection { | ||
| 698 | struct acx_header header; | ||
| 699 | |||
| 700 | /* The RX Clear Channel Assessment threshold in the PHY */ | ||
| 701 | u16 rx_cca_threshold; | ||
| 702 | u8 tx_energy_detection; | ||
| 703 | u8 pad; | ||
| 704 | } __packed; | ||
| 705 | |||
| 706 | #define BCN_RX_TIMEOUT_DEF_VALUE 10000 | ||
| 707 | #define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 | ||
| 708 | #define RX_BROADCAST_IN_PS_DEF_VALUE 1 | ||
| 709 | #define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 | ||
| 710 | |||
| 711 | struct acx_beacon_broadcast { | ||
| 712 | struct acx_header header; | ||
| 713 | |||
| 714 | u16 beacon_rx_timeout; | ||
| 715 | u16 broadcast_timeout; | ||
| 716 | |||
| 717 | /* Enables receiving of broadcast packets in PS mode */ | ||
| 718 | u8 rx_broadcast_in_ps; | ||
| 719 | |||
| 720 | /* Consecutive PS Poll failures before updating the host */ | ||
| 721 | u8 ps_poll_threshold; | ||
| 722 | u8 pad[2]; | ||
| 723 | } __packed; | ||
| 724 | |||
| 725 | struct acx_event_mask { | ||
| 726 | struct acx_header header; | ||
| 727 | |||
| 728 | u32 event_mask; | ||
| 729 | u32 high_event_mask; /* Unused */ | ||
| 730 | } __packed; | ||
| 731 | |||
| 732 | #define CFG_RX_FCS BIT(2) | ||
| 733 | #define CFG_RX_ALL_GOOD BIT(3) | ||
| 734 | #define CFG_UNI_FILTER_EN BIT(4) | ||
| 735 | #define CFG_BSSID_FILTER_EN BIT(5) | ||
| 736 | #define CFG_MC_FILTER_EN BIT(6) | ||
| 737 | #define CFG_MC_ADDR0_EN BIT(7) | ||
| 738 | #define CFG_MC_ADDR1_EN BIT(8) | ||
| 739 | #define CFG_BC_REJECT_EN BIT(9) | ||
| 740 | #define CFG_SSID_FILTER_EN BIT(10) | ||
| 741 | #define CFG_RX_INT_FCS_ERROR BIT(11) | ||
| 742 | #define CFG_RX_INT_ENCRYPTED BIT(12) | ||
| 743 | #define CFG_RX_WR_RX_STATUS BIT(13) | ||
| 744 | #define CFG_RX_FILTER_NULTI BIT(14) | ||
| 745 | #define CFG_RX_RESERVE BIT(15) | ||
| 746 | #define CFG_RX_TIMESTAMP_TSF BIT(16) | ||
| 747 | |||
| 748 | #define CFG_RX_RSV_EN BIT(0) | ||
| 749 | #define CFG_RX_RCTS_ACK BIT(1) | ||
| 750 | #define CFG_RX_PRSP_EN BIT(2) | ||
| 751 | #define CFG_RX_PREQ_EN BIT(3) | ||
| 752 | #define CFG_RX_MGMT_EN BIT(4) | ||
| 753 | #define CFG_RX_FCS_ERROR BIT(5) | ||
| 754 | #define CFG_RX_DATA_EN BIT(6) | ||
| 755 | #define CFG_RX_CTL_EN BIT(7) | ||
| 756 | #define CFG_RX_CF_EN BIT(8) | ||
| 757 | #define CFG_RX_BCN_EN BIT(9) | ||
| 758 | #define CFG_RX_AUTH_EN BIT(10) | ||
| 759 | #define CFG_RX_ASSOC_EN BIT(11) | ||
| 760 | |||
| 761 | #define SCAN_PASSIVE BIT(0) | ||
| 762 | #define SCAN_5GHZ_BAND BIT(1) | ||
| 763 | #define SCAN_TRIGGERED BIT(2) | ||
| 764 | #define SCAN_PRIORITY_HIGH BIT(3) | ||
| 765 | |||
| 766 | struct acx_fw_gen_frame_rates { | ||
| 767 | struct acx_header header; | ||
| 768 | |||
| 769 | u8 tx_ctrl_frame_rate; /* RATE_* */ | ||
| 770 | u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */ | ||
| 771 | u8 tx_mgt_frame_rate; | ||
| 772 | u8 tx_mgt_frame_mod; | ||
| 773 | } __packed; | ||
| 774 | |||
| 775 | /* STA MAC */ | ||
| 776 | struct acx_dot11_station_id { | ||
| 777 | struct acx_header header; | ||
| 778 | |||
| 779 | u8 mac[ETH_ALEN]; | ||
| 780 | u8 pad[2]; | ||
| 781 | } __packed; | ||
| 782 | |||
| 783 | struct acx_feature_config { | ||
| 784 | struct acx_header header; | ||
| 785 | |||
| 786 | u32 options; | ||
| 787 | u32 data_flow_options; | ||
| 788 | } __packed; | ||
| 789 | |||
| 790 | struct acx_current_tx_power { | ||
| 791 | struct acx_header header; | ||
| 792 | |||
| 793 | u8 current_tx_power; | ||
| 794 | u8 padding[3]; | ||
| 795 | } __packed; | ||
| 796 | |||
| 797 | struct acx_dot11_default_key { | ||
| 798 | struct acx_header header; | ||
| 799 | |||
| 800 | u8 id; | ||
| 801 | u8 pad[3]; | ||
| 802 | } __packed; | ||
| 803 | |||
| 804 | struct acx_tsf_info { | ||
| 805 | struct acx_header header; | ||
| 806 | |||
| 807 | u32 current_tsf_msb; | ||
| 808 | u32 current_tsf_lsb; | ||
| 809 | u32 last_TBTT_msb; | ||
| 810 | u32 last_TBTT_lsb; | ||
| 811 | u8 last_dtim_count; | ||
| 812 | u8 pad[3]; | ||
| 813 | } __packed; | ||
| 814 | |||
| 815 | enum acx_wake_up_event { | ||
| 816 | WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ | ||
| 817 | WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ | ||
| 818 | WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ | ||
| 819 | WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ | ||
| 820 | WAKE_UP_EVENT_BITS_MASK = 0x0F | ||
| 821 | }; | ||
| 822 | |||
| 823 | struct acx_wake_up_condition { | ||
| 824 | struct acx_header header; | ||
| 825 | |||
| 826 | u8 wake_up_event; /* Only one bit can be set */ | ||
| 827 | u8 listen_interval; | ||
| 828 | u8 pad[2]; | ||
| 829 | } __packed; | ||
| 830 | |||
| 831 | struct acx_aid { | ||
| 832 | struct acx_header header; | ||
| 833 | |||
| 834 | /* | ||
| 835 | * To be set when associated with an AP. | ||
| 836 | */ | ||
| 837 | u16 aid; | ||
| 838 | u8 pad[2]; | ||
| 839 | } __packed; | ||
| 840 | |||
| 841 | enum acx_preamble_type { | ||
| 842 | ACX_PREAMBLE_LONG = 0, | ||
| 843 | ACX_PREAMBLE_SHORT = 1 | ||
| 844 | }; | ||
| 845 | |||
| 846 | struct acx_preamble { | ||
| 847 | struct acx_header header; | ||
| 848 | |||
| 849 | /* | ||
| 850 | * When set, the WiLink transmits the frames with a short preamble and | ||
| 851 | * when cleared, the WiLink transmits the frames with a long preamble. | ||
| 852 | */ | ||
| 853 | u8 preamble; | ||
| 854 | u8 padding[3]; | ||
| 855 | } __packed; | ||
| 856 | |||
| 857 | enum acx_ctsprotect_type { | ||
| 858 | CTSPROTECT_DISABLE = 0, | ||
| 859 | CTSPROTECT_ENABLE = 1 | ||
| 860 | }; | ||
| 861 | |||
| 862 | struct acx_ctsprotect { | ||
| 863 | struct acx_header header; | ||
| 864 | u8 ctsprotect; | ||
| 865 | u8 padding[3]; | ||
| 866 | } __packed; | ||
| 867 | |||
| 868 | struct acx_tx_statistics { | ||
| 869 | u32 internal_desc_overflow; | ||
| 870 | } __packed; | ||
| 871 | |||
| 872 | struct acx_rx_statistics { | ||
| 873 | u32 out_of_mem; | ||
| 874 | u32 hdr_overflow; | ||
| 875 | u32 hw_stuck; | ||
| 876 | u32 dropped; | ||
| 877 | u32 fcs_err; | ||
| 878 | u32 xfr_hint_trig; | ||
| 879 | u32 path_reset; | ||
| 880 | u32 reset_counter; | ||
| 881 | } __packed; | ||
| 882 | |||
| 883 | struct acx_dma_statistics { | ||
| 884 | u32 rx_requested; | ||
| 885 | u32 rx_errors; | ||
| 886 | u32 tx_requested; | ||
| 887 | u32 tx_errors; | ||
| 888 | } __packed; | ||
| 889 | |||
| 890 | struct acx_isr_statistics { | ||
| 891 | /* host command complete */ | ||
| 892 | u32 cmd_cmplt; | ||
| 893 | |||
| 894 | /* fiqisr() */ | ||
| 895 | u32 fiqs; | ||
| 896 | |||
| 897 | /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ | ||
| 898 | u32 rx_headers; | ||
| 899 | |||
| 900 | /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ | ||
| 901 | u32 rx_completes; | ||
| 902 | |||
| 903 | /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ | ||
| 904 | u32 rx_mem_overflow; | ||
| 905 | |||
| 906 | /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ | ||
| 907 | u32 rx_rdys; | ||
| 908 | |||
| 909 | /* irqisr() */ | ||
| 910 | u32 irqs; | ||
| 911 | |||
| 912 | /* (INT_STS_ND & INT_TRIG_TX_PROC) */ | ||
| 913 | u32 tx_procs; | ||
| 914 | |||
| 915 | /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ | ||
| 916 | u32 decrypt_done; | ||
| 917 | |||
| 918 | /* (INT_STS_ND & INT_TRIG_DMA0) */ | ||
| 919 | u32 dma0_done; | ||
| 920 | |||
| 921 | /* (INT_STS_ND & INT_TRIG_DMA1) */ | ||
| 922 | u32 dma1_done; | ||
| 923 | |||
| 924 | /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ | ||
| 925 | u32 tx_exch_complete; | ||
| 926 | |||
| 927 | /* (INT_STS_ND & INT_TRIG_COMMAND) */ | ||
| 928 | u32 commands; | ||
| 929 | |||
| 930 | /* (INT_STS_ND & INT_TRIG_RX_PROC) */ | ||
| 931 | u32 rx_procs; | ||
| 932 | |||
| 933 | /* (INT_STS_ND & INT_TRIG_PM_802) */ | ||
| 934 | u32 hw_pm_mode_changes; | ||
| 935 | |||
| 936 | /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ | ||
| 937 | u32 host_acknowledges; | ||
| 938 | |||
| 939 | /* (INT_STS_ND & INT_TRIG_PM_PCI) */ | ||
| 940 | u32 pci_pm; | ||
| 941 | |||
| 942 | /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ | ||
| 943 | u32 wakeups; | ||
| 944 | |||
| 945 | /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ | ||
| 946 | u32 low_rssi; | ||
| 947 | } __packed; | ||
| 948 | |||
| 949 | struct acx_wep_statistics { | ||
| 950 | /* WEP address keys configured */ | ||
| 951 | u32 addr_key_count; | ||
| 952 | |||
| 953 | /* default keys configured */ | ||
| 954 | u32 default_key_count; | ||
| 955 | |||
| 956 | u32 reserved; | ||
| 957 | |||
| 958 | /* number of times that WEP key not found on lookup */ | ||
| 959 | u32 key_not_found; | ||
| 960 | |||
| 961 | /* number of times that WEP key decryption failed */ | ||
| 962 | u32 decrypt_fail; | ||
| 963 | |||
| 964 | /* WEP packets decrypted */ | ||
| 965 | u32 packets; | ||
| 966 | |||
| 967 | /* WEP decrypt interrupts */ | ||
| 968 | u32 interrupt; | ||
| 969 | } __packed; | ||
| 970 | |||
| 971 | #define ACX_MISSED_BEACONS_SPREAD 10 | ||
| 972 | |||
| 973 | struct acx_pwr_statistics { | ||
| 974 | /* the amount of enters into power save mode (both PD & ELP) */ | ||
| 975 | u32 ps_enter; | ||
| 976 | |||
| 977 | /* the amount of enters into ELP mode */ | ||
| 978 | u32 elp_enter; | ||
| 979 | |||
| 980 | /* the amount of missing beacon interrupts to the host */ | ||
| 981 | u32 missing_bcns; | ||
| 982 | |||
| 983 | /* the amount of wake on host-access times */ | ||
| 984 | u32 wake_on_host; | ||
| 985 | |||
| 986 | /* the amount of wake on timer-expire */ | ||
| 987 | u32 wake_on_timer_exp; | ||
| 988 | |||
| 989 | /* the number of packets that were transmitted with PS bit set */ | ||
| 990 | u32 tx_with_ps; | ||
| 991 | |||
| 992 | /* the number of packets that were transmitted with PS bit clear */ | ||
| 993 | u32 tx_without_ps; | ||
| 994 | |||
| 995 | /* the number of received beacons */ | ||
| 996 | u32 rcvd_beacons; | ||
| 997 | |||
| 998 | /* the number of entering into PowerOn (power save off) */ | ||
| 999 | u32 power_save_off; | ||
| 1000 | |||
| 1001 | /* the number of entries into power save mode */ | ||
| 1002 | u16 enable_ps; | ||
| 1003 | |||
| 1004 | /* | ||
| 1005 | * the number of exits from power save, not including failed PS | ||
| 1006 | * transitions | ||
| 1007 | */ | ||
| 1008 | u16 disable_ps; | ||
| 1009 | |||
| 1010 | /* | ||
| 1011 | * the number of times the TSF counter was adjusted because | ||
| 1012 | * of drift | ||
| 1013 | */ | ||
| 1014 | u32 fix_tsf_ps; | ||
| 1015 | |||
| 1016 | /* Gives statistics about the spread continuous missed beacons. | ||
| 1017 | * The 16 LSB are dedicated for the PS mode. | ||
| 1018 | * The 16 MSB are dedicated for the PS mode. | ||
| 1019 | * cont_miss_bcns_spread[0] - single missed beacon. | ||
| 1020 | * cont_miss_bcns_spread[1] - two continuous missed beacons. | ||
| 1021 | * cont_miss_bcns_spread[2] - three continuous missed beacons. | ||
| 1022 | * ... | ||
| 1023 | * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. | ||
| 1024 | */ | ||
| 1025 | u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; | ||
| 1026 | |||
| 1027 | /* the number of beacons in awake mode */ | ||
| 1028 | u32 rcvd_awake_beacons; | ||
| 1029 | } __packed; | ||
| 1030 | |||
| 1031 | struct acx_mic_statistics { | ||
| 1032 | u32 rx_pkts; | ||
| 1033 | u32 calc_failure; | ||
| 1034 | } __packed; | ||
| 1035 | |||
| 1036 | struct acx_aes_statistics { | ||
| 1037 | u32 encrypt_fail; | ||
| 1038 | u32 decrypt_fail; | ||
| 1039 | u32 encrypt_packets; | ||
| 1040 | u32 decrypt_packets; | ||
| 1041 | u32 encrypt_interrupt; | ||
| 1042 | u32 decrypt_interrupt; | ||
| 1043 | } __packed; | ||
| 1044 | |||
| 1045 | struct acx_event_statistics { | ||
| 1046 | u32 heart_beat; | ||
| 1047 | u32 calibration; | ||
| 1048 | u32 rx_mismatch; | ||
| 1049 | u32 rx_mem_empty; | ||
| 1050 | u32 rx_pool; | ||
| 1051 | u32 oom_late; | ||
| 1052 | u32 phy_transmit_error; | ||
| 1053 | u32 tx_stuck; | ||
| 1054 | } __packed; | ||
| 1055 | |||
| 1056 | struct acx_ps_statistics { | ||
| 1057 | u32 pspoll_timeouts; | ||
| 1058 | u32 upsd_timeouts; | ||
| 1059 | u32 upsd_max_sptime; | ||
| 1060 | u32 upsd_max_apturn; | ||
| 1061 | u32 pspoll_max_apturn; | ||
| 1062 | u32 pspoll_utilization; | ||
| 1063 | u32 upsd_utilization; | ||
| 1064 | } __packed; | ||
| 1065 | |||
| 1066 | struct acx_rxpipe_statistics { | ||
| 1067 | u32 rx_prep_beacon_drop; | ||
| 1068 | u32 descr_host_int_trig_rx_data; | ||
| 1069 | u32 beacon_buffer_thres_host_int_trig_rx_data; | ||
| 1070 | u32 missed_beacon_host_int_trig_rx_data; | ||
| 1071 | u32 tx_xfr_host_int_trig_rx_data; | ||
| 1072 | } __packed; | ||
| 1073 | |||
| 1074 | struct acx_statistics { | ||
| 1075 | struct acx_header header; | ||
| 1076 | |||
| 1077 | struct acx_tx_statistics tx; | ||
| 1078 | struct acx_rx_statistics rx; | ||
| 1079 | struct acx_dma_statistics dma; | ||
| 1080 | struct acx_isr_statistics isr; | ||
| 1081 | struct acx_wep_statistics wep; | ||
| 1082 | struct acx_pwr_statistics pwr; | ||
| 1083 | struct acx_aes_statistics aes; | ||
| 1084 | struct acx_mic_statistics mic; | ||
| 1085 | struct acx_event_statistics event; | ||
| 1086 | struct acx_ps_statistics ps; | ||
| 1087 | struct acx_rxpipe_statistics rxpipe; | ||
| 1088 | } __packed; | ||
| 1089 | |||
| 1090 | #define ACX_MAX_RATE_CLASSES 8 | ||
| 1091 | #define ACX_RATE_MASK_UNSPECIFIED 0 | ||
| 1092 | #define ACX_RATE_RETRY_LIMIT 10 | ||
| 1093 | |||
| 1094 | struct acx_rate_class { | ||
| 1095 | u32 enabled_rates; | ||
| 1096 | u8 short_retry_limit; | ||
| 1097 | u8 long_retry_limit; | ||
| 1098 | u8 aflags; | ||
| 1099 | u8 reserved; | ||
| 1100 | } __packed; | ||
| 1101 | |||
| 1102 | struct acx_rate_policy { | ||
| 1103 | struct acx_header header; | ||
| 1104 | |||
| 1105 | u32 rate_class_cnt; | ||
| 1106 | struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; | ||
| 1107 | } __packed; | ||
| 1108 | |||
| 1109 | struct wl1251_acx_memory { | ||
| 1110 | __le16 num_stations; /* number of STAs to be supported. */ | ||
| 1111 | u16 reserved_1; | ||
| 1112 | |||
| 1113 | /* | ||
| 1114 | * Nmber of memory buffers for the RX mem pool. | ||
| 1115 | * The actual number may be less if there are | ||
| 1116 | * not enough blocks left for the minimum num | ||
| 1117 | * of TX ones. | ||
| 1118 | */ | ||
| 1119 | u8 rx_mem_block_num; | ||
| 1120 | u8 reserved_2; | ||
| 1121 | u8 num_tx_queues; /* From 1 to 16 */ | ||
| 1122 | u8 host_if_options; /* HOST_IF* */ | ||
| 1123 | u8 tx_min_mem_block_num; | ||
| 1124 | u8 num_ssid_profiles; | ||
| 1125 | __le16 debug_buffer_size; | ||
| 1126 | } __packed; | ||
| 1127 | |||
| 1128 | |||
| 1129 | #define ACX_RX_DESC_MIN 1 | ||
| 1130 | #define ACX_RX_DESC_MAX 127 | ||
| 1131 | #define ACX_RX_DESC_DEF 32 | ||
| 1132 | struct wl1251_acx_rx_queue_config { | ||
| 1133 | u8 num_descs; | ||
| 1134 | u8 pad; | ||
| 1135 | u8 type; | ||
| 1136 | u8 priority; | ||
| 1137 | __le32 dma_address; | ||
| 1138 | } __packed; | ||
| 1139 | |||
| 1140 | #define ACX_TX_DESC_MIN 1 | ||
| 1141 | #define ACX_TX_DESC_MAX 127 | ||
| 1142 | #define ACX_TX_DESC_DEF 16 | ||
| 1143 | struct wl1251_acx_tx_queue_config { | ||
| 1144 | u8 num_descs; | ||
| 1145 | u8 pad[2]; | ||
| 1146 | u8 attributes; | ||
| 1147 | } __packed; | ||
| 1148 | |||
| 1149 | #define MAX_TX_QUEUE_CONFIGS 5 | ||
| 1150 | #define MAX_TX_QUEUES 4 | ||
| 1151 | struct wl1251_acx_config_memory { | ||
| 1152 | struct acx_header header; | ||
| 1153 | |||
| 1154 | struct wl1251_acx_memory mem_config; | ||
| 1155 | struct wl1251_acx_rx_queue_config rx_queue_config; | ||
| 1156 | struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS]; | ||
| 1157 | } __packed; | ||
| 1158 | |||
| 1159 | struct wl1251_acx_mem_map { | ||
| 1160 | struct acx_header header; | ||
| 1161 | |||
| 1162 | void *code_start; | ||
| 1163 | void *code_end; | ||
| 1164 | |||
| 1165 | void *wep_defkey_start; | ||
| 1166 | void *wep_defkey_end; | ||
| 1167 | |||
| 1168 | void *sta_table_start; | ||
| 1169 | void *sta_table_end; | ||
| 1170 | |||
| 1171 | void *packet_template_start; | ||
| 1172 | void *packet_template_end; | ||
| 1173 | |||
| 1174 | void *queue_memory_start; | ||
| 1175 | void *queue_memory_end; | ||
| 1176 | |||
| 1177 | void *packet_memory_pool_start; | ||
| 1178 | void *packet_memory_pool_end; | ||
| 1179 | |||
| 1180 | void *debug_buffer1_start; | ||
| 1181 | void *debug_buffer1_end; | ||
| 1182 | |||
| 1183 | void *debug_buffer2_start; | ||
| 1184 | void *debug_buffer2_end; | ||
| 1185 | |||
| 1186 | /* Number of blocks FW allocated for TX packets */ | ||
| 1187 | u32 num_tx_mem_blocks; | ||
| 1188 | |||
| 1189 | /* Number of blocks FW allocated for RX packets */ | ||
| 1190 | u32 num_rx_mem_blocks; | ||
| 1191 | } __packed; | ||
| 1192 | |||
| 1193 | |||
| 1194 | struct wl1251_acx_wr_tbtt_and_dtim { | ||
| 1195 | |||
| 1196 | struct acx_header header; | ||
| 1197 | |||
| 1198 | /* Time in TUs between two consecutive beacons */ | ||
| 1199 | u16 tbtt; | ||
| 1200 | |||
| 1201 | /* | ||
| 1202 | * DTIM period | ||
| 1203 | * For BSS: Number of TBTTs in a DTIM period (range: 1-10) | ||
| 1204 | * For IBSS: value shall be set to 1 | ||
| 1205 | */ | ||
| 1206 | u8 dtim; | ||
| 1207 | u8 padding; | ||
| 1208 | } __packed; | ||
| 1209 | |||
| 1210 | enum wl1251_acx_bet_mode { | ||
| 1211 | WL1251_ACX_BET_DISABLE = 0, | ||
| 1212 | WL1251_ACX_BET_ENABLE = 1, | ||
| 1213 | }; | ||
| 1214 | |||
| 1215 | struct wl1251_acx_bet_enable { | ||
| 1216 | struct acx_header header; | ||
| 1217 | |||
| 1218 | /* | ||
| 1219 | * Specifies if beacon early termination procedure is enabled or | ||
| 1220 | * disabled, see enum wl1251_acx_bet_mode. | ||
| 1221 | */ | ||
| 1222 | u8 enable; | ||
| 1223 | |||
| 1224 | /* | ||
| 1225 | * Specifies the maximum number of consecutive beacons that may be | ||
| 1226 | * early terminated. After this number is reached at least one full | ||
| 1227 | * beacon must be correctly received in FW before beacon ET | ||
| 1228 | * resumes. Range 0 - 255. | ||
| 1229 | */ | ||
| 1230 | u8 max_consecutive; | ||
| 1231 | |||
| 1232 | u8 padding[2]; | ||
| 1233 | } __packed; | ||
| 1234 | |||
| 1235 | struct wl1251_acx_ac_cfg { | ||
| 1236 | struct acx_header header; | ||
| 1237 | |||
| 1238 | /* | ||
| 1239 | * Access Category - The TX queue's access category | ||
| 1240 | * (refer to AccessCategory_enum) | ||
| 1241 | */ | ||
| 1242 | u8 ac; | ||
| 1243 | |||
| 1244 | /* | ||
| 1245 | * The contention window minimum size (in slots) for | ||
| 1246 | * the access class. | ||
| 1247 | */ | ||
| 1248 | u8 cw_min; | ||
| 1249 | |||
| 1250 | /* | ||
| 1251 | * The contention window maximum size (in slots) for | ||
| 1252 | * the access class. | ||
| 1253 | */ | ||
| 1254 | u16 cw_max; | ||
| 1255 | |||
| 1256 | /* The AIF value (in slots) for the access class. */ | ||
| 1257 | u8 aifsn; | ||
| 1258 | |||
| 1259 | u8 reserved; | ||
| 1260 | |||
| 1261 | /* The TX Op Limit (in microseconds) for the access class. */ | ||
| 1262 | u16 txop_limit; | ||
| 1263 | } __packed; | ||
| 1264 | |||
| 1265 | |||
| 1266 | enum wl1251_acx_channel_type { | ||
| 1267 | CHANNEL_TYPE_DCF = 0, | ||
| 1268 | CHANNEL_TYPE_EDCF = 1, | ||
| 1269 | CHANNEL_TYPE_HCCA = 2, | ||
| 1270 | }; | ||
| 1271 | |||
| 1272 | enum wl1251_acx_ps_scheme { | ||
| 1273 | /* regular ps: simple sending of packets */ | ||
| 1274 | WL1251_ACX_PS_SCHEME_LEGACY = 0, | ||
| 1275 | |||
| 1276 | /* sending a packet triggers a unscheduled apsd downstream */ | ||
| 1277 | WL1251_ACX_PS_SCHEME_UPSD_TRIGGER = 1, | ||
| 1278 | |||
| 1279 | /* a pspoll packet will be sent before every data packet */ | ||
| 1280 | WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, | ||
| 1281 | |||
| 1282 | /* scheduled apsd mode */ | ||
| 1283 | WL1251_ACX_PS_SCHEME_SAPSD = 3, | ||
| 1284 | }; | ||
| 1285 | |||
| 1286 | enum wl1251_acx_ack_policy { | ||
| 1287 | WL1251_ACX_ACK_POLICY_LEGACY = 0, | ||
| 1288 | WL1251_ACX_ACK_POLICY_NO_ACK = 1, | ||
| 1289 | WL1251_ACX_ACK_POLICY_BLOCK = 2, | ||
| 1290 | }; | ||
| 1291 | |||
| 1292 | struct wl1251_acx_tid_cfg { | ||
| 1293 | struct acx_header header; | ||
| 1294 | |||
| 1295 | /* tx queue id number (0-7) */ | ||
| 1296 | u8 queue; | ||
| 1297 | |||
| 1298 | /* channel access type for the queue, enum wl1251_acx_channel_type */ | ||
| 1299 | u8 type; | ||
| 1300 | |||
| 1301 | /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */ | ||
| 1302 | u8 tsid; | ||
| 1303 | |||
| 1304 | /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */ | ||
| 1305 | u8 ps_scheme; | ||
| 1306 | |||
| 1307 | /* the tx queue ack policy, enum wl1251_acx_ack_policy */ | ||
| 1308 | u8 ack_policy; | ||
| 1309 | |||
| 1310 | u8 padding[3]; | ||
| 1311 | |||
| 1312 | /* not supported */ | ||
| 1313 | u32 apsdconf[2]; | ||
| 1314 | } __packed; | ||
| 1315 | |||
| 1316 | /************************************************************************* | ||
| 1317 | |||
| 1318 | Host Interrupt Register (WiLink -> Host) | ||
| 1319 | |||
| 1320 | **************************************************************************/ | ||
| 1321 | |||
| 1322 | /* RX packet is ready in Xfer buffer #0 */ | ||
| 1323 | #define WL1251_ACX_INTR_RX0_DATA BIT(0) | ||
| 1324 | |||
| 1325 | /* TX result(s) are in the TX complete buffer */ | ||
| 1326 | #define WL1251_ACX_INTR_TX_RESULT BIT(1) | ||
| 1327 | |||
| 1328 | /* OBSOLETE */ | ||
| 1329 | #define WL1251_ACX_INTR_TX_XFR BIT(2) | ||
| 1330 | |||
| 1331 | /* RX packet is ready in Xfer buffer #1 */ | ||
| 1332 | #define WL1251_ACX_INTR_RX1_DATA BIT(3) | ||
| 1333 | |||
| 1334 | /* Event was entered to Event MBOX #A */ | ||
| 1335 | #define WL1251_ACX_INTR_EVENT_A BIT(4) | ||
| 1336 | |||
| 1337 | /* Event was entered to Event MBOX #B */ | ||
| 1338 | #define WL1251_ACX_INTR_EVENT_B BIT(5) | ||
| 1339 | |||
| 1340 | /* OBSOLETE */ | ||
| 1341 | #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) | ||
| 1342 | |||
| 1343 | /* Trace message on MBOX #A */ | ||
| 1344 | #define WL1251_ACX_INTR_TRACE_A BIT(7) | ||
| 1345 | |||
| 1346 | /* Trace message on MBOX #B */ | ||
| 1347 | #define WL1251_ACX_INTR_TRACE_B BIT(8) | ||
| 1348 | |||
| 1349 | /* Command processing completion */ | ||
| 1350 | #define WL1251_ACX_INTR_CMD_COMPLETE BIT(9) | ||
| 1351 | |||
| 1352 | /* Init sequence is done */ | ||
| 1353 | #define WL1251_ACX_INTR_INIT_COMPLETE BIT(14) | ||
| 1354 | |||
| 1355 | #define WL1251_ACX_INTR_ALL 0xFFFFFFFF | ||
| 1356 | |||
| 1357 | enum { | ||
| 1358 | ACX_WAKE_UP_CONDITIONS = 0x0002, | ||
| 1359 | ACX_MEM_CFG = 0x0003, | ||
| 1360 | ACX_SLOT = 0x0004, | ||
| 1361 | ACX_QUEUE_HEAD = 0x0005, /* for MASTER mode only */ | ||
| 1362 | ACX_AC_CFG = 0x0007, | ||
| 1363 | ACX_MEM_MAP = 0x0008, | ||
| 1364 | ACX_AID = 0x000A, | ||
| 1365 | ACX_RADIO_PARAM = 0x000B, /* Not used */ | ||
| 1366 | ACX_CFG = 0x000C, /* Not used */ | ||
| 1367 | ACX_FW_REV = 0x000D, | ||
| 1368 | ACX_MEDIUM_USAGE = 0x000F, | ||
| 1369 | ACX_RX_CFG = 0x0010, | ||
| 1370 | ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ | ||
| 1371 | ACX_BSS_IN_PS = 0x0012, /* for AP only */ | ||
| 1372 | ACX_STATISTICS = 0x0013, /* Debug API */ | ||
| 1373 | ACX_FEATURE_CFG = 0x0015, | ||
| 1374 | ACX_MISC_CFG = 0x0017, /* Not used */ | ||
| 1375 | ACX_TID_CFG = 0x001A, | ||
| 1376 | ACX_BEACON_FILTER_OPT = 0x001F, | ||
| 1377 | ACX_LOW_RSSI = 0x0020, | ||
| 1378 | ACX_NOISE_HIST = 0x0021, | ||
| 1379 | ACX_HDK_VERSION = 0x0022, /* ??? */ | ||
| 1380 | ACX_PD_THRESHOLD = 0x0023, | ||
| 1381 | ACX_DATA_PATH_PARAMS = 0x0024, /* WO */ | ||
| 1382 | ACX_DATA_PATH_RESP_PARAMS = 0x0024, /* RO */ | ||
| 1383 | ACX_CCA_THRESHOLD = 0x0025, | ||
| 1384 | ACX_EVENT_MBOX_MASK = 0x0026, | ||
| 1385 | #ifdef FW_RUNNING_AS_AP | ||
| 1386 | ACX_DTIM_PERIOD = 0x0027, /* for AP only */ | ||
| 1387 | #else | ||
| 1388 | ACX_WR_TBTT_AND_DTIM = 0x0027, /* STA only */ | ||
| 1389 | #endif | ||
| 1390 | ACX_ACI_OPTION_CFG = 0x0029, /* OBSOLETE (for 1251)*/ | ||
| 1391 | ACX_GPIO_CFG = 0x002A, /* Not used */ | ||
| 1392 | ACX_GPIO_SET = 0x002B, /* Not used */ | ||
| 1393 | ACX_PM_CFG = 0x002C, /* To Be Documented */ | ||
| 1394 | ACX_CONN_MONIT_PARAMS = 0x002D, | ||
| 1395 | ACX_AVERAGE_RSSI = 0x002E, /* Not used */ | ||
| 1396 | ACX_CONS_TX_FAILURE = 0x002F, | ||
| 1397 | ACX_BCN_DTIM_OPTIONS = 0x0031, | ||
| 1398 | ACX_SG_ENABLE = 0x0032, | ||
| 1399 | ACX_SG_CFG = 0x0033, | ||
| 1400 | ACX_ANTENNA_DIVERSITY_CFG = 0x0035, /* To Be Documented */ | ||
| 1401 | ACX_LOW_SNR = 0x0037, /* To Be Documented */ | ||
| 1402 | ACX_BEACON_FILTER_TABLE = 0x0038, | ||
| 1403 | ACX_ARP_IP_FILTER = 0x0039, | ||
| 1404 | ACX_ROAMING_STATISTICS_TBL = 0x003B, | ||
| 1405 | ACX_RATE_POLICY = 0x003D, | ||
| 1406 | ACX_CTS_PROTECTION = 0x003E, | ||
| 1407 | ACX_SLEEP_AUTH = 0x003F, | ||
| 1408 | ACX_PREAMBLE_TYPE = 0x0040, | ||
| 1409 | ACX_ERROR_CNT = 0x0041, | ||
| 1410 | ACX_FW_GEN_FRAME_RATES = 0x0042, | ||
| 1411 | ACX_IBSS_FILTER = 0x0044, | ||
| 1412 | ACX_SERVICE_PERIOD_TIMEOUT = 0x0045, | ||
| 1413 | ACX_TSF_INFO = 0x0046, | ||
| 1414 | ACX_CONFIG_PS_WMM = 0x0049, | ||
| 1415 | ACX_ENABLE_RX_DATA_FILTER = 0x004A, | ||
| 1416 | ACX_SET_RX_DATA_FILTER = 0x004B, | ||
| 1417 | ACX_GET_DATA_FILTER_STATISTICS = 0x004C, | ||
| 1418 | ACX_POWER_LEVEL_TABLE = 0x004D, | ||
| 1419 | ACX_BET_ENABLE = 0x0050, | ||
| 1420 | DOT11_STATION_ID = 0x1001, | ||
| 1421 | DOT11_RX_MSDU_LIFE_TIME = 0x1004, | ||
| 1422 | DOT11_CUR_TX_PWR = 0x100D, | ||
| 1423 | DOT11_DEFAULT_KEY = 0x1010, | ||
| 1424 | DOT11_RX_DOT11_MODE = 0x1012, | ||
| 1425 | DOT11_RTS_THRESHOLD = 0x1013, | ||
| 1426 | DOT11_GROUP_ADDRESS_TBL = 0x1014, | ||
| 1427 | |||
| 1428 | MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, | ||
| 1429 | |||
| 1430 | MAX_IE = 0xFFFF | ||
| 1431 | }; | ||
| 1432 | |||
| 1433 | |||
| 1434 | int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod, | ||
| 1435 | u8 mgt_rate, u8 mgt_mod); | ||
| 1436 | int wl1251_acx_station_id(struct wl1251 *wl); | ||
| 1437 | int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id); | ||
| 1438 | int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, | ||
| 1439 | u8 listen_interval); | ||
| 1440 | int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); | ||
| 1441 | int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); | ||
| 1442 | int wl1251_acx_tx_power(struct wl1251 *wl, int power); | ||
| 1443 | int wl1251_acx_feature_cfg(struct wl1251 *wl); | ||
| 1444 | int wl1251_acx_mem_map(struct wl1251 *wl, | ||
| 1445 | struct acx_header *mem_map, size_t len); | ||
| 1446 | int wl1251_acx_data_path_params(struct wl1251 *wl, | ||
| 1447 | struct acx_data_path_params_resp *data_path); | ||
| 1448 | int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); | ||
| 1449 | int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); | ||
| 1450 | int wl1251_acx_pd_threshold(struct wl1251 *wl); | ||
| 1451 | int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); | ||
| 1452 | int wl1251_acx_group_address_tbl(struct wl1251 *wl); | ||
| 1453 | int wl1251_acx_service_period_timeout(struct wl1251 *wl); | ||
| 1454 | int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); | ||
| 1455 | int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); | ||
| 1456 | int wl1251_acx_beacon_filter_table(struct wl1251 *wl); | ||
| 1457 | int wl1251_acx_conn_monit_params(struct wl1251 *wl); | ||
| 1458 | int wl1251_acx_sg_enable(struct wl1251 *wl); | ||
| 1459 | int wl1251_acx_sg_cfg(struct wl1251 *wl); | ||
| 1460 | int wl1251_acx_cca_threshold(struct wl1251 *wl); | ||
| 1461 | int wl1251_acx_bcn_dtim_options(struct wl1251 *wl); | ||
| 1462 | int wl1251_acx_aid(struct wl1251 *wl, u16 aid); | ||
| 1463 | int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask); | ||
| 1464 | int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight, | ||
| 1465 | u8 depth, enum wl1251_acx_low_rssi_type type); | ||
| 1466 | int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble); | ||
| 1467 | int wl1251_acx_cts_protect(struct wl1251 *wl, | ||
| 1468 | enum acx_ctsprotect_type ctsprotect); | ||
| 1469 | int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); | ||
| 1470 | int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); | ||
| 1471 | int wl1251_acx_rate_policies(struct wl1251 *wl); | ||
| 1472 | int wl1251_acx_mem_cfg(struct wl1251 *wl); | ||
| 1473 | int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); | ||
| 1474 | int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, | ||
| 1475 | u8 max_consecutive); | ||
| 1476 | int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, | ||
| 1477 | u8 aifs, u16 txop); | ||
| 1478 | int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, | ||
| 1479 | enum wl1251_acx_channel_type type, | ||
| 1480 | u8 tsid, enum wl1251_acx_ps_scheme ps_scheme, | ||
| 1481 | enum wl1251_acx_ack_policy ack_policy); | ||
| 1482 | |||
| 1483 | #endif /* __WL1251_ACX_H__ */ | ||
diff --git a/drivers/net/wireless/wl1251/boot.c b/drivers/net/wireless/wl1251/boot.c new file mode 100644 index 00000000000..d729daf8e84 --- /dev/null +++ b/drivers/net/wireless/wl1251/boot.c | |||
| @@ -0,0 +1,556 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Nokia Corporation | ||
| 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 <linux/slab.h> | ||
| 23 | |||
| 24 | #include "reg.h" | ||
| 25 | #include "boot.h" | ||
| 26 | #include "io.h" | ||
| 27 | #include "spi.h" | ||
| 28 | #include "event.h" | ||
| 29 | #include "acx.h" | ||
| 30 | |||
| 31 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl) | ||
| 32 | { | ||
| 33 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
| 34 | wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); | ||
| 35 | } | ||
| 36 | |||
| 37 | int wl1251_boot_soft_reset(struct wl1251 *wl) | ||
| 38 | { | ||
| 39 | unsigned long timeout; | ||
| 40 | u32 boot_data; | ||
| 41 | |||
| 42 | /* perform soft reset */ | ||
| 43 | wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); | ||
| 44 | |||
| 45 | /* SOFT_RESET is self clearing */ | ||
| 46 | timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); | ||
| 47 | while (1) { | ||
| 48 | boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); | ||
| 49 | wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); | ||
| 50 | if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) | ||
| 51 | break; | ||
| 52 | |||
| 53 | if (time_after(jiffies, timeout)) { | ||
| 54 | /* 1.2 check pWhalBus->uSelfClearTime if the | ||
| 55 | * timeout was reached */ | ||
| 56 | wl1251_error("soft reset timeout"); | ||
| 57 | return -1; | ||
| 58 | } | ||
| 59 | |||
| 60 | udelay(SOFT_RESET_STALL_TIME); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* disable Rx/Tx */ | ||
| 64 | wl1251_reg_write32(wl, ENABLE, 0x0); | ||
| 65 | |||
| 66 | /* disable auto calibration on start*/ | ||
| 67 | wl1251_reg_write32(wl, SPARE_A2, 0xffff); | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | int wl1251_boot_init_seq(struct wl1251 *wl) | ||
| 73 | { | ||
| 74 | u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq; | ||
| 75 | |||
| 76 | /* | ||
| 77 | * col #1: INTEGER_DIVIDER | ||
| 78 | * col #2: FRACTIONAL_DIVIDER | ||
| 79 | * col #3: ATTN_BB | ||
| 80 | * col #4: ALPHA_BB | ||
| 81 | * col #5: STOP_TIME_BB | ||
| 82 | * col #6: BB_PLL_LOOP_FILTER | ||
| 83 | */ | ||
| 84 | static const u32 LUT[REF_FREQ_NUM][LUT_PARAM_NUM] = { | ||
| 85 | |||
| 86 | { 83, 87381, 0xB, 5, 0xF00, 3}, /* REF_FREQ_19_2*/ | ||
| 87 | { 61, 141154, 0xB, 5, 0x1450, 2}, /* REF_FREQ_26_0*/ | ||
| 88 | { 41, 174763, 0xC, 6, 0x2D00, 1}, /* REF_FREQ_38_4*/ | ||
| 89 | { 40, 0, 0xC, 6, 0x2EE0, 1}, /* REF_FREQ_40_0*/ | ||
| 90 | { 47, 162280, 0xC, 6, 0x2760, 1} /* REF_FREQ_33_6 */ | ||
| 91 | }; | ||
| 92 | |||
| 93 | /* read NVS params */ | ||
| 94 | scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6); | ||
| 95 | wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6); | ||
| 96 | |||
| 97 | /* read ELP_CMD */ | ||
| 98 | elp_cmd = wl1251_reg_read32(wl, ELP_CMD); | ||
| 99 | wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd); | ||
| 100 | |||
| 101 | /* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */ | ||
| 102 | ref_freq = scr_pad6 & 0x000000FF; | ||
| 103 | wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq); | ||
| 104 | |||
| 105 | wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9); | ||
| 106 | |||
| 107 | /* | ||
| 108 | * PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME) | ||
| 109 | */ | ||
| 110 | wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6); | ||
| 111 | |||
| 112 | /* | ||
| 113 | * set the clock detect feature to work in the restart wu procedure | ||
| 114 | * (ELP_CFG_MODE[14]) and Select the clock source type | ||
| 115 | * (ELP_CFG_MODE[13:12]) | ||
| 116 | */ | ||
| 117 | tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000; | ||
| 118 | wl1251_reg_write32(wl, ELP_CFG_MODE, tmp); | ||
| 119 | |||
| 120 | /* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */ | ||
| 121 | elp_cmd |= 0x00000040; | ||
| 122 | wl1251_reg_write32(wl, ELP_CMD, elp_cmd); | ||
| 123 | |||
| 124 | /* PG 1.2: Set the BB PLL stable time to be 1000usec | ||
| 125 | * (PLL_STABLE_TIME) */ | ||
| 126 | wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20); | ||
| 127 | |||
| 128 | /* PG 1.2: read clock request time */ | ||
| 129 | init_data = wl1251_reg_read32(wl, CLK_REQ_TIME); | ||
| 130 | |||
| 131 | /* | ||
| 132 | * PG 1.2: set the clock request time to be ref_clk_settling_time - | ||
| 133 | * 1ms = 4ms | ||
| 134 | */ | ||
| 135 | if (init_data > 0x21) | ||
| 136 | tmp = init_data - 0x21; | ||
| 137 | else | ||
| 138 | tmp = 0; | ||
| 139 | wl1251_reg_write32(wl, CLK_REQ_TIME, tmp); | ||
| 140 | |||
| 141 | /* set BB PLL configurations in RF AFE */ | ||
| 142 | wl1251_reg_write32(wl, 0x003058cc, 0x4B5); | ||
| 143 | |||
| 144 | /* set RF_AFE_REG_5 */ | ||
| 145 | wl1251_reg_write32(wl, 0x003058d4, 0x50); | ||
| 146 | |||
| 147 | /* set RF_AFE_CTRL_REG_2 */ | ||
| 148 | wl1251_reg_write32(wl, 0x00305948, 0x11c001); | ||
| 149 | |||
| 150 | /* | ||
| 151 | * change RF PLL and BB PLL divider for VCO clock and adjust VCO | ||
| 152 | * bais current(RF_AFE_REG_13) | ||
| 153 | */ | ||
| 154 | wl1251_reg_write32(wl, 0x003058f4, 0x1e); | ||
| 155 | |||
| 156 | /* set BB PLL configurations */ | ||
| 157 | tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000; | ||
| 158 | wl1251_reg_write32(wl, 0x00305840, tmp); | ||
| 159 | |||
| 160 | /* set fractional divider according to Appendix C-BB PLL | ||
| 161 | * Calculations | ||
| 162 | */ | ||
| 163 | tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER]; | ||
| 164 | wl1251_reg_write32(wl, 0x00305844, tmp); | ||
| 165 | |||
| 166 | /* set the initial data for the sigma delta */ | ||
| 167 | wl1251_reg_write32(wl, 0x00305848, 0x3039); | ||
| 168 | |||
| 169 | /* | ||
| 170 | * set the accumulator attenuation value, calibration loop1 | ||
| 171 | * (alpha), calibration loop2 (beta), calibration loop3 (gamma) and | ||
| 172 | * the VCO gain | ||
| 173 | */ | ||
| 174 | tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) | | ||
| 175 | (LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1; | ||
| 176 | wl1251_reg_write32(wl, 0x00305854, tmp); | ||
| 177 | |||
| 178 | /* | ||
| 179 | * set the calibration stop time after holdoff time expires and set | ||
| 180 | * settling time HOLD_OFF_TIME_BB | ||
| 181 | */ | ||
| 182 | tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000; | ||
| 183 | wl1251_reg_write32(wl, 0x00305858, tmp); | ||
| 184 | |||
| 185 | /* | ||
| 186 | * set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL | ||
| 187 | * constant leakage current to linearize PFD to 0uA - | ||
| 188 | * BB_ILOOPF[7:3] | ||
| 189 | */ | ||
| 190 | tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030; | ||
| 191 | wl1251_reg_write32(wl, 0x003058f8, tmp); | ||
| 192 | |||
| 193 | /* | ||
| 194 | * set regulator output voltage for n divider to | ||
| 195 | * 1.35-BB_REFDIV[1:0], set charge pump current- BB_CPGAIN[4:2], | ||
| 196 | * set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB | ||
| 197 | * PLL auto-call to normal mode- BB_CALGAIN_3DB[8] | ||
| 198 | */ | ||
| 199 | wl1251_reg_write32(wl, 0x003058f0, 0x29); | ||
| 200 | |||
| 201 | /* enable restart wakeup sequence (ELP_CMD[0]) */ | ||
| 202 | wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1); | ||
| 203 | |||
| 204 | /* restart sequence completed */ | ||
| 205 | udelay(2000); | ||
| 206 | |||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static void wl1251_boot_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) | ||
| 211 | { | ||
| 212 | u32 cpu_ctrl; | ||
| 213 | |||
| 214 | /* 10.5.0 run the firmware (I) */ | ||
| 215 | cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
| 216 | |||
| 217 | /* 10.5.1 run the firmware (II) */ | ||
| 218 | cpu_ctrl &= ~flag; | ||
| 219 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
| 220 | } | ||
| 221 | |||
| 222 | int wl1251_boot_run_firmware(struct wl1251 *wl) | ||
| 223 | { | ||
| 224 | int loop, ret; | ||
| 225 | u32 chip_id, acx_intr; | ||
| 226 | |||
| 227 | wl1251_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); | ||
| 228 | |||
| 229 | chip_id = wl1251_reg_read32(wl, CHIP_ID_B); | ||
| 230 | |||
| 231 | wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); | ||
| 232 | |||
| 233 | if (chip_id != wl->chip_id) { | ||
| 234 | wl1251_error("chip id doesn't match after firmware boot"); | ||
| 235 | return -EIO; | ||
| 236 | } | ||
| 237 | |||
| 238 | /* wait for init to complete */ | ||
| 239 | loop = 0; | ||
| 240 | while (loop++ < INIT_LOOP) { | ||
| 241 | udelay(INIT_LOOP_DELAY); | ||
| 242 | acx_intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
| 243 | |||
| 244 | if (acx_intr == 0xffffffff) { | ||
| 245 | wl1251_error("error reading hardware complete " | ||
| 246 | "init indication"); | ||
| 247 | return -EIO; | ||
| 248 | } | ||
| 249 | /* check that ACX_INTR_INIT_COMPLETE is enabled */ | ||
| 250 | else if (acx_intr & WL1251_ACX_INTR_INIT_COMPLETE) { | ||
| 251 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
| 252 | WL1251_ACX_INTR_INIT_COMPLETE); | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | if (loop > INIT_LOOP) { | ||
| 258 | wl1251_error("timeout waiting for the hardware to " | ||
| 259 | "complete initialization"); | ||
| 260 | return -EIO; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* get hardware config command mail box */ | ||
| 264 | wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); | ||
| 265 | |||
| 266 | /* get hardware config event mail box */ | ||
| 267 | wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
| 268 | |||
| 269 | /* set the working partition to its "running" mode offset */ | ||
| 270 | wl1251_set_partition(wl, WL1251_PART_WORK_MEM_START, | ||
| 271 | WL1251_PART_WORK_MEM_SIZE, | ||
| 272 | WL1251_PART_WORK_REG_START, | ||
| 273 | WL1251_PART_WORK_REG_SIZE); | ||
| 274 | |||
| 275 | wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", | ||
| 276 | wl->cmd_box_addr, wl->event_box_addr); | ||
| 277 | |||
| 278 | wl1251_acx_fw_version(wl, wl->fw_ver, sizeof(wl->fw_ver)); | ||
| 279 | |||
| 280 | /* | ||
| 281 | * in case of full asynchronous mode the firmware event must be | ||
| 282 | * ready to receive event from the command mailbox | ||
| 283 | */ | ||
| 284 | |||
| 285 | /* enable gpio interrupts */ | ||
| 286 | wl1251_enable_interrupts(wl); | ||
| 287 | |||
| 288 | /* Enable target's interrupts */ | ||
| 289 | wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | | ||
| 290 | WL1251_ACX_INTR_RX1_DATA | | ||
| 291 | WL1251_ACX_INTR_TX_RESULT | | ||
| 292 | WL1251_ACX_INTR_EVENT_A | | ||
| 293 | WL1251_ACX_INTR_EVENT_B | | ||
| 294 | WL1251_ACX_INTR_INIT_COMPLETE; | ||
| 295 | wl1251_boot_target_enable_interrupts(wl); | ||
| 296 | |||
| 297 | wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID | | ||
| 298 | SYNCHRONIZATION_TIMEOUT_EVENT_ID | | ||
| 299 | ROAMING_TRIGGER_LOW_RSSI_EVENT_ID | | ||
| 300 | ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID | | ||
| 301 | REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID | | ||
| 302 | BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID; | ||
| 303 | |||
| 304 | ret = wl1251_event_unmask(wl); | ||
| 305 | if (ret < 0) { | ||
| 306 | wl1251_error("EVENT mask setting failed"); | ||
| 307 | return ret; | ||
| 308 | } | ||
| 309 | |||
| 310 | wl1251_event_mbox_config(wl); | ||
| 311 | |||
| 312 | /* firmware startup completed */ | ||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | static int wl1251_boot_upload_firmware(struct wl1251 *wl) | ||
| 317 | { | ||
| 318 | int addr, chunk_num, partition_limit; | ||
| 319 | size_t fw_data_len, len; | ||
| 320 | u8 *p, *buf; | ||
| 321 | |||
| 322 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
| 323 | |||
| 324 | wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", | ||
| 325 | wl1251_reg_read32(wl, CHIP_ID_B)); | ||
| 326 | |||
| 327 | /* 10.0 check firmware length and set partition */ | ||
| 328 | fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | | ||
| 329 | (wl->fw[6] << 8) | (wl->fw[7]); | ||
| 330 | |||
| 331 | wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, | ||
| 332 | CHUNK_SIZE); | ||
| 333 | |||
| 334 | if ((fw_data_len % 4) != 0) { | ||
| 335 | wl1251_error("firmware length not multiple of four"); | ||
| 336 | return -EIO; | ||
| 337 | } | ||
| 338 | |||
| 339 | buf = kmalloc(CHUNK_SIZE, GFP_KERNEL); | ||
| 340 | if (!buf) { | ||
| 341 | wl1251_error("allocation for firmware upload chunk failed"); | ||
| 342 | return -ENOMEM; | ||
| 343 | } | ||
| 344 | |||
| 345 | wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, | ||
| 346 | WL1251_PART_DOWN_MEM_SIZE, | ||
| 347 | WL1251_PART_DOWN_REG_START, | ||
| 348 | WL1251_PART_DOWN_REG_SIZE); | ||
| 349 | |||
| 350 | /* 10.1 set partition limit and chunk num */ | ||
| 351 | chunk_num = 0; | ||
| 352 | partition_limit = WL1251_PART_DOWN_MEM_SIZE; | ||
| 353 | |||
| 354 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
| 355 | /* 10.2 update partition, if needed */ | ||
| 356 | addr = WL1251_PART_DOWN_MEM_START + | ||
| 357 | (chunk_num + 2) * CHUNK_SIZE; | ||
| 358 | if (addr > partition_limit) { | ||
| 359 | addr = WL1251_PART_DOWN_MEM_START + | ||
| 360 | chunk_num * CHUNK_SIZE; | ||
| 361 | partition_limit = chunk_num * CHUNK_SIZE + | ||
| 362 | WL1251_PART_DOWN_MEM_SIZE; | ||
| 363 | wl1251_set_partition(wl, | ||
| 364 | addr, | ||
| 365 | WL1251_PART_DOWN_MEM_SIZE, | ||
| 366 | WL1251_PART_DOWN_REG_START, | ||
| 367 | WL1251_PART_DOWN_REG_SIZE); | ||
| 368 | } | ||
| 369 | |||
| 370 | /* 10.3 upload the chunk */ | ||
| 371 | addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; | ||
| 372 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
| 373 | wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
| 374 | p, addr); | ||
| 375 | |||
| 376 | /* need to copy the chunk for dma */ | ||
| 377 | len = CHUNK_SIZE; | ||
| 378 | memcpy(buf, p, len); | ||
| 379 | wl1251_mem_write(wl, addr, buf, len); | ||
| 380 | |||
| 381 | chunk_num++; | ||
| 382 | } | ||
| 383 | |||
| 384 | /* 10.4 upload the last chunk */ | ||
| 385 | addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; | ||
| 386 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
| 387 | |||
| 388 | /* need to copy the chunk for dma */ | ||
| 389 | len = fw_data_len % CHUNK_SIZE; | ||
| 390 | memcpy(buf, p, len); | ||
| 391 | |||
| 392 | wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", | ||
| 393 | len, p, addr); | ||
| 394 | wl1251_mem_write(wl, addr, buf, len); | ||
| 395 | |||
| 396 | kfree(buf); | ||
| 397 | |||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | |||
| 401 | static int wl1251_boot_upload_nvs(struct wl1251 *wl) | ||
| 402 | { | ||
| 403 | size_t nvs_len, nvs_bytes_written, burst_len; | ||
| 404 | int nvs_start, i; | ||
| 405 | u32 dest_addr, val; | ||
| 406 | u8 *nvs_ptr, *nvs; | ||
| 407 | |||
| 408 | nvs = wl->nvs; | ||
| 409 | if (nvs == NULL) | ||
| 410 | return -ENODEV; | ||
| 411 | |||
| 412 | nvs_ptr = nvs; | ||
| 413 | |||
| 414 | nvs_len = wl->nvs_len; | ||
| 415 | nvs_start = wl->fw_len; | ||
| 416 | |||
| 417 | /* | ||
| 418 | * Layout before the actual NVS tables: | ||
| 419 | * 1 byte : burst length. | ||
| 420 | * 2 bytes: destination address. | ||
| 421 | * n bytes: data to burst copy. | ||
| 422 | * | ||
| 423 | * This is ended by a 0 length, then the NVS tables. | ||
| 424 | */ | ||
| 425 | |||
| 426 | while (nvs_ptr[0]) { | ||
| 427 | burst_len = nvs_ptr[0]; | ||
| 428 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
| 429 | |||
| 430 | /* We move our pointer to the data */ | ||
| 431 | nvs_ptr += 3; | ||
| 432 | |||
| 433 | for (i = 0; i < burst_len; i++) { | ||
| 434 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
| 435 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
| 436 | |||
| 437 | wl1251_debug(DEBUG_BOOT, | ||
| 438 | "nvs burst write 0x%x: 0x%x", | ||
| 439 | dest_addr, val); | ||
| 440 | wl1251_mem_write32(wl, dest_addr, val); | ||
| 441 | |||
| 442 | nvs_ptr += 4; | ||
| 443 | dest_addr += 4; | ||
| 444 | } | ||
| 445 | } | ||
| 446 | |||
| 447 | /* | ||
| 448 | * We've reached the first zero length, the first NVS table | ||
| 449 | * is 7 bytes further. | ||
| 450 | */ | ||
| 451 | nvs_ptr += 7; | ||
| 452 | nvs_len -= nvs_ptr - nvs; | ||
| 453 | nvs_len = ALIGN(nvs_len, 4); | ||
| 454 | |||
| 455 | /* Now we must set the partition correctly */ | ||
| 456 | wl1251_set_partition(wl, nvs_start, | ||
| 457 | WL1251_PART_DOWN_MEM_SIZE, | ||
| 458 | WL1251_PART_DOWN_REG_START, | ||
| 459 | WL1251_PART_DOWN_REG_SIZE); | ||
| 460 | |||
| 461 | /* And finally we upload the NVS tables */ | ||
| 462 | nvs_bytes_written = 0; | ||
| 463 | while (nvs_bytes_written < nvs_len) { | ||
| 464 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
| 465 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
| 466 | |||
| 467 | val = cpu_to_le32(val); | ||
| 468 | |||
| 469 | wl1251_debug(DEBUG_BOOT, | ||
| 470 | "nvs write table 0x%x: 0x%x", | ||
| 471 | nvs_start, val); | ||
| 472 | wl1251_mem_write32(wl, nvs_start, val); | ||
| 473 | |||
| 474 | nvs_ptr += 4; | ||
| 475 | nvs_bytes_written += 4; | ||
| 476 | nvs_start += 4; | ||
| 477 | } | ||
| 478 | |||
| 479 | return 0; | ||
| 480 | } | ||
| 481 | |||
| 482 | int wl1251_boot(struct wl1251 *wl) | ||
| 483 | { | ||
| 484 | int ret = 0, minor_minor_e2_ver; | ||
| 485 | u32 tmp, boot_data; | ||
| 486 | |||
| 487 | /* halt embedded ARM CPU while loading firmware */ | ||
| 488 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, ECPU_CONTROL_HALT); | ||
| 489 | |||
| 490 | ret = wl1251_boot_soft_reset(wl); | ||
| 491 | if (ret < 0) | ||
| 492 | goto out; | ||
| 493 | |||
| 494 | /* 2. start processing NVS file */ | ||
| 495 | if (wl->use_eeprom) { | ||
| 496 | wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR); | ||
| 497 | /* Wait for EEPROM NVS burst read to complete */ | ||
| 498 | msleep(40); | ||
| 499 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM); | ||
| 500 | } else { | ||
| 501 | ret = wl1251_boot_upload_nvs(wl); | ||
| 502 | if (ret < 0) | ||
| 503 | goto out; | ||
| 504 | |||
| 505 | /* write firmware's last address (ie. it's length) to | ||
| 506 | * ACX_EEPROMLESS_IND_REG */ | ||
| 507 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); | ||
| 508 | } | ||
| 509 | |||
| 510 | /* 6. read the EEPROM parameters */ | ||
| 511 | tmp = wl1251_reg_read32(wl, SCR_PAD2); | ||
| 512 | |||
| 513 | /* 7. read bootdata */ | ||
| 514 | wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; | ||
| 515 | wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; | ||
| 516 | tmp = wl1251_reg_read32(wl, SCR_PAD3); | ||
| 517 | |||
| 518 | /* 8. check bootdata and call restart sequence */ | ||
| 519 | wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; | ||
| 520 | minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; | ||
| 521 | |||
| 522 | wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " | ||
| 523 | "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", | ||
| 524 | wl->boot_attr.radio_type, wl->boot_attr.major, | ||
| 525 | wl->boot_attr.minor, minor_minor_e2_ver); | ||
| 526 | |||
| 527 | ret = wl1251_boot_init_seq(wl); | ||
| 528 | if (ret < 0) | ||
| 529 | goto out; | ||
| 530 | |||
| 531 | /* 9. NVS processing done */ | ||
| 532 | boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
| 533 | |||
| 534 | wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); | ||
| 535 | |||
| 536 | /* 10. check that ECPU_CONTROL_HALT bits are set in | ||
| 537 | * pWhalBus->uBootData and start uploading firmware | ||
| 538 | */ | ||
| 539 | if ((boot_data & ECPU_CONTROL_HALT) == 0) { | ||
| 540 | wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); | ||
| 541 | ret = -EIO; | ||
| 542 | goto out; | ||
| 543 | } | ||
| 544 | |||
| 545 | ret = wl1251_boot_upload_firmware(wl); | ||
| 546 | if (ret < 0) | ||
| 547 | goto out; | ||
| 548 | |||
| 549 | /* 10.5 start firmware */ | ||
| 550 | ret = wl1251_boot_run_firmware(wl); | ||
| 551 | if (ret < 0) | ||
| 552 | goto out; | ||
| 553 | |||
| 554 | out: | ||
| 555 | return ret; | ||
| 556 | } | ||
diff --git a/drivers/net/wireless/wl1251/boot.h b/drivers/net/wireless/wl1251/boot.h new file mode 100644 index 00000000000..7661bc5e466 --- /dev/null +++ b/drivers/net/wireless/wl1251/boot.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Nokia Corporation | ||
| 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 | #ifndef __BOOT_H__ | ||
| 23 | #define __BOOT_H__ | ||
| 24 | |||
| 25 | #include "wl1251.h" | ||
| 26 | |||
| 27 | int wl1251_boot_soft_reset(struct wl1251 *wl); | ||
| 28 | int wl1251_boot_init_seq(struct wl1251 *wl); | ||
| 29 | int wl1251_boot_run_firmware(struct wl1251 *wl); | ||
| 30 | void wl1251_boot_target_enable_interrupts(struct wl1251 *wl); | ||
| 31 | int wl1251_boot(struct wl1251 *wl); | ||
| 32 | |||
| 33 | /* number of times we try to read the INIT interrupt */ | ||
| 34 | #define INIT_LOOP 20000 | ||
| 35 | |||
| 36 | /* delay between retries */ | ||
| 37 | #define INIT_LOOP_DELAY 50 | ||
| 38 | |||
| 39 | #endif | ||
diff --git a/drivers/net/wireless/wl1251/cmd.c b/drivers/net/wireless/wl1251/cmd.c new file mode 100644 index 00000000000..d14d69d733a --- /dev/null +++ b/drivers/net/wireless/wl1251/cmd.c | |||
| @@ -0,0 +1,496 @@ | |||
| 1 | #include "cmd.h" | ||
| 2 | |||
| 3 | #include <linux/module.h> | ||
| 4 | #include <linux/slab.h> | ||
| 5 | #include <linux/crc7.h> | ||
| 6 | |||
| 7 | #include "wl1251.h" | ||
| 8 | #include "reg.h" | ||
| 9 | #include "io.h" | ||
| 10 | #include "ps.h" | ||
| 11 | #include "acx.h" | ||
| 12 | |||
| 13 | /** | ||
| 14 | * send command to firmware | ||
| 15 | * | ||
| 16 | * @wl: wl struct | ||
| 17 | * @id: command id | ||
| 18 | * @buf: buffer containing the command, must work with dma | ||
| 19 | * @len: length of the buffer | ||
| 20 | */ | ||
| 21 | int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len) | ||
| 22 | { | ||
| 23 | struct wl1251_cmd_header *cmd; | ||
| 24 | unsigned long timeout; | ||
| 25 | u32 intr; | ||
| 26 | int ret = 0; | ||
| 27 | |||
| 28 | cmd = buf; | ||
| 29 | cmd->id = id; | ||
| 30 | cmd->status = 0; | ||
| 31 | |||
| 32 | WARN_ON(len % 4 != 0); | ||
| 33 | |||
| 34 | wl1251_mem_write(wl, wl->cmd_box_addr, buf, len); | ||
| 35 | |||
| 36 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); | ||
| 37 | |||
| 38 | timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT); | ||
| 39 | |||
| 40 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
| 41 | while (!(intr & WL1251_ACX_INTR_CMD_COMPLETE)) { | ||
| 42 | if (time_after(jiffies, timeout)) { | ||
| 43 | wl1251_error("command complete timeout"); | ||
| 44 | ret = -ETIMEDOUT; | ||
| 45 | goto out; | ||
| 46 | } | ||
| 47 | |||
| 48 | msleep(1); | ||
| 49 | |||
| 50 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); | ||
| 51 | } | ||
| 52 | |||
| 53 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK, | ||
| 54 | WL1251_ACX_INTR_CMD_COMPLETE); | ||
| 55 | |||
| 56 | out: | ||
| 57 | return ret; | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * send test command to firmware | ||
| 62 | * | ||
| 63 | * @wl: wl struct | ||
| 64 | * @buf: buffer containing the command, with all headers, must work with dma | ||
| 65 | * @len: length of the buffer | ||
| 66 | * @answer: is answer needed | ||
| 67 | */ | ||
| 68 | int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) | ||
| 69 | { | ||
| 70 | int ret; | ||
| 71 | |||
| 72 | wl1251_debug(DEBUG_CMD, "cmd test"); | ||
| 73 | |||
| 74 | ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len); | ||
| 75 | |||
| 76 | if (ret < 0) { | ||
| 77 | wl1251_warning("TEST command failed"); | ||
| 78 | return ret; | ||
| 79 | } | ||
| 80 | |||
| 81 | if (answer) { | ||
| 82 | struct wl1251_command *cmd_answer; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * The test command got in, we can read the answer. | ||
| 86 | * The answer would be a wl1251_command, where the | ||
| 87 | * parameter array contains the actual answer. | ||
| 88 | */ | ||
| 89 | wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); | ||
| 90 | |||
| 91 | cmd_answer = buf; | ||
| 92 | |||
| 93 | if (cmd_answer->header.status != CMD_STATUS_SUCCESS) | ||
| 94 | wl1251_error("TEST command answer error: %d", | ||
| 95 | cmd_answer->header.status); | ||
| 96 | } | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * read acx from firmware | ||
| 103 | * | ||
| 104 | * @wl: wl struct | ||
| 105 | * @id: acx id | ||
| 106 | * @buf: buffer for the response, including all headers, must work with dma | ||
| 107 | * @len: length of buf | ||
| 108 | */ | ||
| 109 | int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) | ||
| 110 | { | ||
| 111 | struct acx_header *acx = buf; | ||
| 112 | int ret; | ||
| 113 | |||
| 114 | wl1251_debug(DEBUG_CMD, "cmd interrogate"); | ||
| 115 | |||
| 116 | acx->id = id; | ||
| 117 | |||
| 118 | /* payload length, does not include any headers */ | ||
| 119 | acx->len = len - sizeof(*acx); | ||
| 120 | |||
| 121 | ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); | ||
| 122 | if (ret < 0) { | ||
| 123 | wl1251_error("INTERROGATE command failed"); | ||
| 124 | goto out; | ||
| 125 | } | ||
| 126 | |||
| 127 | /* the interrogate command got in, we can read the answer */ | ||
| 128 | wl1251_mem_read(wl, wl->cmd_box_addr, buf, len); | ||
| 129 | |||
| 130 | acx = buf; | ||
| 131 | if (acx->cmd.status != CMD_STATUS_SUCCESS) | ||
| 132 | wl1251_error("INTERROGATE command error: %d", | ||
| 133 | acx->cmd.status); | ||
| 134 | |||
| 135 | out: | ||
| 136 | return ret; | ||
| 137 | } | ||
| 138 | |||
| 139 | /** | ||
| 140 | * write acx value to firmware | ||
| 141 | * | ||
| 142 | * @wl: wl struct | ||
| 143 | * @id: acx id | ||
| 144 | * @buf: buffer containing acx, including all headers, must work with dma | ||
| 145 | * @len: length of buf | ||
| 146 | */ | ||
| 147 | int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len) | ||
| 148 | { | ||
| 149 | struct acx_header *acx = buf; | ||
| 150 | int ret; | ||
| 151 | |||
| 152 | wl1251_debug(DEBUG_CMD, "cmd configure"); | ||
| 153 | |||
| 154 | acx->id = id; | ||
| 155 | |||
| 156 | /* payload length, does not include any headers */ | ||
| 157 | acx->len = len - sizeof(*acx); | ||
| 158 | |||
| 159 | ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len); | ||
| 160 | if (ret < 0) { | ||
| 161 | wl1251_warning("CONFIGURE command NOK"); | ||
| 162 | return ret; | ||
| 163 | } | ||
| 164 | |||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | |||
| 168 | int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, | ||
| 169 | void *bitmap, u16 bitmap_len, u8 bitmap_control) | ||
| 170 | { | ||
| 171 | struct wl1251_cmd_vbm_update *vbm; | ||
| 172 | int ret; | ||
| 173 | |||
| 174 | wl1251_debug(DEBUG_CMD, "cmd vbm"); | ||
| 175 | |||
| 176 | vbm = kzalloc(sizeof(*vbm), GFP_KERNEL); | ||
| 177 | if (!vbm) { | ||
| 178 | ret = -ENOMEM; | ||
| 179 | goto out; | ||
| 180 | } | ||
| 181 | |||
| 182 | /* Count and period will be filled by the target */ | ||
| 183 | vbm->tim.bitmap_ctrl = bitmap_control; | ||
| 184 | if (bitmap_len > PARTIAL_VBM_MAX) { | ||
| 185 | wl1251_warning("cmd vbm len is %d B, truncating to %d", | ||
| 186 | bitmap_len, PARTIAL_VBM_MAX); | ||
| 187 | bitmap_len = PARTIAL_VBM_MAX; | ||
| 188 | } | ||
| 189 | memcpy(vbm->tim.pvb_field, bitmap, bitmap_len); | ||
| 190 | vbm->tim.identity = identity; | ||
| 191 | vbm->tim.length = bitmap_len + 3; | ||
| 192 | |||
| 193 | vbm->len = cpu_to_le16(bitmap_len + 5); | ||
| 194 | |||
| 195 | ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm)); | ||
| 196 | if (ret < 0) { | ||
| 197 | wl1251_error("VBM command failed"); | ||
| 198 | goto out; | ||
| 199 | } | ||
| 200 | |||
| 201 | out: | ||
| 202 | kfree(vbm); | ||
| 203 | return ret; | ||
| 204 | } | ||
| 205 | |||
| 206 | int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) | ||
| 207 | { | ||
| 208 | struct cmd_enabledisable_path *cmd; | ||
| 209 | int ret; | ||
| 210 | u16 cmd_rx, cmd_tx; | ||
| 211 | |||
| 212 | wl1251_debug(DEBUG_CMD, "cmd data path"); | ||
| 213 | |||
| 214 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
| 215 | if (!cmd) { | ||
| 216 | ret = -ENOMEM; | ||
| 217 | goto out; | ||
| 218 | } | ||
| 219 | |||
| 220 | cmd->channel = channel; | ||
| 221 | |||
| 222 | if (enable) { | ||
| 223 | cmd_rx = CMD_ENABLE_RX; | ||
| 224 | cmd_tx = CMD_ENABLE_TX; | ||
| 225 | } else { | ||
| 226 | cmd_rx = CMD_DISABLE_RX; | ||
| 227 | cmd_tx = CMD_DISABLE_TX; | ||
| 228 | } | ||
| 229 | |||
| 230 | ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); | ||
| 231 | if (ret < 0) { | ||
| 232 | wl1251_error("rx %s cmd for channel %d failed", | ||
| 233 | enable ? "start" : "stop", channel); | ||
| 234 | goto out; | ||
| 235 | } | ||
| 236 | |||
| 237 | wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", | ||
| 238 | enable ? "start" : "stop", channel); | ||
| 239 | |||
| 240 | ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); | ||
| 241 | if (ret < 0) { | ||
| 242 | wl1251_error("tx %s cmd for channel %d failed", | ||
| 243 | enable ? "start" : "stop", channel); | ||
| 244 | goto out; | ||
| 245 | } | ||
| 246 | |||
| 247 | wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", | ||
| 248 | enable ? "start" : "stop", channel); | ||
| 249 | |||
| 250 | out: | ||
| 251 | kfree(cmd); | ||
| 252 | return ret; | ||
| 253 | } | ||
| 254 | |||
| 255 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, | ||
| 256 | u16 beacon_interval, u8 dtim_interval) | ||
| 257 | { | ||
| 258 | struct cmd_join *join; | ||
| 259 | int ret, i; | ||
| 260 | u8 *bssid; | ||
| 261 | |||
| 262 | join = kzalloc(sizeof(*join), GFP_KERNEL); | ||
| 263 | if (!join) { | ||
| 264 | ret = -ENOMEM; | ||
| 265 | goto out; | ||
| 266 | } | ||
| 267 | |||
| 268 | wl1251_debug(DEBUG_CMD, "cmd join%s ch %d %d/%d", | ||
| 269 | bss_type == BSS_TYPE_IBSS ? " ibss" : "", | ||
| 270 | channel, beacon_interval, dtim_interval); | ||
| 271 | |||
| 272 | /* Reverse order BSSID */ | ||
| 273 | bssid = (u8 *) &join->bssid_lsb; | ||
| 274 | for (i = 0; i < ETH_ALEN; i++) | ||
| 275 | bssid[i] = wl->bssid[ETH_ALEN - i - 1]; | ||
| 276 | |||
| 277 | join->rx_config_options = wl->rx_config; | ||
| 278 | join->rx_filter_options = wl->rx_filter; | ||
| 279 | |||
| 280 | /* | ||
| 281 | * FIXME: disable temporarily all filters because after commit | ||
| 282 | * 9cef8737 "mac80211: fix managed mode BSSID handling" broke | ||
| 283 | * association. The filter logic needs to be implemented properly | ||
| 284 | * and once that is done, this hack can be removed. | ||
| 285 | */ | ||
| 286 | join->rx_config_options = 0; | ||
| 287 | join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; | ||
| 288 | |||
| 289 | join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | | ||
| 290 | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; | ||
| 291 | |||
| 292 | join->beacon_interval = beacon_interval; | ||
| 293 | join->dtim_interval = dtim_interval; | ||
| 294 | join->bss_type = bss_type; | ||
| 295 | join->channel = channel; | ||
| 296 | join->ctrl = JOIN_CMD_CTRL_TX_FLUSH; | ||
| 297 | |||
| 298 | ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); | ||
| 299 | if (ret < 0) { | ||
| 300 | wl1251_error("failed to initiate cmd join"); | ||
| 301 | goto out; | ||
| 302 | } | ||
| 303 | |||
| 304 | out: | ||
| 305 | kfree(join); | ||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | |||
| 309 | int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode) | ||
| 310 | { | ||
| 311 | struct wl1251_cmd_ps_params *ps_params = NULL; | ||
| 312 | int ret = 0; | ||
| 313 | |||
| 314 | wl1251_debug(DEBUG_CMD, "cmd set ps mode"); | ||
| 315 | |||
| 316 | ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); | ||
| 317 | if (!ps_params) { | ||
| 318 | ret = -ENOMEM; | ||
| 319 | goto out; | ||
| 320 | } | ||
| 321 | |||
| 322 | ps_params->ps_mode = ps_mode; | ||
| 323 | ps_params->send_null_data = 1; | ||
| 324 | ps_params->retries = 5; | ||
| 325 | ps_params->hang_over_period = 128; | ||
| 326 | ps_params->null_data_rate = 1; /* 1 Mbps */ | ||
| 327 | |||
| 328 | ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params, | ||
| 329 | sizeof(*ps_params)); | ||
| 330 | if (ret < 0) { | ||
| 331 | wl1251_error("cmd set_ps_mode failed"); | ||
| 332 | goto out; | ||
| 333 | } | ||
| 334 | |||
| 335 | out: | ||
| 336 | kfree(ps_params); | ||
| 337 | return ret; | ||
| 338 | } | ||
| 339 | |||
| 340 | int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | ||
| 341 | size_t len) | ||
| 342 | { | ||
| 343 | struct cmd_read_write_memory *cmd; | ||
| 344 | int ret = 0; | ||
| 345 | |||
| 346 | wl1251_debug(DEBUG_CMD, "cmd read memory"); | ||
| 347 | |||
| 348 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
| 349 | if (!cmd) { | ||
| 350 | ret = -ENOMEM; | ||
| 351 | goto out; | ||
| 352 | } | ||
| 353 | |||
| 354 | WARN_ON(len > MAX_READ_SIZE); | ||
| 355 | len = min_t(size_t, len, MAX_READ_SIZE); | ||
| 356 | |||
| 357 | cmd->addr = addr; | ||
| 358 | cmd->size = len; | ||
| 359 | |||
| 360 | ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); | ||
| 361 | if (ret < 0) { | ||
| 362 | wl1251_error("read memory command failed: %d", ret); | ||
| 363 | goto out; | ||
| 364 | } | ||
| 365 | |||
| 366 | /* the read command got in, we can now read the answer */ | ||
| 367 | wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
| 368 | |||
| 369 | if (cmd->header.status != CMD_STATUS_SUCCESS) | ||
| 370 | wl1251_error("error in read command result: %d", | ||
| 371 | cmd->header.status); | ||
| 372 | |||
| 373 | memcpy(answer, cmd->value, len); | ||
| 374 | |||
| 375 | out: | ||
| 376 | kfree(cmd); | ||
| 377 | return ret; | ||
| 378 | } | ||
| 379 | |||
| 380 | int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, | ||
| 381 | void *buf, size_t buf_len) | ||
| 382 | { | ||
| 383 | struct wl1251_cmd_packet_template *cmd; | ||
| 384 | size_t cmd_len; | ||
| 385 | int ret = 0; | ||
| 386 | |||
| 387 | wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id); | ||
| 388 | |||
| 389 | WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE); | ||
| 390 | buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE); | ||
| 391 | cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4); | ||
| 392 | |||
| 393 | cmd = kzalloc(cmd_len, GFP_KERNEL); | ||
| 394 | if (!cmd) { | ||
| 395 | ret = -ENOMEM; | ||
| 396 | goto out; | ||
| 397 | } | ||
| 398 | |||
| 399 | cmd->size = cpu_to_le16(buf_len); | ||
| 400 | |||
| 401 | if (buf) | ||
| 402 | memcpy(cmd->data, buf, buf_len); | ||
| 403 | |||
| 404 | ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len); | ||
| 405 | if (ret < 0) { | ||
| 406 | wl1251_warning("cmd set_template failed: %d", ret); | ||
| 407 | goto out; | ||
| 408 | } | ||
| 409 | |||
| 410 | out: | ||
| 411 | kfree(cmd); | ||
| 412 | return ret; | ||
| 413 | } | ||
| 414 | |||
| 415 | int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, | ||
| 416 | struct ieee80211_channel *channels[], | ||
| 417 | unsigned int n_channels, unsigned int n_probes) | ||
| 418 | { | ||
| 419 | struct wl1251_cmd_scan *cmd; | ||
| 420 | int i, ret = 0; | ||
| 421 | |||
| 422 | wl1251_debug(DEBUG_CMD, "cmd scan"); | ||
| 423 | |||
| 424 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
| 425 | if (!cmd) | ||
| 426 | return -ENOMEM; | ||
| 427 | |||
| 428 | cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
| 429 | cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | | ||
| 430 | CFG_RX_MGMT_EN | | ||
| 431 | CFG_RX_BCN_EN); | ||
| 432 | cmd->params.scan_options = 0; | ||
| 433 | cmd->params.num_channels = n_channels; | ||
| 434 | cmd->params.num_probe_requests = n_probes; | ||
| 435 | cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
| 436 | cmd->params.tid_trigger = 0; | ||
| 437 | |||
| 438 | for (i = 0; i < n_channels; i++) { | ||
| 439 | cmd->channels[i].min_duration = | ||
| 440 | cpu_to_le32(WL1251_SCAN_MIN_DURATION); | ||
| 441 | cmd->channels[i].max_duration = | ||
| 442 | cpu_to_le32(WL1251_SCAN_MAX_DURATION); | ||
| 443 | memset(&cmd->channels[i].bssid_lsb, 0xff, 4); | ||
| 444 | memset(&cmd->channels[i].bssid_msb, 0xff, 2); | ||
| 445 | cmd->channels[i].early_termination = 0; | ||
| 446 | cmd->channels[i].tx_power_att = 0; | ||
| 447 | cmd->channels[i].channel = channels[i]->hw_value; | ||
| 448 | } | ||
| 449 | |||
| 450 | cmd->params.ssid_len = ssid_len; | ||
| 451 | if (ssid) | ||
| 452 | memcpy(cmd->params.ssid, ssid, ssid_len); | ||
| 453 | |||
| 454 | ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); | ||
| 455 | if (ret < 0) { | ||
| 456 | wl1251_error("cmd scan failed: %d", ret); | ||
| 457 | goto out; | ||
| 458 | } | ||
| 459 | |||
| 460 | wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
| 461 | |||
| 462 | if (cmd->header.status != CMD_STATUS_SUCCESS) { | ||
| 463 | wl1251_error("cmd scan status wasn't success: %d", | ||
| 464 | cmd->header.status); | ||
| 465 | ret = -EIO; | ||
| 466 | goto out; | ||
| 467 | } | ||
| 468 | |||
| 469 | out: | ||
| 470 | kfree(cmd); | ||
| 471 | return ret; | ||
| 472 | } | ||
| 473 | |||
| 474 | int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) | ||
| 475 | { | ||
| 476 | struct wl1251_cmd_trigger_scan_to *cmd; | ||
| 477 | int ret; | ||
| 478 | |||
| 479 | wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); | ||
| 480 | |||
| 481 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
| 482 | if (!cmd) | ||
| 483 | return -ENOMEM; | ||
| 484 | |||
| 485 | cmd->timeout = timeout; | ||
| 486 | |||
| 487 | ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, cmd, sizeof(*cmd)); | ||
| 488 | if (ret < 0) { | ||
| 489 | wl1251_error("cmd trigger scan to failed: %d", ret); | ||
| 490 | goto out; | ||
| 491 | } | ||
| 492 | |||
| 493 | out: | ||
| 494 | kfree(cmd); | ||
| 495 | return ret; | ||
| 496 | } | ||
diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h new file mode 100644 index 00000000000..79ca5273c9e --- /dev/null +++ b/drivers/net/wireless/wl1251/cmd.h | |||
| @@ -0,0 +1,415 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __WL1251_CMD_H__ | ||
| 24 | #define __WL1251_CMD_H__ | ||
| 25 | |||
| 26 | #include "wl1251.h" | ||
| 27 | |||
| 28 | #include <net/cfg80211.h> | ||
| 29 | |||
| 30 | struct acx_header; | ||
| 31 | |||
| 32 | int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); | ||
| 33 | int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer); | ||
| 34 | int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); | ||
| 35 | int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); | ||
| 36 | int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, | ||
| 37 | void *bitmap, u16 bitmap_len, u8 bitmap_control); | ||
| 38 | int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); | ||
| 39 | int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, | ||
| 40 | u16 beacon_interval, u8 dtim_interval); | ||
| 41 | int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); | ||
| 42 | int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | ||
| 43 | size_t len); | ||
| 44 | int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, | ||
| 45 | void *buf, size_t buf_len); | ||
| 46 | int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, | ||
| 47 | struct ieee80211_channel *channels[], | ||
| 48 | unsigned int n_channels, unsigned int n_probes); | ||
| 49 | int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); | ||
| 50 | |||
| 51 | /* unit ms */ | ||
| 52 | #define WL1251_COMMAND_TIMEOUT 2000 | ||
| 53 | |||
| 54 | enum wl1251_commands { | ||
| 55 | CMD_RESET = 0, | ||
| 56 | CMD_INTERROGATE = 1, /*use this to read information elements*/ | ||
| 57 | CMD_CONFIGURE = 2, /*use this to write information elements*/ | ||
| 58 | CMD_ENABLE_RX = 3, | ||
| 59 | CMD_ENABLE_TX = 4, | ||
| 60 | CMD_DISABLE_RX = 5, | ||
| 61 | CMD_DISABLE_TX = 6, | ||
| 62 | CMD_SCAN = 8, | ||
| 63 | CMD_STOP_SCAN = 9, | ||
| 64 | CMD_VBM = 10, | ||
| 65 | CMD_START_JOIN = 11, | ||
| 66 | CMD_SET_KEYS = 12, | ||
| 67 | CMD_READ_MEMORY = 13, | ||
| 68 | CMD_WRITE_MEMORY = 14, | ||
| 69 | CMD_BEACON = 19, | ||
| 70 | CMD_PROBE_RESP = 20, | ||
| 71 | CMD_NULL_DATA = 21, | ||
| 72 | CMD_PROBE_REQ = 22, | ||
| 73 | CMD_TEST = 23, | ||
| 74 | CMD_RADIO_CALIBRATE = 25, /* OBSOLETE */ | ||
| 75 | CMD_ENABLE_RX_PATH = 27, /* OBSOLETE */ | ||
| 76 | CMD_NOISE_HIST = 28, | ||
| 77 | CMD_RX_RESET = 29, | ||
| 78 | CMD_PS_POLL = 30, | ||
| 79 | CMD_QOS_NULL_DATA = 31, | ||
| 80 | CMD_LNA_CONTROL = 32, | ||
| 81 | CMD_SET_BCN_MODE = 33, | ||
| 82 | CMD_MEASUREMENT = 34, | ||
| 83 | CMD_STOP_MEASUREMENT = 35, | ||
| 84 | CMD_DISCONNECT = 36, | ||
| 85 | CMD_SET_PS_MODE = 37, | ||
| 86 | CMD_CHANNEL_SWITCH = 38, | ||
| 87 | CMD_STOP_CHANNEL_SWICTH = 39, | ||
| 88 | CMD_AP_DISCOVERY = 40, | ||
| 89 | CMD_STOP_AP_DISCOVERY = 41, | ||
| 90 | CMD_SPS_SCAN = 42, | ||
| 91 | CMD_STOP_SPS_SCAN = 43, | ||
| 92 | CMD_HEALTH_CHECK = 45, | ||
| 93 | CMD_DEBUG = 46, | ||
| 94 | CMD_TRIGGER_SCAN_TO = 47, | ||
| 95 | |||
| 96 | NUM_COMMANDS, | ||
| 97 | MAX_COMMAND_ID = 0xFFFF, | ||
| 98 | }; | ||
| 99 | |||
| 100 | #define MAX_CMD_PARAMS 572 | ||
| 101 | |||
| 102 | struct wl1251_cmd_header { | ||
| 103 | u16 id; | ||
| 104 | u16 status; | ||
| 105 | /* payload */ | ||
| 106 | u8 data[0]; | ||
| 107 | } __packed; | ||
| 108 | |||
| 109 | struct wl1251_command { | ||
| 110 | struct wl1251_cmd_header header; | ||
| 111 | u8 parameters[MAX_CMD_PARAMS]; | ||
| 112 | } __packed; | ||
| 113 | |||
| 114 | enum { | ||
| 115 | CMD_MAILBOX_IDLE = 0, | ||
| 116 | CMD_STATUS_SUCCESS = 1, | ||
| 117 | CMD_STATUS_UNKNOWN_CMD = 2, | ||
| 118 | CMD_STATUS_UNKNOWN_IE = 3, | ||
| 119 | CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, | ||
| 120 | CMD_STATUS_RX_BUSY = 13, | ||
| 121 | CMD_STATUS_INVALID_PARAM = 14, | ||
| 122 | CMD_STATUS_TEMPLATE_TOO_LARGE = 15, | ||
| 123 | CMD_STATUS_OUT_OF_MEMORY = 16, | ||
| 124 | CMD_STATUS_STA_TABLE_FULL = 17, | ||
| 125 | CMD_STATUS_RADIO_ERROR = 18, | ||
| 126 | CMD_STATUS_WRONG_NESTING = 19, | ||
| 127 | CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ | ||
| 128 | CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ | ||
| 129 | MAX_COMMAND_STATUS = 0xff | ||
| 130 | }; | ||
| 131 | |||
| 132 | |||
| 133 | /* | ||
| 134 | * CMD_READ_MEMORY | ||
| 135 | * | ||
| 136 | * The host issues this command to read the WiLink device memory/registers. | ||
| 137 | * | ||
| 138 | * Note: The Base Band address has special handling (16 bits registers and | ||
| 139 | * addresses). For more information, see the hardware specification. | ||
| 140 | */ | ||
| 141 | /* | ||
| 142 | * CMD_WRITE_MEMORY | ||
| 143 | * | ||
| 144 | * The host issues this command to write the WiLink device memory/registers. | ||
| 145 | * | ||
| 146 | * The Base Band address has special handling (16 bits registers and | ||
| 147 | * addresses). For more information, see the hardware specification. | ||
| 148 | */ | ||
| 149 | #define MAX_READ_SIZE 256 | ||
| 150 | |||
| 151 | struct cmd_read_write_memory { | ||
| 152 | struct wl1251_cmd_header header; | ||
| 153 | |||
| 154 | /* The address of the memory to read from or write to.*/ | ||
| 155 | u32 addr; | ||
| 156 | |||
| 157 | /* The amount of data in bytes to read from or write to the WiLink | ||
| 158 | * device.*/ | ||
| 159 | u32 size; | ||
| 160 | |||
| 161 | /* The actual value read from or written to the Wilink. The source | ||
| 162 | of this field is the Host in WRITE command or the Wilink in READ | ||
| 163 | command. */ | ||
| 164 | u8 value[MAX_READ_SIZE]; | ||
| 165 | } __packed; | ||
| 166 | |||
| 167 | #define CMDMBOX_HEADER_LEN 4 | ||
| 168 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 | ||
| 169 | |||
| 170 | #define WL1251_SCAN_MIN_DURATION 30000 | ||
| 171 | #define WL1251_SCAN_MAX_DURATION 60000 | ||
| 172 | |||
| 173 | #define WL1251_SCAN_NUM_PROBES 3 | ||
| 174 | |||
| 175 | struct wl1251_scan_parameters { | ||
| 176 | __le32 rx_config_options; | ||
| 177 | __le32 rx_filter_options; | ||
| 178 | |||
| 179 | /* | ||
| 180 | * Scan options: | ||
| 181 | * bit 0: When this bit is set, passive scan. | ||
| 182 | * bit 1: Band, when this bit is set we scan | ||
| 183 | * in the 5Ghz band. | ||
| 184 | * bit 2: voice mode, 0 for normal scan. | ||
| 185 | * bit 3: scan priority, 1 for high priority. | ||
| 186 | */ | ||
| 187 | __le16 scan_options; | ||
| 188 | |||
| 189 | /* Number of channels to scan */ | ||
| 190 | u8 num_channels; | ||
| 191 | |||
| 192 | /* Number opf probe requests to send, per channel */ | ||
| 193 | u8 num_probe_requests; | ||
| 194 | |||
| 195 | /* Rate and modulation for probe requests */ | ||
| 196 | __le16 tx_rate; | ||
| 197 | |||
| 198 | u8 tid_trigger; | ||
| 199 | u8 ssid_len; | ||
| 200 | u8 ssid[32]; | ||
| 201 | |||
| 202 | } __packed; | ||
| 203 | |||
| 204 | struct wl1251_scan_ch_parameters { | ||
| 205 | __le32 min_duration; /* in TU */ | ||
| 206 | __le32 max_duration; /* in TU */ | ||
| 207 | u32 bssid_lsb; | ||
| 208 | u16 bssid_msb; | ||
| 209 | |||
| 210 | /* | ||
| 211 | * bits 0-3: Early termination count. | ||
| 212 | * bits 4-5: Early termination condition. | ||
| 213 | */ | ||
| 214 | u8 early_termination; | ||
| 215 | |||
| 216 | u8 tx_power_att; | ||
| 217 | u8 channel; | ||
| 218 | u8 pad[3]; | ||
| 219 | } __packed; | ||
| 220 | |||
| 221 | /* SCAN parameters */ | ||
| 222 | #define SCAN_MAX_NUM_OF_CHANNELS 16 | ||
| 223 | |||
| 224 | struct wl1251_cmd_scan { | ||
| 225 | struct wl1251_cmd_header header; | ||
| 226 | |||
| 227 | struct wl1251_scan_parameters params; | ||
| 228 | struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; | ||
| 229 | } __packed; | ||
| 230 | |||
| 231 | enum { | ||
| 232 | BSS_TYPE_IBSS = 0, | ||
| 233 | BSS_TYPE_STA_BSS = 2, | ||
| 234 | BSS_TYPE_AP_BSS = 3, | ||
| 235 | MAX_BSS_TYPE = 0xFF | ||
| 236 | }; | ||
| 237 | |||
| 238 | #define JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ | ||
| 239 | #define JOIN_CMD_CTRL_EARLY_WAKEUP_ENABLE 0x01 /* Early wakeup time */ | ||
| 240 | |||
| 241 | |||
| 242 | struct cmd_join { | ||
| 243 | struct wl1251_cmd_header header; | ||
| 244 | |||
| 245 | u32 bssid_lsb; | ||
| 246 | u16 bssid_msb; | ||
| 247 | u16 beacon_interval; /* in TBTTs */ | ||
| 248 | u32 rx_config_options; | ||
| 249 | u32 rx_filter_options; | ||
| 250 | |||
| 251 | /* | ||
| 252 | * The target uses this field to determine the rate at | ||
| 253 | * which to transmit control frame responses (such as | ||
| 254 | * ACK or CTS frames). | ||
| 255 | */ | ||
| 256 | u16 basic_rate_set; | ||
| 257 | u8 dtim_interval; | ||
| 258 | u8 tx_ctrl_frame_rate; /* OBSOLETE */ | ||
| 259 | u8 tx_ctrl_frame_mod; /* OBSOLETE */ | ||
| 260 | /* | ||
| 261 | * bits 0-2: This bitwise field specifies the type | ||
| 262 | * of BSS to start or join (BSS_TYPE_*). | ||
| 263 | * bit 4: Band - The radio band in which to join | ||
| 264 | * or start. | ||
| 265 | * 0 - 2.4GHz band | ||
| 266 | * 1 - 5GHz band | ||
| 267 | * bits 3, 5-7: Reserved | ||
| 268 | */ | ||
| 269 | u8 bss_type; | ||
| 270 | u8 channel; | ||
| 271 | u8 ssid_len; | ||
| 272 | u8 ssid[IW_ESSID_MAX_SIZE]; | ||
| 273 | u8 ctrl; /* JOIN_CMD_CTRL_* */ | ||
| 274 | u8 tx_mgt_frame_rate; /* OBSOLETE */ | ||
| 275 | u8 tx_mgt_frame_mod; /* OBSOLETE */ | ||
| 276 | u8 reserved; | ||
| 277 | } __packed; | ||
| 278 | |||
| 279 | struct cmd_enabledisable_path { | ||
| 280 | struct wl1251_cmd_header header; | ||
| 281 | |||
| 282 | u8 channel; | ||
| 283 | u8 padding[3]; | ||
| 284 | } __packed; | ||
| 285 | |||
| 286 | #define WL1251_MAX_TEMPLATE_SIZE 300 | ||
| 287 | |||
| 288 | struct wl1251_cmd_packet_template { | ||
| 289 | struct wl1251_cmd_header header; | ||
| 290 | |||
| 291 | __le16 size; | ||
| 292 | u8 data[0]; | ||
| 293 | } __packed; | ||
| 294 | |||
| 295 | #define TIM_ELE_ID 5 | ||
| 296 | #define PARTIAL_VBM_MAX 251 | ||
| 297 | |||
| 298 | struct wl1251_tim { | ||
| 299 | u8 identity; | ||
| 300 | u8 length; | ||
| 301 | u8 dtim_count; | ||
| 302 | u8 dtim_period; | ||
| 303 | u8 bitmap_ctrl; | ||
| 304 | u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ | ||
| 305 | } __packed; | ||
| 306 | |||
| 307 | /* Virtual Bit Map update */ | ||
| 308 | struct wl1251_cmd_vbm_update { | ||
| 309 | struct wl1251_cmd_header header; | ||
| 310 | __le16 len; | ||
| 311 | u8 padding[2]; | ||
| 312 | struct wl1251_tim tim; | ||
| 313 | } __packed; | ||
| 314 | |||
| 315 | enum wl1251_cmd_ps_mode { | ||
| 316 | CHIP_ACTIVE_MODE, | ||
| 317 | CHIP_POWER_SAVE_MODE | ||
| 318 | }; | ||
| 319 | |||
| 320 | struct wl1251_cmd_ps_params { | ||
| 321 | struct wl1251_cmd_header header; | ||
| 322 | |||
| 323 | u8 ps_mode; /* STATION_* */ | ||
| 324 | u8 send_null_data; /* Do we have to send NULL data packet ? */ | ||
| 325 | u8 retries; /* Number of retires for the initial NULL data packet */ | ||
| 326 | |||
| 327 | /* | ||
| 328 | * TUs during which the target stays awake after switching | ||
| 329 | * to power save mode. | ||
| 330 | */ | ||
| 331 | u8 hang_over_period; | ||
| 332 | u16 null_data_rate; | ||
| 333 | u8 pad[2]; | ||
| 334 | } __packed; | ||
| 335 | |||
| 336 | struct wl1251_cmd_trigger_scan_to { | ||
| 337 | struct wl1251_cmd_header header; | ||
| 338 | |||
| 339 | u32 timeout; | ||
| 340 | } __packed; | ||
| 341 | |||
| 342 | /* HW encryption keys */ | ||
| 343 | #define NUM_ACCESS_CATEGORIES_COPY 4 | ||
| 344 | #define MAX_KEY_SIZE 32 | ||
| 345 | |||
| 346 | /* When set, disable HW encryption */ | ||
| 347 | #define DF_ENCRYPTION_DISABLE 0x01 | ||
| 348 | /* When set, disable HW decryption */ | ||
| 349 | #define DF_SNIFF_MODE_ENABLE 0x80 | ||
| 350 | |||
| 351 | enum wl1251_cmd_key_action { | ||
| 352 | KEY_ADD_OR_REPLACE = 1, | ||
| 353 | KEY_REMOVE = 2, | ||
| 354 | KEY_SET_ID = 3, | ||
| 355 | MAX_KEY_ACTION = 0xffff, | ||
| 356 | }; | ||
| 357 | |||
| 358 | enum wl1251_cmd_key_type { | ||
| 359 | KEY_WEP_DEFAULT = 0, | ||
| 360 | KEY_WEP_ADDR = 1, | ||
| 361 | KEY_AES_GROUP = 4, | ||
| 362 | KEY_AES_PAIRWISE = 5, | ||
| 363 | KEY_WEP_GROUP = 6, | ||
| 364 | KEY_TKIP_MIC_GROUP = 10, | ||
| 365 | KEY_TKIP_MIC_PAIRWISE = 11, | ||
| 366 | }; | ||
| 367 | |||
| 368 | /* | ||
| 369 | * | ||
| 370 | * key_type_e key size key format | ||
| 371 | * ---------- --------- ---------- | ||
| 372 | * 0x00 5, 13, 29 Key data | ||
| 373 | * 0x01 5, 13, 29 Key data | ||
| 374 | * 0x04 16 16 bytes of key data | ||
| 375 | * 0x05 16 16 bytes of key data | ||
| 376 | * 0x0a 32 16 bytes of TKIP key data | ||
| 377 | * 8 bytes of RX MIC key data | ||
| 378 | * 8 bytes of TX MIC key data | ||
| 379 | * 0x0b 32 16 bytes of TKIP key data | ||
| 380 | * 8 bytes of RX MIC key data | ||
| 381 | * 8 bytes of TX MIC key data | ||
| 382 | * | ||
| 383 | */ | ||
| 384 | |||
| 385 | struct wl1251_cmd_set_keys { | ||
| 386 | struct wl1251_cmd_header header; | ||
| 387 | |||
| 388 | /* Ignored for default WEP key */ | ||
| 389 | u8 addr[ETH_ALEN]; | ||
| 390 | |||
| 391 | /* key_action_e */ | ||
| 392 | u16 key_action; | ||
| 393 | |||
| 394 | u16 reserved_1; | ||
| 395 | |||
| 396 | /* key size in bytes */ | ||
| 397 | u8 key_size; | ||
| 398 | |||
| 399 | /* key_type_e */ | ||
| 400 | u8 key_type; | ||
| 401 | u8 ssid_profile; | ||
| 402 | |||
| 403 | /* | ||
| 404 | * TKIP, AES: frame's key id field. | ||
| 405 | * For WEP default key: key id; | ||
| 406 | */ | ||
| 407 | u8 id; | ||
| 408 | u8 reserved_2[6]; | ||
| 409 | u8 key[MAX_KEY_SIZE]; | ||
| 410 | u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; | ||
| 411 | u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; | ||
| 412 | } __packed; | ||
| 413 | |||
| 414 | |||
| 415 | #endif /* __WL1251_CMD_H__ */ | ||
diff --git a/drivers/net/wireless/wl1251/debugfs.c b/drivers/net/wireless/wl1251/debugfs.c new file mode 100644 index 00000000000..6c274007d20 --- /dev/null +++ b/drivers/net/wireless/wl1251/debugfs.c | |||
| @@ -0,0 +1,545 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Nokia Corporation | ||
| 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 "debugfs.h" | ||
| 23 | |||
| 24 | #include <linux/skbuff.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | |||
| 27 | #include "wl1251.h" | ||
| 28 | #include "acx.h" | ||
| 29 | #include "ps.h" | ||
| 30 | |||
| 31 | /* ms */ | ||
| 32 | #define WL1251_DEBUGFS_STATS_LIFETIME 1000 | ||
| 33 | |||
| 34 | /* debugfs macros idea from mac80211 */ | ||
| 35 | |||
| 36 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | ||
| 37 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
| 38 | size_t count, loff_t *ppos) \ | ||
| 39 | { \ | ||
| 40 | struct wl1251 *wl = file->private_data; \ | ||
| 41 | char buf[buflen]; \ | ||
| 42 | int res; \ | ||
| 43 | \ | ||
| 44 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
| 45 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
| 46 | } \ | ||
| 47 | \ | ||
| 48 | static const struct file_operations name## _ops = { \ | ||
| 49 | .read = name## _read, \ | ||
| 50 | .open = wl1251_open_file_generic, \ | ||
| 51 | .llseek = generic_file_llseek, \ | ||
| 52 | }; | ||
| 53 | |||
| 54 | #define DEBUGFS_ADD(name, parent) \ | ||
| 55 | wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ | ||
| 56 | wl, &name## _ops); \ | ||
| 57 | if (IS_ERR(wl->debugfs.name)) { \ | ||
| 58 | ret = PTR_ERR(wl->debugfs.name); \ | ||
| 59 | wl->debugfs.name = NULL; \ | ||
| 60 | goto out; \ | ||
| 61 | } | ||
| 62 | |||
| 63 | #define DEBUGFS_DEL(name) \ | ||
| 64 | do { \ | ||
| 65 | debugfs_remove(wl->debugfs.name); \ | ||
| 66 | wl->debugfs.name = NULL; \ | ||
| 67 | } while (0) | ||
| 68 | |||
| 69 | #define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ | ||
| 70 | static ssize_t sub## _ ##name## _read(struct file *file, \ | ||
| 71 | char __user *userbuf, \ | ||
| 72 | size_t count, loff_t *ppos) \ | ||
| 73 | { \ | ||
| 74 | struct wl1251 *wl = file->private_data; \ | ||
| 75 | char buf[buflen]; \ | ||
| 76 | int res; \ | ||
| 77 | \ | ||
| 78 | wl1251_debugfs_update_stats(wl); \ | ||
| 79 | \ | ||
| 80 | res = scnprintf(buf, buflen, fmt "\n", \ | ||
| 81 | wl->stats.fw_stats->sub.name); \ | ||
| 82 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
| 83 | } \ | ||
| 84 | \ | ||
| 85 | static const struct file_operations sub## _ ##name## _ops = { \ | ||
| 86 | .read = sub## _ ##name## _read, \ | ||
| 87 | .open = wl1251_open_file_generic, \ | ||
| 88 | .llseek = generic_file_llseek, \ | ||
| 89 | }; | ||
| 90 | |||
| 91 | #define DEBUGFS_FWSTATS_ADD(sub, name) \ | ||
| 92 | DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) | ||
| 93 | |||
| 94 | #define DEBUGFS_FWSTATS_DEL(sub, name) \ | ||
| 95 | DEBUGFS_DEL(sub## _ ##name) | ||
| 96 | |||
| 97 | static void wl1251_debugfs_update_stats(struct wl1251 *wl) | ||
| 98 | { | ||
| 99 | int ret; | ||
| 100 | |||
| 101 | mutex_lock(&wl->mutex); | ||
| 102 | |||
| 103 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 104 | if (ret < 0) | ||
| 105 | goto out; | ||
| 106 | |||
| 107 | if (wl->state == WL1251_STATE_ON && | ||
| 108 | time_after(jiffies, wl->stats.fw_stats_update + | ||
| 109 | msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) { | ||
| 110 | wl1251_acx_statistics(wl, wl->stats.fw_stats); | ||
| 111 | wl->stats.fw_stats_update = jiffies; | ||
| 112 | } | ||
| 113 | |||
| 114 | wl1251_ps_elp_sleep(wl); | ||
| 115 | |||
| 116 | out: | ||
| 117 | mutex_unlock(&wl->mutex); | ||
| 118 | } | ||
| 119 | |||
| 120 | static int wl1251_open_file_generic(struct inode *inode, struct file *file) | ||
| 121 | { | ||
| 122 | file->private_data = inode->i_private; | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); | ||
| 127 | |||
| 128 | DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); | ||
| 129 | DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); | ||
| 130 | DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); | ||
| 131 | DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); | ||
| 132 | DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); | ||
| 133 | DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); | ||
| 134 | DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); | ||
| 135 | DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); | ||
| 136 | |||
| 137 | DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); | ||
| 138 | DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); | ||
| 139 | DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); | ||
| 140 | DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); | ||
| 141 | |||
| 142 | DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); | ||
| 143 | DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); | ||
| 144 | DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); | ||
| 145 | DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); | ||
| 146 | DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); | ||
| 147 | DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); | ||
| 148 | DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); | ||
| 149 | DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); | ||
| 150 | DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); | ||
| 151 | DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); | ||
| 152 | DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); | ||
| 153 | DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); | ||
| 154 | DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); | ||
| 155 | DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); | ||
| 156 | DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); | ||
| 157 | DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); | ||
| 158 | DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); | ||
| 159 | DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); | ||
| 160 | |||
| 161 | DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); | ||
| 162 | DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); | ||
| 163 | /* skipping wep.reserved */ | ||
| 164 | DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); | ||
| 165 | DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); | ||
| 166 | DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); | ||
| 167 | DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); | ||
| 168 | |||
| 169 | DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); | ||
| 170 | DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); | ||
| 171 | DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); | ||
| 172 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); | ||
| 173 | DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); | ||
| 174 | DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); | ||
| 175 | DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); | ||
| 176 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); | ||
| 177 | DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); | ||
| 178 | DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); | ||
| 179 | DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); | ||
| 180 | DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); | ||
| 181 | /* skipping cont_miss_bcns_spread for now */ | ||
| 182 | DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); | ||
| 183 | |||
| 184 | DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); | ||
| 185 | DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); | ||
| 186 | |||
| 187 | DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); | ||
| 188 | DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); | ||
| 189 | DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); | ||
| 190 | DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); | ||
| 191 | DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); | ||
| 192 | DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); | ||
| 193 | |||
| 194 | DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); | ||
| 195 | DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); | ||
| 196 | DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); | ||
| 197 | DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); | ||
| 198 | DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); | ||
| 199 | DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); | ||
| 200 | DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); | ||
| 201 | DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); | ||
| 202 | |||
| 203 | DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); | ||
| 204 | DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); | ||
| 205 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); | ||
| 206 | DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); | ||
| 207 | DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); | ||
| 208 | DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); | ||
| 209 | DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); | ||
| 210 | |||
| 211 | DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); | ||
| 212 | DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); | ||
| 213 | DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, | ||
| 214 | 20, "%u"); | ||
| 215 | DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); | ||
| 216 | DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); | ||
| 217 | |||
| 218 | DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); | ||
| 219 | DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", | ||
| 220 | wl->stats.excessive_retries); | ||
| 221 | |||
| 222 | static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, | ||
| 223 | size_t count, loff_t *ppos) | ||
| 224 | { | ||
| 225 | struct wl1251 *wl = file->private_data; | ||
| 226 | u32 queue_len; | ||
| 227 | char buf[20]; | ||
| 228 | int res; | ||
| 229 | |||
| 230 | queue_len = skb_queue_len(&wl->tx_queue); | ||
| 231 | |||
| 232 | res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); | ||
| 233 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
| 234 | } | ||
| 235 | |||
| 236 | static const struct file_operations tx_queue_len_ops = { | ||
| 237 | .read = tx_queue_len_read, | ||
| 238 | .open = wl1251_open_file_generic, | ||
| 239 | .llseek = generic_file_llseek, | ||
| 240 | }; | ||
| 241 | |||
| 242 | static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, | ||
| 243 | size_t count, loff_t *ppos) | ||
| 244 | { | ||
| 245 | struct wl1251 *wl = file->private_data; | ||
| 246 | char buf[3], status; | ||
| 247 | int len; | ||
| 248 | |||
| 249 | if (wl->tx_queue_stopped) | ||
| 250 | status = 's'; | ||
| 251 | else | ||
| 252 | status = 'r'; | ||
| 253 | |||
| 254 | len = scnprintf(buf, sizeof(buf), "%c\n", status); | ||
| 255 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
| 256 | } | ||
| 257 | |||
| 258 | static const struct file_operations tx_queue_status_ops = { | ||
| 259 | .read = tx_queue_status_read, | ||
| 260 | .open = wl1251_open_file_generic, | ||
| 261 | .llseek = generic_file_llseek, | ||
| 262 | }; | ||
| 263 | |||
| 264 | static void wl1251_debugfs_delete_files(struct wl1251 *wl) | ||
| 265 | { | ||
| 266 | DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); | ||
| 267 | |||
| 268 | DEBUGFS_FWSTATS_DEL(rx, out_of_mem); | ||
| 269 | DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); | ||
| 270 | DEBUGFS_FWSTATS_DEL(rx, hw_stuck); | ||
| 271 | DEBUGFS_FWSTATS_DEL(rx, dropped); | ||
| 272 | DEBUGFS_FWSTATS_DEL(rx, fcs_err); | ||
| 273 | DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); | ||
| 274 | DEBUGFS_FWSTATS_DEL(rx, path_reset); | ||
| 275 | DEBUGFS_FWSTATS_DEL(rx, reset_counter); | ||
| 276 | |||
| 277 | DEBUGFS_FWSTATS_DEL(dma, rx_requested); | ||
| 278 | DEBUGFS_FWSTATS_DEL(dma, rx_errors); | ||
| 279 | DEBUGFS_FWSTATS_DEL(dma, tx_requested); | ||
| 280 | DEBUGFS_FWSTATS_DEL(dma, tx_errors); | ||
| 281 | |||
| 282 | DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); | ||
| 283 | DEBUGFS_FWSTATS_DEL(isr, fiqs); | ||
| 284 | DEBUGFS_FWSTATS_DEL(isr, rx_headers); | ||
| 285 | DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); | ||
| 286 | DEBUGFS_FWSTATS_DEL(isr, rx_rdys); | ||
| 287 | DEBUGFS_FWSTATS_DEL(isr, irqs); | ||
| 288 | DEBUGFS_FWSTATS_DEL(isr, tx_procs); | ||
| 289 | DEBUGFS_FWSTATS_DEL(isr, decrypt_done); | ||
| 290 | DEBUGFS_FWSTATS_DEL(isr, dma0_done); | ||
| 291 | DEBUGFS_FWSTATS_DEL(isr, dma1_done); | ||
| 292 | DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); | ||
| 293 | DEBUGFS_FWSTATS_DEL(isr, commands); | ||
| 294 | DEBUGFS_FWSTATS_DEL(isr, rx_procs); | ||
| 295 | DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); | ||
| 296 | DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); | ||
| 297 | DEBUGFS_FWSTATS_DEL(isr, pci_pm); | ||
| 298 | DEBUGFS_FWSTATS_DEL(isr, wakeups); | ||
| 299 | DEBUGFS_FWSTATS_DEL(isr, low_rssi); | ||
| 300 | |||
| 301 | DEBUGFS_FWSTATS_DEL(wep, addr_key_count); | ||
| 302 | DEBUGFS_FWSTATS_DEL(wep, default_key_count); | ||
| 303 | /* skipping wep.reserved */ | ||
| 304 | DEBUGFS_FWSTATS_DEL(wep, key_not_found); | ||
| 305 | DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); | ||
| 306 | DEBUGFS_FWSTATS_DEL(wep, packets); | ||
| 307 | DEBUGFS_FWSTATS_DEL(wep, interrupt); | ||
| 308 | |||
| 309 | DEBUGFS_FWSTATS_DEL(pwr, ps_enter); | ||
| 310 | DEBUGFS_FWSTATS_DEL(pwr, elp_enter); | ||
| 311 | DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); | ||
| 312 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); | ||
| 313 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); | ||
| 314 | DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); | ||
| 315 | DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); | ||
| 316 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); | ||
| 317 | DEBUGFS_FWSTATS_DEL(pwr, power_save_off); | ||
| 318 | DEBUGFS_FWSTATS_DEL(pwr, enable_ps); | ||
| 319 | DEBUGFS_FWSTATS_DEL(pwr, disable_ps); | ||
| 320 | DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); | ||
| 321 | /* skipping cont_miss_bcns_spread for now */ | ||
| 322 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); | ||
| 323 | |||
| 324 | DEBUGFS_FWSTATS_DEL(mic, rx_pkts); | ||
| 325 | DEBUGFS_FWSTATS_DEL(mic, calc_failure); | ||
| 326 | |||
| 327 | DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); | ||
| 328 | DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); | ||
| 329 | DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); | ||
| 330 | DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); | ||
| 331 | DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); | ||
| 332 | DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); | ||
| 333 | |||
| 334 | DEBUGFS_FWSTATS_DEL(event, heart_beat); | ||
| 335 | DEBUGFS_FWSTATS_DEL(event, calibration); | ||
| 336 | DEBUGFS_FWSTATS_DEL(event, rx_mismatch); | ||
| 337 | DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); | ||
| 338 | DEBUGFS_FWSTATS_DEL(event, rx_pool); | ||
| 339 | DEBUGFS_FWSTATS_DEL(event, oom_late); | ||
| 340 | DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); | ||
| 341 | DEBUGFS_FWSTATS_DEL(event, tx_stuck); | ||
| 342 | |||
| 343 | DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); | ||
| 344 | DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); | ||
| 345 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); | ||
| 346 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); | ||
| 347 | DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); | ||
| 348 | DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); | ||
| 349 | DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); | ||
| 350 | |||
| 351 | DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); | ||
| 352 | DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); | ||
| 353 | DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
| 354 | DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
| 355 | DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
| 356 | |||
| 357 | DEBUGFS_DEL(tx_queue_len); | ||
| 358 | DEBUGFS_DEL(tx_queue_status); | ||
| 359 | DEBUGFS_DEL(retry_count); | ||
| 360 | DEBUGFS_DEL(excessive_retries); | ||
| 361 | } | ||
| 362 | |||
| 363 | static int wl1251_debugfs_add_files(struct wl1251 *wl) | ||
| 364 | { | ||
| 365 | int ret = 0; | ||
| 366 | |||
| 367 | DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); | ||
| 368 | |||
| 369 | DEBUGFS_FWSTATS_ADD(rx, out_of_mem); | ||
| 370 | DEBUGFS_FWSTATS_ADD(rx, hdr_overflow); | ||
| 371 | DEBUGFS_FWSTATS_ADD(rx, hw_stuck); | ||
| 372 | DEBUGFS_FWSTATS_ADD(rx, dropped); | ||
| 373 | DEBUGFS_FWSTATS_ADD(rx, fcs_err); | ||
| 374 | DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig); | ||
| 375 | DEBUGFS_FWSTATS_ADD(rx, path_reset); | ||
| 376 | DEBUGFS_FWSTATS_ADD(rx, reset_counter); | ||
| 377 | |||
| 378 | DEBUGFS_FWSTATS_ADD(dma, rx_requested); | ||
| 379 | DEBUGFS_FWSTATS_ADD(dma, rx_errors); | ||
| 380 | DEBUGFS_FWSTATS_ADD(dma, tx_requested); | ||
| 381 | DEBUGFS_FWSTATS_ADD(dma, tx_errors); | ||
| 382 | |||
| 383 | DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt); | ||
| 384 | DEBUGFS_FWSTATS_ADD(isr, fiqs); | ||
| 385 | DEBUGFS_FWSTATS_ADD(isr, rx_headers); | ||
| 386 | DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow); | ||
| 387 | DEBUGFS_FWSTATS_ADD(isr, rx_rdys); | ||
| 388 | DEBUGFS_FWSTATS_ADD(isr, irqs); | ||
| 389 | DEBUGFS_FWSTATS_ADD(isr, tx_procs); | ||
| 390 | DEBUGFS_FWSTATS_ADD(isr, decrypt_done); | ||
| 391 | DEBUGFS_FWSTATS_ADD(isr, dma0_done); | ||
| 392 | DEBUGFS_FWSTATS_ADD(isr, dma1_done); | ||
| 393 | DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete); | ||
| 394 | DEBUGFS_FWSTATS_ADD(isr, commands); | ||
| 395 | DEBUGFS_FWSTATS_ADD(isr, rx_procs); | ||
| 396 | DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes); | ||
| 397 | DEBUGFS_FWSTATS_ADD(isr, host_acknowledges); | ||
| 398 | DEBUGFS_FWSTATS_ADD(isr, pci_pm); | ||
| 399 | DEBUGFS_FWSTATS_ADD(isr, wakeups); | ||
| 400 | DEBUGFS_FWSTATS_ADD(isr, low_rssi); | ||
| 401 | |||
| 402 | DEBUGFS_FWSTATS_ADD(wep, addr_key_count); | ||
| 403 | DEBUGFS_FWSTATS_ADD(wep, default_key_count); | ||
| 404 | /* skipping wep.reserved */ | ||
| 405 | DEBUGFS_FWSTATS_ADD(wep, key_not_found); | ||
| 406 | DEBUGFS_FWSTATS_ADD(wep, decrypt_fail); | ||
| 407 | DEBUGFS_FWSTATS_ADD(wep, packets); | ||
| 408 | DEBUGFS_FWSTATS_ADD(wep, interrupt); | ||
| 409 | |||
| 410 | DEBUGFS_FWSTATS_ADD(pwr, ps_enter); | ||
| 411 | DEBUGFS_FWSTATS_ADD(pwr, elp_enter); | ||
| 412 | DEBUGFS_FWSTATS_ADD(pwr, missing_bcns); | ||
| 413 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_host); | ||
| 414 | DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp); | ||
| 415 | DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps); | ||
| 416 | DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps); | ||
| 417 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons); | ||
| 418 | DEBUGFS_FWSTATS_ADD(pwr, power_save_off); | ||
| 419 | DEBUGFS_FWSTATS_ADD(pwr, enable_ps); | ||
| 420 | DEBUGFS_FWSTATS_ADD(pwr, disable_ps); | ||
| 421 | DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps); | ||
| 422 | /* skipping cont_miss_bcns_spread for now */ | ||
| 423 | DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons); | ||
| 424 | |||
| 425 | DEBUGFS_FWSTATS_ADD(mic, rx_pkts); | ||
| 426 | DEBUGFS_FWSTATS_ADD(mic, calc_failure); | ||
| 427 | |||
| 428 | DEBUGFS_FWSTATS_ADD(aes, encrypt_fail); | ||
| 429 | DEBUGFS_FWSTATS_ADD(aes, decrypt_fail); | ||
| 430 | DEBUGFS_FWSTATS_ADD(aes, encrypt_packets); | ||
| 431 | DEBUGFS_FWSTATS_ADD(aes, decrypt_packets); | ||
| 432 | DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt); | ||
| 433 | DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt); | ||
| 434 | |||
| 435 | DEBUGFS_FWSTATS_ADD(event, heart_beat); | ||
| 436 | DEBUGFS_FWSTATS_ADD(event, calibration); | ||
| 437 | DEBUGFS_FWSTATS_ADD(event, rx_mismatch); | ||
| 438 | DEBUGFS_FWSTATS_ADD(event, rx_mem_empty); | ||
| 439 | DEBUGFS_FWSTATS_ADD(event, rx_pool); | ||
| 440 | DEBUGFS_FWSTATS_ADD(event, oom_late); | ||
| 441 | DEBUGFS_FWSTATS_ADD(event, phy_transmit_error); | ||
| 442 | DEBUGFS_FWSTATS_ADD(event, tx_stuck); | ||
| 443 | |||
| 444 | DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts); | ||
| 445 | DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts); | ||
| 446 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime); | ||
| 447 | DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn); | ||
| 448 | DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn); | ||
| 449 | DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization); | ||
| 450 | DEBUGFS_FWSTATS_ADD(ps, upsd_utilization); | ||
| 451 | |||
| 452 | DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop); | ||
| 453 | DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data); | ||
| 454 | DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
| 455 | DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
| 456 | DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
| 457 | |||
| 458 | DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); | ||
| 459 | DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir); | ||
| 460 | DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); | ||
| 461 | DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); | ||
| 462 | |||
| 463 | out: | ||
| 464 | if (ret < 0) | ||
| 465 | wl1251_debugfs_delete_files(wl); | ||
| 466 | |||
| 467 | return ret; | ||
| 468 | } | ||
| 469 | |||
| 470 | void wl1251_debugfs_reset(struct wl1251 *wl) | ||
| 471 | { | ||
| 472 | if (wl->stats.fw_stats != NULL) | ||
| 473 | memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); | ||
| 474 | wl->stats.retry_count = 0; | ||
| 475 | wl->stats.excessive_retries = 0; | ||
| 476 | } | ||
| 477 | |||
| 478 | int wl1251_debugfs_init(struct wl1251 *wl) | ||
| 479 | { | ||
| 480 | int ret; | ||
| 481 | |||
| 482 | wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
| 483 | |||
| 484 | if (IS_ERR(wl->debugfs.rootdir)) { | ||
| 485 | ret = PTR_ERR(wl->debugfs.rootdir); | ||
| 486 | wl->debugfs.rootdir = NULL; | ||
| 487 | goto err; | ||
| 488 | } | ||
| 489 | |||
| 490 | wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", | ||
| 491 | wl->debugfs.rootdir); | ||
| 492 | |||
| 493 | if (IS_ERR(wl->debugfs.fw_statistics)) { | ||
| 494 | ret = PTR_ERR(wl->debugfs.fw_statistics); | ||
| 495 | wl->debugfs.fw_statistics = NULL; | ||
| 496 | goto err_root; | ||
| 497 | } | ||
| 498 | |||
| 499 | wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), | ||
| 500 | GFP_KERNEL); | ||
| 501 | |||
| 502 | if (!wl->stats.fw_stats) { | ||
| 503 | ret = -ENOMEM; | ||
| 504 | goto err_fw; | ||
| 505 | } | ||
| 506 | |||
| 507 | wl->stats.fw_stats_update = jiffies; | ||
| 508 | |||
| 509 | ret = wl1251_debugfs_add_files(wl); | ||
| 510 | |||
| 511 | if (ret < 0) | ||
| 512 | goto err_file; | ||
| 513 | |||
| 514 | return 0; | ||
| 515 | |||
| 516 | err_file: | ||
| 517 | kfree(wl->stats.fw_stats); | ||
| 518 | wl->stats.fw_stats = NULL; | ||
| 519 | |||
| 520 | err_fw: | ||
| 521 | debugfs_remove(wl->debugfs.fw_statistics); | ||
| 522 | wl->debugfs.fw_statistics = NULL; | ||
| 523 | |||
| 524 | err_root: | ||
| 525 | debugfs_remove(wl->debugfs.rootdir); | ||
| 526 | wl->debugfs.rootdir = NULL; | ||
| 527 | |||
| 528 | err: | ||
| 529 | return ret; | ||
| 530 | } | ||
| 531 | |||
| 532 | void wl1251_debugfs_exit(struct wl1251 *wl) | ||
| 533 | { | ||
| 534 | wl1251_debugfs_delete_files(wl); | ||
| 535 | |||
| 536 | kfree(wl->stats.fw_stats); | ||
| 537 | wl->stats.fw_stats = NULL; | ||
| 538 | |||
| 539 | debugfs_remove(wl->debugfs.fw_statistics); | ||
| 540 | wl->debugfs.fw_statistics = NULL; | ||
| 541 | |||
| 542 | debugfs_remove(wl->debugfs.rootdir); | ||
| 543 | wl->debugfs.rootdir = NULL; | ||
| 544 | |||
| 545 | } | ||
diff --git a/drivers/net/wireless/wl1251/debugfs.h b/drivers/net/wireless/wl1251/debugfs.h new file mode 100644 index 00000000000..b3417c02a21 --- /dev/null +++ b/drivers/net/wireless/wl1251/debugfs.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Nokia Corporation | ||
| 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 | #ifndef WL1251_DEBUGFS_H | ||
| 23 | #define WL1251_DEBUGFS_H | ||
| 24 | |||
| 25 | #include "wl1251.h" | ||
| 26 | |||
| 27 | int wl1251_debugfs_init(struct wl1251 *wl); | ||
| 28 | void wl1251_debugfs_exit(struct wl1251 *wl); | ||
| 29 | void wl1251_debugfs_reset(struct wl1251 *wl); | ||
| 30 | |||
| 31 | #endif /* WL1251_DEBUGFS_H */ | ||
diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c new file mode 100644 index 00000000000..9f15ccaf8f0 --- /dev/null +++ b/drivers/net/wireless/wl1251/event.c | |||
| @@ -0,0 +1,188 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include "wl1251.h" | ||
| 24 | #include "reg.h" | ||
| 25 | #include "io.h" | ||
| 26 | #include "event.h" | ||
| 27 | #include "ps.h" | ||
| 28 | |||
| 29 | static int wl1251_event_scan_complete(struct wl1251 *wl, | ||
| 30 | struct event_mailbox *mbox) | ||
| 31 | { | ||
| 32 | wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", | ||
| 33 | mbox->scheduled_scan_status, | ||
| 34 | mbox->scheduled_scan_channels); | ||
| 35 | |||
| 36 | if (wl->scanning) { | ||
| 37 | ieee80211_scan_completed(wl->hw, false); | ||
| 38 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); | ||
| 39 | wl->scanning = false; | ||
| 40 | } | ||
| 41 | |||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | static void wl1251_event_mbox_dump(struct event_mailbox *mbox) | ||
| 46 | { | ||
| 47 | wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); | ||
| 48 | wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector); | ||
| 49 | wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); | ||
| 50 | } | ||
| 51 | |||
| 52 | static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) | ||
| 53 | { | ||
| 54 | int ret; | ||
| 55 | u32 vector; | ||
| 56 | |||
| 57 | wl1251_event_mbox_dump(mbox); | ||
| 58 | |||
| 59 | vector = mbox->events_vector & ~(mbox->events_mask); | ||
| 60 | wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector); | ||
| 61 | |||
| 62 | if (vector & SCAN_COMPLETE_EVENT_ID) { | ||
| 63 | ret = wl1251_event_scan_complete(wl, mbox); | ||
| 64 | if (ret < 0) | ||
| 65 | return ret; | ||
| 66 | } | ||
| 67 | |||
| 68 | if (vector & BSS_LOSE_EVENT_ID) { | ||
| 69 | wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); | ||
| 70 | |||
| 71 | if (wl->psm_requested && | ||
| 72 | wl->station_mode != STATION_ACTIVE_MODE) { | ||
| 73 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
| 74 | if (ret < 0) | ||
| 75 | return ret; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && | ||
| 80 | wl->station_mode != STATION_ACTIVE_MODE) { | ||
| 81 | wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); | ||
| 82 | |||
| 83 | /* indicate to the stack, that beacons have been lost */ | ||
| 84 | ieee80211_beacon_loss(wl->vif); | ||
| 85 | } | ||
| 86 | |||
| 87 | if (vector & REGAINED_BSS_EVENT_ID) { | ||
| 88 | if (wl->psm_requested) { | ||
| 89 | ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||
| 90 | if (ret < 0) | ||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | if (wl->vif && wl->rssi_thold) { | ||
| 96 | if (vector & ROAMING_TRIGGER_LOW_RSSI_EVENT_ID) { | ||
| 97 | wl1251_debug(DEBUG_EVENT, | ||
| 98 | "ROAMING_TRIGGER_LOW_RSSI_EVENT"); | ||
| 99 | ieee80211_cqm_rssi_notify(wl->vif, | ||
| 100 | NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, | ||
| 101 | GFP_KERNEL); | ||
| 102 | } | ||
| 103 | |||
| 104 | if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) { | ||
| 105 | wl1251_debug(DEBUG_EVENT, | ||
| 106 | "ROAMING_TRIGGER_REGAINED_RSSI_EVENT"); | ||
| 107 | ieee80211_cqm_rssi_notify(wl->vif, | ||
| 108 | NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, | ||
| 109 | GFP_KERNEL); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* | ||
| 117 | * Poll the mailbox event field until any of the bits in the mask is set or a | ||
| 118 | * timeout occurs (WL1251_EVENT_TIMEOUT in msecs) | ||
| 119 | */ | ||
| 120 | int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms) | ||
| 121 | { | ||
| 122 | u32 events_vector, event; | ||
| 123 | unsigned long timeout; | ||
| 124 | |||
| 125 | timeout = jiffies + msecs_to_jiffies(timeout_ms); | ||
| 126 | |||
| 127 | do { | ||
| 128 | if (time_after(jiffies, timeout)) | ||
| 129 | return -ETIMEDOUT; | ||
| 130 | |||
| 131 | msleep(1); | ||
| 132 | |||
| 133 | /* read from both event fields */ | ||
| 134 | wl1251_mem_read(wl, wl->mbox_ptr[0], &events_vector, | ||
| 135 | sizeof(events_vector)); | ||
| 136 | event = events_vector & mask; | ||
| 137 | wl1251_mem_read(wl, wl->mbox_ptr[1], &events_vector, | ||
| 138 | sizeof(events_vector)); | ||
| 139 | event |= events_vector & mask; | ||
| 140 | } while (!event); | ||
| 141 | |||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | int wl1251_event_unmask(struct wl1251 *wl) | ||
| 146 | { | ||
| 147 | int ret; | ||
| 148 | |||
| 149 | ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask)); | ||
| 150 | if (ret < 0) | ||
| 151 | return ret; | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | void wl1251_event_mbox_config(struct wl1251 *wl) | ||
| 157 | { | ||
| 158 | wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR); | ||
| 159 | wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); | ||
| 160 | |||
| 161 | wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", | ||
| 162 | wl->mbox_ptr[0], wl->mbox_ptr[1]); | ||
| 163 | } | ||
| 164 | |||
| 165 | int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num) | ||
| 166 | { | ||
| 167 | struct event_mailbox mbox; | ||
| 168 | int ret; | ||
| 169 | |||
| 170 | wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); | ||
| 171 | |||
| 172 | if (mbox_num > 1) | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | /* first we read the mbox descriptor */ | ||
| 176 | wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, | ||
| 177 | sizeof(struct event_mailbox)); | ||
| 178 | |||
| 179 | /* process the descriptor */ | ||
| 180 | ret = wl1251_event_process(wl, &mbox); | ||
| 181 | if (ret < 0) | ||
| 182 | return ret; | ||
| 183 | |||
| 184 | /* then we let the firmware know it can go on...*/ | ||
| 185 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
diff --git a/drivers/net/wireless/wl1251/event.h b/drivers/net/wireless/wl1251/event.h new file mode 100644 index 00000000000..30eb5d150bf --- /dev/null +++ b/drivers/net/wireless/wl1251/event.h | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __WL1251_EVENT_H__ | ||
| 24 | #define __WL1251_EVENT_H__ | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Mbox events | ||
| 28 | * | ||
| 29 | * The event mechanism is based on a pair of event buffers (buffers A and | ||
| 30 | * B) at fixed locations in the target's memory. The host processes one | ||
| 31 | * buffer while the other buffer continues to collect events. If the host | ||
| 32 | * is not processing events, an interrupt is issued to signal that a buffer | ||
| 33 | * is ready. Once the host is done with processing events from one buffer, | ||
| 34 | * it signals the target (with an ACK interrupt) that the event buffer is | ||
| 35 | * free. | ||
| 36 | */ | ||
| 37 | |||
| 38 | enum { | ||
| 39 | RESERVED1_EVENT_ID = BIT(0), | ||
| 40 | RESERVED2_EVENT_ID = BIT(1), | ||
| 41 | MEASUREMENT_START_EVENT_ID = BIT(2), | ||
| 42 | SCAN_COMPLETE_EVENT_ID = BIT(3), | ||
| 43 | CALIBRATION_COMPLETE_EVENT_ID = BIT(4), | ||
| 44 | ROAMING_TRIGGER_LOW_RSSI_EVENT_ID = BIT(5), | ||
| 45 | PS_REPORT_EVENT_ID = BIT(6), | ||
| 46 | SYNCHRONIZATION_TIMEOUT_EVENT_ID = BIT(7), | ||
| 47 | HEALTH_REPORT_EVENT_ID = BIT(8), | ||
| 48 | ACI_DETECTION_EVENT_ID = BIT(9), | ||
| 49 | DEBUG_REPORT_EVENT_ID = BIT(10), | ||
| 50 | MAC_STATUS_EVENT_ID = BIT(11), | ||
| 51 | DISCONNECT_EVENT_COMPLETE_ID = BIT(12), | ||
| 52 | JOIN_EVENT_COMPLETE_ID = BIT(13), | ||
| 53 | CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(14), | ||
| 54 | BSS_LOSE_EVENT_ID = BIT(15), | ||
| 55 | ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(16), | ||
| 56 | MEASUREMENT_COMPLETE_EVENT_ID = BIT(17), | ||
| 57 | AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(18), | ||
| 58 | SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(19), | ||
| 59 | PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(20), | ||
| 60 | RESET_BSS_EVENT_ID = BIT(21), | ||
| 61 | REGAINED_BSS_EVENT_ID = BIT(22), | ||
| 62 | ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID = BIT(23), | ||
| 63 | ROAMING_TRIGGER_LOW_SNR_EVENT_ID = BIT(24), | ||
| 64 | ROAMING_TRIGGER_REGAINED_SNR_EVENT_ID = BIT(25), | ||
| 65 | |||
| 66 | DBG_EVENT_ID = BIT(26), | ||
| 67 | BT_PTA_SENSE_EVENT_ID = BIT(27), | ||
| 68 | BT_PTA_PREDICTION_EVENT_ID = BIT(28), | ||
| 69 | BT_PTA_AVALANCHE_EVENT_ID = BIT(29), | ||
| 70 | |||
| 71 | PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(30), | ||
| 72 | |||
| 73 | EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, | ||
| 74 | }; | ||
| 75 | |||
| 76 | struct event_debug_report { | ||
| 77 | u8 debug_event_id; | ||
| 78 | u8 num_params; | ||
| 79 | u16 pad; | ||
| 80 | u32 report_1; | ||
| 81 | u32 report_2; | ||
| 82 | u32 report_3; | ||
| 83 | } __packed; | ||
| 84 | |||
| 85 | struct event_mailbox { | ||
| 86 | u32 events_vector; | ||
| 87 | u32 events_mask; | ||
| 88 | u32 reserved_1; | ||
| 89 | u32 reserved_2; | ||
| 90 | |||
| 91 | char average_rssi_level; | ||
| 92 | u8 ps_status; | ||
| 93 | u8 channel_switch_status; | ||
| 94 | u8 scheduled_scan_status; | ||
| 95 | |||
| 96 | /* Channels scanned by the scheduled scan */ | ||
| 97 | u16 scheduled_scan_channels; | ||
| 98 | |||
| 99 | /* If bit 0 is set -> target's fatal error */ | ||
| 100 | u16 health_report; | ||
| 101 | u16 bad_fft_counter; | ||
| 102 | u8 bt_pta_sense_info; | ||
| 103 | u8 bt_pta_protective_info; | ||
| 104 | u32 reserved; | ||
| 105 | u32 debug_report[2]; | ||
| 106 | |||
| 107 | /* Number of FCS errors since last event */ | ||
| 108 | u32 fcs_err_counter; | ||
| 109 | |||
| 110 | struct event_debug_report report; | ||
| 111 | u8 average_snr_level; | ||
| 112 | u8 padding[19]; | ||
| 113 | } __packed; | ||
| 114 | |||
| 115 | int wl1251_event_unmask(struct wl1251 *wl); | ||
| 116 | void wl1251_event_mbox_config(struct wl1251 *wl); | ||
| 117 | int wl1251_event_handle(struct wl1251 *wl, u8 mbox); | ||
| 118 | int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms); | ||
| 119 | |||
| 120 | #endif | ||
diff --git a/drivers/net/wireless/wl1251/init.c b/drivers/net/wireless/wl1251/init.c new file mode 100644 index 00000000000..89b43d35473 --- /dev/null +++ b/drivers/net/wireless/wl1251/init.c | |||
| @@ -0,0 +1,423 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Nokia Corporation | ||
| 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 <linux/kernel.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | |||
| 26 | #include "init.h" | ||
| 27 | #include "wl12xx_80211.h" | ||
| 28 | #include "acx.h" | ||
| 29 | #include "cmd.h" | ||
| 30 | #include "reg.h" | ||
| 31 | |||
| 32 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl) | ||
| 33 | { | ||
| 34 | int ret; | ||
| 35 | |||
| 36 | ret = wl1251_acx_feature_cfg(wl); | ||
| 37 | if (ret < 0) { | ||
| 38 | wl1251_warning("couldn't set feature config"); | ||
| 39 | return ret; | ||
| 40 | } | ||
| 41 | |||
| 42 | ret = wl1251_acx_default_key(wl, wl->default_key); | ||
| 43 | if (ret < 0) { | ||
| 44 | wl1251_warning("couldn't set default key"); | ||
| 45 | return ret; | ||
| 46 | } | ||
| 47 | |||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | int wl1251_hw_init_templates_config(struct wl1251 *wl) | ||
| 52 | { | ||
| 53 | int ret; | ||
| 54 | u8 partial_vbm[PARTIAL_VBM_MAX]; | ||
| 55 | |||
| 56 | /* send empty templates for fw memory reservation */ | ||
| 57 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL, | ||
| 58 | sizeof(struct wl12xx_probe_req_template)); | ||
| 59 | if (ret < 0) | ||
| 60 | return ret; | ||
| 61 | |||
| 62 | ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL, | ||
| 63 | sizeof(struct wl12xx_null_data_template)); | ||
| 64 | if (ret < 0) | ||
| 65 | return ret; | ||
| 66 | |||
| 67 | ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL, | ||
| 68 | sizeof(struct wl12xx_ps_poll_template)); | ||
| 69 | if (ret < 0) | ||
| 70 | return ret; | ||
| 71 | |||
| 72 | ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL, | ||
| 73 | sizeof | ||
| 74 | (struct wl12xx_qos_null_data_template)); | ||
| 75 | if (ret < 0) | ||
| 76 | return ret; | ||
| 77 | |||
| 78 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL, | ||
| 79 | sizeof | ||
| 80 | (struct wl12xx_probe_resp_template)); | ||
| 81 | if (ret < 0) | ||
| 82 | return ret; | ||
| 83 | |||
| 84 | ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL, | ||
| 85 | sizeof | ||
| 86 | (struct wl12xx_beacon_template)); | ||
| 87 | if (ret < 0) | ||
| 88 | return ret; | ||
| 89 | |||
| 90 | /* tim templates, first reserve space then allocate an empty one */ | ||
| 91 | memset(partial_vbm, 0, PARTIAL_VBM_MAX); | ||
| 92 | ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0); | ||
| 93 | if (ret < 0) | ||
| 94 | return ret; | ||
| 95 | |||
| 96 | ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0); | ||
| 97 | if (ret < 0) | ||
| 98 | return ret; | ||
| 99 | |||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter) | ||
| 104 | { | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); | ||
| 108 | if (ret < 0) | ||
| 109 | return ret; | ||
| 110 | |||
| 111 | ret = wl1251_acx_rx_config(wl, config, filter); | ||
| 112 | if (ret < 0) | ||
| 113 | return ret; | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | int wl1251_hw_init_phy_config(struct wl1251 *wl) | ||
| 119 | { | ||
| 120 | int ret; | ||
| 121 | |||
| 122 | ret = wl1251_acx_pd_threshold(wl); | ||
| 123 | if (ret < 0) | ||
| 124 | return ret; | ||
| 125 | |||
| 126 | ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME); | ||
| 127 | if (ret < 0) | ||
| 128 | return ret; | ||
| 129 | |||
| 130 | ret = wl1251_acx_group_address_tbl(wl); | ||
| 131 | if (ret < 0) | ||
| 132 | return ret; | ||
| 133 | |||
| 134 | ret = wl1251_acx_service_period_timeout(wl); | ||
| 135 | if (ret < 0) | ||
| 136 | return ret; | ||
| 137 | |||
| 138 | ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); | ||
| 139 | if (ret < 0) | ||
| 140 | return ret; | ||
| 141 | |||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | int wl1251_hw_init_beacon_filter(struct wl1251 *wl) | ||
| 146 | { | ||
| 147 | int ret; | ||
| 148 | |||
| 149 | /* disable beacon filtering at this stage */ | ||
| 150 | ret = wl1251_acx_beacon_filter_opt(wl, false); | ||
| 151 | if (ret < 0) | ||
| 152 | return ret; | ||
| 153 | |||
| 154 | ret = wl1251_acx_beacon_filter_table(wl); | ||
| 155 | if (ret < 0) | ||
| 156 | return ret; | ||
| 157 | |||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | int wl1251_hw_init_pta(struct wl1251 *wl) | ||
| 162 | { | ||
| 163 | int ret; | ||
| 164 | |||
| 165 | ret = wl1251_acx_sg_enable(wl); | ||
| 166 | if (ret < 0) | ||
| 167 | return ret; | ||
| 168 | |||
| 169 | ret = wl1251_acx_sg_cfg(wl); | ||
| 170 | if (ret < 0) | ||
| 171 | return ret; | ||
| 172 | |||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | int wl1251_hw_init_energy_detection(struct wl1251 *wl) | ||
| 177 | { | ||
| 178 | int ret; | ||
| 179 | |||
| 180 | ret = wl1251_acx_cca_threshold(wl); | ||
| 181 | if (ret < 0) | ||
| 182 | return ret; | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl) | ||
| 188 | { | ||
| 189 | int ret; | ||
| 190 | |||
| 191 | ret = wl1251_acx_bcn_dtim_options(wl); | ||
| 192 | if (ret < 0) | ||
| 193 | return ret; | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | int wl1251_hw_init_power_auth(struct wl1251 *wl) | ||
| 199 | { | ||
| 200 | return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | ||
| 201 | } | ||
| 202 | |||
| 203 | int wl1251_hw_init_mem_config(struct wl1251 *wl) | ||
| 204 | { | ||
| 205 | int ret; | ||
| 206 | |||
| 207 | ret = wl1251_acx_mem_cfg(wl); | ||
| 208 | if (ret < 0) | ||
| 209 | return ret; | ||
| 210 | |||
| 211 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
| 212 | GFP_KERNEL); | ||
| 213 | if (!wl->target_mem_map) { | ||
| 214 | wl1251_error("couldn't allocate target memory map"); | ||
| 215 | return -ENOMEM; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* we now ask for the firmware built memory map */ | ||
| 219 | ret = wl1251_acx_mem_map(wl, wl->target_mem_map, | ||
| 220 | sizeof(struct wl1251_acx_mem_map)); | ||
| 221 | if (ret < 0) { | ||
| 222 | wl1251_error("couldn't retrieve firmware memory map"); | ||
| 223 | kfree(wl->target_mem_map); | ||
| 224 | wl->target_mem_map = NULL; | ||
| 225 | return ret; | ||
| 226 | } | ||
| 227 | |||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
| 232 | struct acx_tx_queue_qos_config *config, | ||
| 233 | u32 num_blocks) | ||
| 234 | { | ||
| 235 | config->qid = qid; | ||
| 236 | |||
| 237 | switch (qid) { | ||
| 238 | case QOS_AC_BE: | ||
| 239 | config->high_threshold = | ||
| 240 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
| 241 | config->low_threshold = | ||
| 242 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
| 243 | break; | ||
| 244 | case QOS_AC_BK: | ||
| 245 | config->high_threshold = | ||
| 246 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
| 247 | config->low_threshold = | ||
| 248 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
| 249 | break; | ||
| 250 | case QOS_AC_VI: | ||
| 251 | config->high_threshold = | ||
| 252 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
| 253 | config->low_threshold = | ||
| 254 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
| 255 | break; | ||
| 256 | case QOS_AC_VO: | ||
| 257 | config->high_threshold = | ||
| 258 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
| 259 | config->low_threshold = | ||
| 260 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
| 261 | break; | ||
| 262 | default: | ||
| 263 | wl1251_error("Invalid TX queue id: %d", qid); | ||
| 264 | return -EINVAL; | ||
| 265 | } | ||
| 266 | |||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | |||
| 270 | static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | ||
| 271 | { | ||
| 272 | struct acx_tx_queue_qos_config *config; | ||
| 273 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
| 274 | int ret, i; | ||
| 275 | |||
| 276 | wl1251_debug(DEBUG_ACX, "acx tx queue config"); | ||
| 277 | |||
| 278 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
| 279 | if (!config) { | ||
| 280 | ret = -ENOMEM; | ||
| 281 | goto out; | ||
| 282 | } | ||
| 283 | |||
| 284 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
| 285 | ret = wl1251_hw_init_txq_fill(i, config, | ||
| 286 | wl_mem_map->num_tx_mem_blocks); | ||
| 287 | if (ret < 0) | ||
| 288 | goto out; | ||
| 289 | |||
| 290 | ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, | ||
| 291 | config, sizeof(*config)); | ||
| 292 | if (ret < 0) | ||
| 293 | goto out; | ||
| 294 | } | ||
| 295 | |||
| 296 | wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE); | ||
| 297 | wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK); | ||
| 298 | wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI); | ||
| 299 | wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO); | ||
| 300 | |||
| 301 | out: | ||
| 302 | kfree(config); | ||
| 303 | return ret; | ||
| 304 | } | ||
| 305 | |||
| 306 | static int wl1251_hw_init_data_path_config(struct wl1251 *wl) | ||
| 307 | { | ||
| 308 | int ret; | ||
| 309 | |||
| 310 | /* asking for the data path parameters */ | ||
| 311 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
| 312 | GFP_KERNEL); | ||
| 313 | if (!wl->data_path) { | ||
| 314 | wl1251_error("Couldnt allocate data path parameters"); | ||
| 315 | return -ENOMEM; | ||
| 316 | } | ||
| 317 | |||
| 318 | ret = wl1251_acx_data_path_params(wl, wl->data_path); | ||
| 319 | if (ret < 0) { | ||
| 320 | kfree(wl->data_path); | ||
| 321 | wl->data_path = NULL; | ||
| 322 | return ret; | ||
| 323 | } | ||
| 324 | |||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | |||
| 328 | |||
| 329 | int wl1251_hw_init(struct wl1251 *wl) | ||
| 330 | { | ||
| 331 | struct wl1251_acx_mem_map *wl_mem_map; | ||
| 332 | int ret; | ||
| 333 | |||
| 334 | ret = wl1251_hw_init_hwenc_config(wl); | ||
| 335 | if (ret < 0) | ||
| 336 | return ret; | ||
| 337 | |||
| 338 | /* Template settings */ | ||
| 339 | ret = wl1251_hw_init_templates_config(wl); | ||
| 340 | if (ret < 0) | ||
| 341 | return ret; | ||
| 342 | |||
| 343 | /* Default memory configuration */ | ||
| 344 | ret = wl1251_hw_init_mem_config(wl); | ||
| 345 | if (ret < 0) | ||
| 346 | return ret; | ||
| 347 | |||
| 348 | /* Default data path configuration */ | ||
| 349 | ret = wl1251_hw_init_data_path_config(wl); | ||
| 350 | if (ret < 0) | ||
| 351 | goto out_free_memmap; | ||
| 352 | |||
| 353 | /* RX config */ | ||
| 354 | ret = wl1251_hw_init_rx_config(wl, | ||
| 355 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
| 356 | RX_FILTER_OPTION_DEF); | ||
| 357 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
| 358 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
| 359 | if (ret < 0) | ||
| 360 | goto out_free_data_path; | ||
| 361 | |||
| 362 | /* TX queues config */ | ||
| 363 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
| 364 | if (ret < 0) | ||
| 365 | goto out_free_data_path; | ||
| 366 | |||
| 367 | /* PHY layer config */ | ||
| 368 | ret = wl1251_hw_init_phy_config(wl); | ||
| 369 | if (ret < 0) | ||
| 370 | goto out_free_data_path; | ||
| 371 | |||
| 372 | /* Initialize connection monitoring thresholds */ | ||
| 373 | ret = wl1251_acx_conn_monit_params(wl); | ||
| 374 | if (ret < 0) | ||
| 375 | goto out_free_data_path; | ||
| 376 | |||
| 377 | /* Beacon filtering */ | ||
| 378 | ret = wl1251_hw_init_beacon_filter(wl); | ||
| 379 | if (ret < 0) | ||
| 380 | goto out_free_data_path; | ||
| 381 | |||
| 382 | /* Bluetooth WLAN coexistence */ | ||
| 383 | ret = wl1251_hw_init_pta(wl); | ||
| 384 | if (ret < 0) | ||
| 385 | goto out_free_data_path; | ||
| 386 | |||
| 387 | /* Energy detection */ | ||
| 388 | ret = wl1251_hw_init_energy_detection(wl); | ||
| 389 | if (ret < 0) | ||
| 390 | goto out_free_data_path; | ||
| 391 | |||
| 392 | /* Beacons and boradcast settings */ | ||
| 393 | ret = wl1251_hw_init_beacon_broadcast(wl); | ||
| 394 | if (ret < 0) | ||
| 395 | goto out_free_data_path; | ||
| 396 | |||
| 397 | /* Enable data path */ | ||
| 398 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
| 399 | if (ret < 0) | ||
| 400 | goto out_free_data_path; | ||
| 401 | |||
| 402 | /* Default power state */ | ||
| 403 | ret = wl1251_hw_init_power_auth(wl); | ||
| 404 | if (ret < 0) | ||
| 405 | goto out_free_data_path; | ||
| 406 | |||
| 407 | wl_mem_map = wl->target_mem_map; | ||
| 408 | wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
| 409 | wl_mem_map->num_tx_mem_blocks, | ||
| 410 | wl->data_path->tx_control_addr, | ||
| 411 | wl_mem_map->num_rx_mem_blocks, | ||
| 412 | wl->data_path->rx_control_addr); | ||
| 413 | |||
| 414 | return 0; | ||
| 415 | |||
| 416 | out_free_data_path: | ||
| 417 | kfree(wl->data_path); | ||
| 418 | |||
| 419 | out_free_memmap: | ||
| 420 | kfree(wl->target_mem_map); | ||
| 421 | |||
| 422 | return ret; | ||
| 423 | } | ||
diff --git a/drivers/net/wireless/wl1251/init.h b/drivers/net/wireless/wl1251/init.h new file mode 100644 index 00000000000..543f17582ea --- /dev/null +++ b/drivers/net/wireless/wl1251/init.h | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Nokia Corporation | ||
| 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 | #ifndef __WL1251_INIT_H__ | ||
| 23 | #define __WL1251_INIT_H__ | ||
| 24 | |||
| 25 | #include "wl1251.h" | ||
| 26 | |||
| 27 | enum { | ||
| 28 | /* best effort/legacy */ | ||
| 29 | AC_BE = 0, | ||
| 30 | |||
| 31 | /* background */ | ||
| 32 | AC_BK = 1, | ||
| 33 | |||
| 34 | /* video */ | ||
| 35 | AC_VI = 2, | ||
| 36 | |||
| 37 | /* voice */ | ||
| 38 | AC_VO = 3, | ||
| 39 | |||
| 40 | /* broadcast dummy access category */ | ||
| 41 | AC_BCAST = 4, | ||
| 42 | |||
| 43 | NUM_ACCESS_CATEGORIES = 4 | ||
| 44 | }; | ||
| 45 | |||
| 46 | /* following are defult values for the IE fields*/ | ||
| 47 | #define CWMIN_BK 15 | ||
| 48 | #define CWMIN_BE 15 | ||
| 49 | #define CWMIN_VI 7 | ||
| 50 | #define CWMIN_VO 3 | ||
| 51 | #define CWMAX_BK 1023 | ||
| 52 | #define CWMAX_BE 63 | ||
| 53 | #define CWMAX_VI 15 | ||
| 54 | #define CWMAX_VO 7 | ||
| 55 | |||
| 56 | /* slot number setting to start transmission at PIFS interval */ | ||
| 57 | #define AIFS_PIFS 1 | ||
| 58 | |||
| 59 | /* | ||
| 60 | * slot number setting to start transmission at DIFS interval - normal DCF | ||
| 61 | * access | ||
| 62 | */ | ||
| 63 | #define AIFS_DIFS 2 | ||
| 64 | |||
| 65 | #define AIFSN_BK 7 | ||
| 66 | #define AIFSN_BE 3 | ||
| 67 | #define AIFSN_VI AIFS_PIFS | ||
| 68 | #define AIFSN_VO AIFS_PIFS | ||
| 69 | #define TXOP_BK 0 | ||
| 70 | #define TXOP_BE 0 | ||
| 71 | #define TXOP_VI 3008 | ||
| 72 | #define TXOP_VO 1504 | ||
| 73 | |||
| 74 | int wl1251_hw_init_hwenc_config(struct wl1251 *wl); | ||
| 75 | int wl1251_hw_init_templates_config(struct wl1251 *wl); | ||
| 76 | int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter); | ||
| 77 | int wl1251_hw_init_phy_config(struct wl1251 *wl); | ||
| 78 | int wl1251_hw_init_beacon_filter(struct wl1251 *wl); | ||
| 79 | int wl1251_hw_init_pta(struct wl1251 *wl); | ||
| 80 | int wl1251_hw_init_energy_detection(struct wl1251 *wl); | ||
| 81 | int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl); | ||
| 82 | int wl1251_hw_init_power_auth(struct wl1251 *wl); | ||
| 83 | int wl1251_hw_init_mem_config(struct wl1251 *wl); | ||
| 84 | int wl1251_hw_init(struct wl1251 *wl); | ||
| 85 | |||
| 86 | #endif | ||
diff --git a/drivers/net/wireless/wl1251/io.c b/drivers/net/wireless/wl1251/io.c new file mode 100644 index 00000000000..cdcadbf6ac2 --- /dev/null +++ b/drivers/net/wireless/wl1251/io.c | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl12xx | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Nokia Corporation | ||
| 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 "wl1251.h" | ||
| 23 | #include "reg.h" | ||
| 24 | #include "io.h" | ||
| 25 | |||
| 26 | /* FIXME: this is static data nowadays and the table can be removed */ | ||
| 27 | static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { | ||
| 28 | [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), | ||
| 29 | [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), | ||
| 30 | [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), | ||
| 31 | [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), | ||
| 32 | [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), | ||
| 33 | [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), | ||
| 34 | [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), | ||
| 35 | [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), | ||
| 36 | [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), | ||
| 37 | [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), | ||
| 38 | [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) | ||
| 39 | }; | ||
| 40 | |||
| 41 | static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) | ||
| 42 | { | ||
| 43 | /* If the address is lower than REGISTERS_BASE, it means that this is | ||
| 44 | * a chip-specific register address, so look it up in the registers | ||
| 45 | * table */ | ||
| 46 | if (addr < REGISTERS_BASE) { | ||
| 47 | /* Make sure we don't go over the table */ | ||
| 48 | if (addr >= ACX_REG_TABLE_LEN) { | ||
| 49 | wl1251_error("address out of range (%d)", addr); | ||
| 50 | return -EINVAL; | ||
| 51 | } | ||
| 52 | addr = wl1251_io_reg_table[addr]; | ||
| 53 | } | ||
| 54 | |||
| 55 | return addr - wl->physical_reg_addr + wl->virtual_reg_addr; | ||
| 56 | } | ||
| 57 | |||
| 58 | static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) | ||
| 59 | { | ||
| 60 | return addr - wl->physical_mem_addr + wl->virtual_mem_addr; | ||
| 61 | } | ||
| 62 | |||
| 63 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
| 64 | { | ||
| 65 | int physical; | ||
| 66 | |||
| 67 | physical = wl1251_translate_mem_addr(wl, addr); | ||
| 68 | |||
| 69 | wl->if_ops->read(wl, physical, buf, len); | ||
| 70 | } | ||
| 71 | |||
| 72 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) | ||
| 73 | { | ||
| 74 | int physical; | ||
| 75 | |||
| 76 | physical = wl1251_translate_mem_addr(wl, addr); | ||
| 77 | |||
| 78 | wl->if_ops->write(wl, physical, buf, len); | ||
| 79 | } | ||
| 80 | |||
| 81 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr) | ||
| 82 | { | ||
| 83 | return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); | ||
| 84 | } | ||
| 85 | |||
| 86 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) | ||
| 87 | { | ||
| 88 | wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); | ||
| 89 | } | ||
| 90 | |||
| 91 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr) | ||
| 92 | { | ||
| 93 | return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); | ||
| 94 | } | ||
| 95 | |||
| 96 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) | ||
| 97 | { | ||
| 98 | wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); | ||
| 99 | } | ||
| 100 | |||
| 101 | /* Set the partitions to access the chip addresses. | ||
| 102 | * | ||
| 103 | * There are two VIRTUAL partitions (the memory partition and the | ||
| 104 | * registers partition), which are mapped to two different areas of the | ||
| 105 | * PHYSICAL (hardware) memory. This function also makes other checks to | ||
| 106 | * ensure that the partitions are not overlapping. In the diagram below, the | ||
| 107 | * memory partition comes before the register partition, but the opposite is | ||
| 108 | * also supported. | ||
| 109 | * | ||
| 110 | * PHYSICAL address | ||
| 111 | * space | ||
| 112 | * | ||
| 113 | * | | | ||
| 114 | * ...+----+--> mem_start | ||
| 115 | * VIRTUAL address ... | | | ||
| 116 | * space ... | | [PART_0] | ||
| 117 | * ... | | | ||
| 118 | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size | ||
| 119 | * | | ... | | | ||
| 120 | * |MEM | ... | | | ||
| 121 | * | | ... | | | ||
| 122 | * part_size <--+----+... | | {unused area) | ||
| 123 | * | | ... | | | ||
| 124 | * |REG | ... | | | ||
| 125 | * part_size | | ... | | | ||
| 126 | * + <--+----+... ...+----+--> reg_start | ||
| 127 | * reg_size ... | | | ||
| 128 | * ... | | [PART_1] | ||
| 129 | * ... | | | ||
| 130 | * ...+----+--> reg_start + reg_size | ||
| 131 | * | | | ||
| 132 | * | ||
| 133 | */ | ||
| 134 | void wl1251_set_partition(struct wl1251 *wl, | ||
| 135 | u32 mem_start, u32 mem_size, | ||
| 136 | u32 reg_start, u32 reg_size) | ||
| 137 | { | ||
| 138 | struct wl1251_partition partition[2]; | ||
| 139 | |||
| 140 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
| 141 | mem_start, mem_size); | ||
| 142 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
| 143 | reg_start, reg_size); | ||
| 144 | |||
| 145 | /* Make sure that the two partitions together don't exceed the | ||
| 146 | * address range */ | ||
| 147 | if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { | ||
| 148 | wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" | ||
| 149 | " address range. Truncating partition[0]."); | ||
| 150 | mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; | ||
| 151 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
| 152 | mem_start, mem_size); | ||
| 153 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
| 154 | reg_start, reg_size); | ||
| 155 | } | ||
| 156 | |||
| 157 | if ((mem_start < reg_start) && | ||
| 158 | ((mem_start + mem_size) > reg_start)) { | ||
| 159 | /* Guarantee that the memory partition doesn't overlap the | ||
| 160 | * registers partition */ | ||
| 161 | wl1251_debug(DEBUG_SPI, "End of partition[0] is " | ||
| 162 | "overlapping partition[1]. Adjusted."); | ||
| 163 | mem_size = reg_start - mem_start; | ||
| 164 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
| 165 | mem_start, mem_size); | ||
| 166 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
| 167 | reg_start, reg_size); | ||
| 168 | } else if ((reg_start < mem_start) && | ||
| 169 | ((reg_start + reg_size) > mem_start)) { | ||
| 170 | /* Guarantee that the register partition doesn't overlap the | ||
| 171 | * memory partition */ | ||
| 172 | wl1251_debug(DEBUG_SPI, "End of partition[1] is" | ||
| 173 | " overlapping partition[0]. Adjusted."); | ||
| 174 | reg_size = mem_start - reg_start; | ||
| 175 | wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", | ||
| 176 | mem_start, mem_size); | ||
| 177 | wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", | ||
| 178 | reg_start, reg_size); | ||
| 179 | } | ||
| 180 | |||
| 181 | partition[0].start = mem_start; | ||
| 182 | partition[0].size = mem_size; | ||
| 183 | partition[1].start = reg_start; | ||
| 184 | partition[1].size = reg_size; | ||
| 185 | |||
| 186 | wl->physical_mem_addr = mem_start; | ||
| 187 | wl->physical_reg_addr = reg_start; | ||
| 188 | |||
| 189 | wl->virtual_mem_addr = 0; | ||
| 190 | wl->virtual_reg_addr = mem_size; | ||
| 191 | |||
| 192 | wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, | ||
| 193 | sizeof(partition)); | ||
| 194 | } | ||
diff --git a/drivers/net/wireless/wl1251/io.h b/drivers/net/wireless/wl1251/io.h new file mode 100644 index 00000000000..c545e9d5f51 --- /dev/null +++ b/drivers/net/wireless/wl1251/io.h | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl12xx | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Nokia Corporation | ||
| 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 | #ifndef __WL1251_IO_H__ | ||
| 22 | #define __WL1251_IO_H__ | ||
| 23 | |||
| 24 | #include "wl1251.h" | ||
| 25 | |||
| 26 | #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 | ||
| 27 | |||
| 28 | #define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 | ||
| 29 | #define HW_ACCESS_PART0_START_ADDR 0x1FFC4 | ||
| 30 | #define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 | ||
| 31 | #define HW_ACCESS_PART1_START_ADDR 0x1FFCC | ||
| 32 | |||
| 33 | #define HW_ACCESS_REGISTER_SIZE 4 | ||
| 34 | |||
| 35 | #define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 | ||
| 36 | |||
| 37 | static inline u32 wl1251_read32(struct wl1251 *wl, int addr) | ||
| 38 | { | ||
| 39 | u32 response; | ||
| 40 | |||
| 41 | wl->if_ops->read(wl, addr, &response, sizeof(u32)); | ||
| 42 | |||
| 43 | return response; | ||
| 44 | } | ||
| 45 | |||
| 46 | static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val) | ||
| 47 | { | ||
| 48 | wl->if_ops->write(wl, addr, &val, sizeof(u32)); | ||
| 49 | } | ||
| 50 | |||
| 51 | static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr) | ||
| 52 | { | ||
| 53 | u32 response; | ||
| 54 | |||
| 55 | if (wl->if_ops->read_elp) | ||
| 56 | wl->if_ops->read_elp(wl, addr, &response); | ||
| 57 | else | ||
| 58 | wl->if_ops->read(wl, addr, &response, sizeof(u32)); | ||
| 59 | |||
| 60 | return response; | ||
| 61 | } | ||
| 62 | |||
| 63 | static inline void wl1251_write_elp(struct wl1251 *wl, int addr, u32 val) | ||
| 64 | { | ||
| 65 | if (wl->if_ops->write_elp) | ||
| 66 | wl->if_ops->write_elp(wl, addr, val); | ||
| 67 | else | ||
| 68 | wl->if_ops->write(wl, addr, &val, sizeof(u32)); | ||
| 69 | } | ||
| 70 | |||
| 71 | /* Memory target IO, address is translated to partition 0 */ | ||
| 72 | void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
| 73 | void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
| 74 | u32 wl1251_mem_read32(struct wl1251 *wl, int addr); | ||
| 75 | void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val); | ||
| 76 | /* Registers IO */ | ||
| 77 | u32 wl1251_reg_read32(struct wl1251 *wl, int addr); | ||
| 78 | void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val); | ||
| 79 | |||
| 80 | void wl1251_set_partition(struct wl1251 *wl, | ||
| 81 | u32 part_start, u32 part_size, | ||
| 82 | u32 reg_start, u32 reg_size); | ||
| 83 | |||
| 84 | #endif | ||
diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c new file mode 100644 index 00000000000..a14a48c99cd --- /dev/null +++ b/drivers/net/wireless/wl1251/main.c | |||
| @@ -0,0 +1,1469 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
| 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 <linux/module.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/firmware.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/irq.h> | ||
| 27 | #include <linux/crc32.h> | ||
| 28 | #include <linux/etherdevice.h> | ||
| 29 | #include <linux/vmalloc.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | |||
| 32 | #include "wl1251.h" | ||
| 33 | #include "wl12xx_80211.h" | ||
| 34 | #include "reg.h" | ||
| 35 | #include "io.h" | ||
| 36 | #include "cmd.h" | ||
| 37 | #include "event.h" | ||
| 38 | #include "tx.h" | ||
| 39 | #include "rx.h" | ||
| 40 | #include "ps.h" | ||
| 41 | #include "init.h" | ||
| 42 | #include "debugfs.h" | ||
| 43 | #include "boot.h" | ||
| 44 | |||
| 45 | void wl1251_enable_interrupts(struct wl1251 *wl) | ||
| 46 | { | ||
| 47 | wl->if_ops->enable_irq(wl); | ||
| 48 | } | ||
| 49 | |||
| 50 | void wl1251_disable_interrupts(struct wl1251 *wl) | ||
| 51 | { | ||
| 52 | wl->if_ops->disable_irq(wl); | ||
| 53 | } | ||
| 54 | |||
| 55 | static int wl1251_power_off(struct wl1251 *wl) | ||
| 56 | { | ||
| 57 | return wl->if_ops->power(wl, false); | ||
| 58 | } | ||
| 59 | |||
| 60 | static int wl1251_power_on(struct wl1251 *wl) | ||
| 61 | { | ||
| 62 | return wl->if_ops->power(wl, true); | ||
| 63 | } | ||
| 64 | |||
| 65 | static int wl1251_fetch_firmware(struct wl1251 *wl) | ||
| 66 | { | ||
| 67 | const struct firmware *fw; | ||
| 68 | struct device *dev = wiphy_dev(wl->hw->wiphy); | ||
| 69 | int ret; | ||
| 70 | |||
| 71 | ret = request_firmware(&fw, WL1251_FW_NAME, dev); | ||
| 72 | |||
| 73 | if (ret < 0) { | ||
| 74 | wl1251_error("could not get firmware: %d", ret); | ||
| 75 | return ret; | ||
| 76 | } | ||
| 77 | |||
| 78 | if (fw->size % 4) { | ||
| 79 | wl1251_error("firmware size is not multiple of 32 bits: %zu", | ||
| 80 | fw->size); | ||
| 81 | ret = -EILSEQ; | ||
| 82 | goto out; | ||
| 83 | } | ||
| 84 | |||
| 85 | wl->fw_len = fw->size; | ||
| 86 | wl->fw = vmalloc(wl->fw_len); | ||
| 87 | |||
| 88 | if (!wl->fw) { | ||
| 89 | wl1251_error("could not allocate memory for the firmware"); | ||
| 90 | ret = -ENOMEM; | ||
| 91 | goto out; | ||
| 92 | } | ||
| 93 | |||
| 94 | memcpy(wl->fw, fw->data, wl->fw_len); | ||
| 95 | |||
| 96 | ret = 0; | ||
| 97 | |||
| 98 | out: | ||
| 99 | release_firmware(fw); | ||
| 100 | |||
| 101 | return ret; | ||
| 102 | } | ||
| 103 | |||
| 104 | static int wl1251_fetch_nvs(struct wl1251 *wl) | ||
| 105 | { | ||
| 106 | const struct firmware *fw; | ||
| 107 | struct device *dev = wiphy_dev(wl->hw->wiphy); | ||
| 108 | int ret; | ||
| 109 | |||
| 110 | ret = request_firmware(&fw, WL1251_NVS_NAME, dev); | ||
| 111 | |||
| 112 | if (ret < 0) { | ||
| 113 | wl1251_error("could not get nvs file: %d", ret); | ||
| 114 | return ret; | ||
| 115 | } | ||
| 116 | |||
| 117 | if (fw->size % 4) { | ||
| 118 | wl1251_error("nvs size is not multiple of 32 bits: %zu", | ||
| 119 | fw->size); | ||
| 120 | ret = -EILSEQ; | ||
| 121 | goto out; | ||
| 122 | } | ||
| 123 | |||
| 124 | wl->nvs_len = fw->size; | ||
| 125 | wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL); | ||
| 126 | |||
| 127 | if (!wl->nvs) { | ||
| 128 | wl1251_error("could not allocate memory for the nvs file"); | ||
| 129 | ret = -ENOMEM; | ||
| 130 | goto out; | ||
| 131 | } | ||
| 132 | |||
| 133 | ret = 0; | ||
| 134 | |||
| 135 | out: | ||
| 136 | release_firmware(fw); | ||
| 137 | |||
| 138 | return ret; | ||
| 139 | } | ||
| 140 | |||
| 141 | static void wl1251_fw_wakeup(struct wl1251 *wl) | ||
| 142 | { | ||
| 143 | u32 elp_reg; | ||
| 144 | |||
| 145 | elp_reg = ELPCTRL_WAKE_UP; | ||
| 146 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
| 147 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
| 148 | |||
| 149 | if (!(elp_reg & ELPCTRL_WLAN_READY)) | ||
| 150 | wl1251_warning("WLAN not ready"); | ||
| 151 | } | ||
| 152 | |||
| 153 | static int wl1251_chip_wakeup(struct wl1251 *wl) | ||
| 154 | { | ||
| 155 | int ret; | ||
| 156 | |||
| 157 | ret = wl1251_power_on(wl); | ||
| 158 | if (ret < 0) | ||
| 159 | return ret; | ||
| 160 | |||
| 161 | msleep(WL1251_POWER_ON_SLEEP); | ||
| 162 | wl->if_ops->reset(wl); | ||
| 163 | |||
| 164 | /* We don't need a real memory partition here, because we only want | ||
| 165 | * to use the registers at this point. */ | ||
| 166 | wl1251_set_partition(wl, | ||
| 167 | 0x00000000, | ||
| 168 | 0x00000000, | ||
| 169 | REGISTERS_BASE, | ||
| 170 | REGISTERS_DOWN_SIZE); | ||
| 171 | |||
| 172 | /* ELP module wake up */ | ||
| 173 | wl1251_fw_wakeup(wl); | ||
| 174 | |||
| 175 | /* whal_FwCtrl_BootSm() */ | ||
| 176 | |||
| 177 | /* 0. read chip id from CHIP_ID */ | ||
| 178 | wl->chip_id = wl1251_reg_read32(wl, CHIP_ID_B); | ||
| 179 | |||
| 180 | /* 1. check if chip id is valid */ | ||
| 181 | |||
| 182 | switch (wl->chip_id) { | ||
| 183 | case CHIP_ID_1251_PG12: | ||
| 184 | wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", | ||
| 185 | wl->chip_id); | ||
| 186 | break; | ||
| 187 | case CHIP_ID_1251_PG11: | ||
| 188 | wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)", | ||
| 189 | wl->chip_id); | ||
| 190 | break; | ||
| 191 | case CHIP_ID_1251_PG10: | ||
| 192 | default: | ||
| 193 | wl1251_error("unsupported chip id: 0x%x", wl->chip_id); | ||
| 194 | ret = -ENODEV; | ||
| 195 | goto out; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (wl->fw == NULL) { | ||
| 199 | ret = wl1251_fetch_firmware(wl); | ||
| 200 | if (ret < 0) | ||
| 201 | goto out; | ||
| 202 | } | ||
| 203 | |||
| 204 | if (wl->nvs == NULL && !wl->use_eeprom) { | ||
| 205 | /* No NVS from netlink, try to get it from the filesystem */ | ||
| 206 | ret = wl1251_fetch_nvs(wl); | ||
| 207 | if (ret < 0) | ||
| 208 | goto out; | ||
| 209 | } | ||
| 210 | |||
| 211 | out: | ||
| 212 | return ret; | ||
| 213 | } | ||
| 214 | |||
| 215 | #define WL1251_IRQ_LOOP_COUNT 10 | ||
| 216 | static void wl1251_irq_work(struct work_struct *work) | ||
| 217 | { | ||
| 218 | u32 intr, ctr = WL1251_IRQ_LOOP_COUNT; | ||
| 219 | struct wl1251 *wl = | ||
| 220 | container_of(work, struct wl1251, irq_work); | ||
| 221 | int ret; | ||
| 222 | |||
| 223 | mutex_lock(&wl->mutex); | ||
| 224 | |||
| 225 | wl1251_debug(DEBUG_IRQ, "IRQ work"); | ||
| 226 | |||
| 227 | if (wl->state == WL1251_STATE_OFF) | ||
| 228 | goto out; | ||
| 229 | |||
| 230 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 231 | if (ret < 0) | ||
| 232 | goto out; | ||
| 233 | |||
| 234 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); | ||
| 235 | |||
| 236 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
| 237 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); | ||
| 238 | |||
| 239 | do { | ||
| 240 | if (wl->data_path) { | ||
| 241 | wl->rx_counter = wl1251_mem_read32( | ||
| 242 | wl, wl->data_path->rx_control_addr); | ||
| 243 | |||
| 244 | /* We handle a frmware bug here */ | ||
| 245 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | ||
| 246 | case 0: | ||
| 247 | wl1251_debug(DEBUG_IRQ, | ||
| 248 | "RX: FW and host in sync"); | ||
| 249 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | ||
| 250 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
| 251 | break; | ||
| 252 | case 1: | ||
| 253 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); | ||
| 254 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
| 255 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
| 256 | break; | ||
| 257 | case 2: | ||
| 258 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); | ||
| 259 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
| 260 | intr |= WL1251_ACX_INTR_RX1_DATA; | ||
| 261 | break; | ||
| 262 | default: | ||
| 263 | wl1251_warning( | ||
| 264 | "RX: FW and host out of sync: %d", | ||
| 265 | wl->rx_counter - wl->rx_handled); | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | |||
| 269 | wl->rx_handled = wl->rx_counter; | ||
| 270 | |||
| 271 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", | ||
| 272 | wl->rx_counter); | ||
| 273 | } | ||
| 274 | |||
| 275 | intr &= wl->intr_mask; | ||
| 276 | |||
| 277 | if (intr == 0) { | ||
| 278 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); | ||
| 279 | goto out_sleep; | ||
| 280 | } | ||
| 281 | |||
| 282 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | ||
| 283 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | ||
| 284 | wl1251_rx(wl); | ||
| 285 | } | ||
| 286 | |||
| 287 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | ||
| 288 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | ||
| 289 | wl1251_rx(wl); | ||
| 290 | } | ||
| 291 | |||
| 292 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | ||
| 293 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | ||
| 294 | wl1251_tx_complete(wl); | ||
| 295 | } | ||
| 296 | |||
| 297 | if (intr & WL1251_ACX_INTR_EVENT_A) { | ||
| 298 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_A"); | ||
| 299 | wl1251_event_handle(wl, 0); | ||
| 300 | } | ||
| 301 | |||
| 302 | if (intr & WL1251_ACX_INTR_EVENT_B) { | ||
| 303 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_B"); | ||
| 304 | wl1251_event_handle(wl, 1); | ||
| 305 | } | ||
| 306 | |||
| 307 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | ||
| 308 | wl1251_debug(DEBUG_IRQ, | ||
| 309 | "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
| 310 | |||
| 311 | if (--ctr == 0) | ||
| 312 | break; | ||
| 313 | |||
| 314 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
| 315 | } while (intr); | ||
| 316 | |||
| 317 | out_sleep: | ||
| 318 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
| 319 | wl1251_ps_elp_sleep(wl); | ||
| 320 | |||
| 321 | out: | ||
| 322 | mutex_unlock(&wl->mutex); | ||
| 323 | } | ||
| 324 | |||
| 325 | static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, | ||
| 326 | u16 beacon_interval, u8 dtim_period) | ||
| 327 | { | ||
| 328 | int ret; | ||
| 329 | |||
| 330 | ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE, | ||
| 331 | DEFAULT_HW_GEN_MODULATION_TYPE, | ||
| 332 | wl->tx_mgmt_frm_rate, | ||
| 333 | wl->tx_mgmt_frm_mod); | ||
| 334 | if (ret < 0) | ||
| 335 | goto out; | ||
| 336 | |||
| 337 | |||
| 338 | ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, | ||
| 339 | dtim_period); | ||
| 340 | if (ret < 0) | ||
| 341 | goto out; | ||
| 342 | |||
| 343 | ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100); | ||
| 344 | if (ret < 0) | ||
| 345 | wl1251_warning("join timeout"); | ||
| 346 | |||
| 347 | out: | ||
| 348 | return ret; | ||
| 349 | } | ||
| 350 | |||
| 351 | static void wl1251_filter_work(struct work_struct *work) | ||
| 352 | { | ||
| 353 | struct wl1251 *wl = | ||
| 354 | container_of(work, struct wl1251, filter_work); | ||
| 355 | int ret; | ||
| 356 | |||
| 357 | mutex_lock(&wl->mutex); | ||
| 358 | |||
| 359 | if (wl->state == WL1251_STATE_OFF) | ||
| 360 | goto out; | ||
| 361 | |||
| 362 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 363 | if (ret < 0) | ||
| 364 | goto out; | ||
| 365 | |||
| 366 | ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, | ||
| 367 | wl->dtim_period); | ||
| 368 | if (ret < 0) | ||
| 369 | goto out_sleep; | ||
| 370 | |||
| 371 | out_sleep: | ||
| 372 | wl1251_ps_elp_sleep(wl); | ||
| 373 | |||
| 374 | out: | ||
| 375 | mutex_unlock(&wl->mutex); | ||
| 376 | } | ||
| 377 | |||
| 378 | static void wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
| 379 | { | ||
| 380 | struct wl1251 *wl = hw->priv; | ||
| 381 | unsigned long flags; | ||
| 382 | |||
| 383 | skb_queue_tail(&wl->tx_queue, skb); | ||
| 384 | |||
| 385 | /* | ||
| 386 | * The chip specific setup must run before the first TX packet - | ||
| 387 | * before that, the tx_work will not be initialized! | ||
| 388 | */ | ||
| 389 | |||
| 390 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
| 391 | |||
| 392 | /* | ||
| 393 | * The workqueue is slow to process the tx_queue and we need stop | ||
| 394 | * the queue here, otherwise the queue will get too long. | ||
| 395 | */ | ||
| 396 | if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_HIGH_WATERMARK) { | ||
| 397 | wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues"); | ||
| 398 | |||
| 399 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
| 400 | ieee80211_stop_queues(wl->hw); | ||
| 401 | wl->tx_queue_stopped = true; | ||
| 402 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | static int wl1251_op_start(struct ieee80211_hw *hw) | ||
| 407 | { | ||
| 408 | struct wl1251 *wl = hw->priv; | ||
| 409 | struct wiphy *wiphy = hw->wiphy; | ||
| 410 | int ret = 0; | ||
| 411 | |||
| 412 | wl1251_debug(DEBUG_MAC80211, "mac80211 start"); | ||
| 413 | |||
| 414 | mutex_lock(&wl->mutex); | ||
| 415 | |||
| 416 | if (wl->state != WL1251_STATE_OFF) { | ||
| 417 | wl1251_error("cannot start because not in off state: %d", | ||
| 418 | wl->state); | ||
| 419 | ret = -EBUSY; | ||
| 420 | goto out; | ||
| 421 | } | ||
| 422 | |||
| 423 | ret = wl1251_chip_wakeup(wl); | ||
| 424 | if (ret < 0) | ||
| 425 | goto out; | ||
| 426 | |||
| 427 | ret = wl1251_boot(wl); | ||
| 428 | if (ret < 0) | ||
| 429 | goto out; | ||
| 430 | |||
| 431 | ret = wl1251_hw_init(wl); | ||
| 432 | if (ret < 0) | ||
| 433 | goto out; | ||
| 434 | |||
| 435 | ret = wl1251_acx_station_id(wl); | ||
| 436 | if (ret < 0) | ||
| 437 | goto out; | ||
| 438 | |||
| 439 | wl->state = WL1251_STATE_ON; | ||
| 440 | |||
| 441 | wl1251_info("firmware booted (%s)", wl->fw_ver); | ||
| 442 | |||
| 443 | /* update hw/fw version info in wiphy struct */ | ||
| 444 | wiphy->hw_version = wl->chip_id; | ||
| 445 | strncpy(wiphy->fw_version, wl->fw_ver, sizeof(wiphy->fw_version)); | ||
| 446 | |||
| 447 | out: | ||
| 448 | if (ret < 0) | ||
| 449 | wl1251_power_off(wl); | ||
| 450 | |||
| 451 | mutex_unlock(&wl->mutex); | ||
| 452 | |||
| 453 | return ret; | ||
| 454 | } | ||
| 455 | |||
| 456 | static void wl1251_op_stop(struct ieee80211_hw *hw) | ||
| 457 | { | ||
| 458 | struct wl1251 *wl = hw->priv; | ||
| 459 | |||
| 460 | wl1251_info("down"); | ||
| 461 | |||
| 462 | wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
| 463 | |||
| 464 | mutex_lock(&wl->mutex); | ||
| 465 | |||
| 466 | WARN_ON(wl->state != WL1251_STATE_ON); | ||
| 467 | |||
| 468 | if (wl->scanning) { | ||
| 469 | ieee80211_scan_completed(wl->hw, true); | ||
| 470 | wl->scanning = false; | ||
| 471 | } | ||
| 472 | |||
| 473 | wl->state = WL1251_STATE_OFF; | ||
| 474 | |||
| 475 | wl1251_disable_interrupts(wl); | ||
| 476 | |||
| 477 | mutex_unlock(&wl->mutex); | ||
| 478 | |||
| 479 | cancel_work_sync(&wl->irq_work); | ||
| 480 | cancel_work_sync(&wl->tx_work); | ||
| 481 | cancel_work_sync(&wl->filter_work); | ||
| 482 | |||
| 483 | mutex_lock(&wl->mutex); | ||
| 484 | |||
| 485 | /* let's notify MAC80211 about the remaining pending TX frames */ | ||
| 486 | wl1251_tx_flush(wl); | ||
| 487 | wl1251_power_off(wl); | ||
| 488 | |||
| 489 | memset(wl->bssid, 0, ETH_ALEN); | ||
| 490 | wl->listen_int = 1; | ||
| 491 | wl->bss_type = MAX_BSS_TYPE; | ||
| 492 | |||
| 493 | wl->data_in_count = 0; | ||
| 494 | wl->rx_counter = 0; | ||
| 495 | wl->rx_handled = 0; | ||
| 496 | wl->rx_current_buffer = 0; | ||
| 497 | wl->rx_last_id = 0; | ||
| 498 | wl->next_tx_complete = 0; | ||
| 499 | wl->elp = false; | ||
| 500 | wl->station_mode = STATION_ACTIVE_MODE; | ||
| 501 | wl->tx_queue_stopped = false; | ||
| 502 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | ||
| 503 | wl->rssi_thold = 0; | ||
| 504 | wl->channel = WL1251_DEFAULT_CHANNEL; | ||
| 505 | |||
| 506 | wl1251_debugfs_reset(wl); | ||
| 507 | |||
| 508 | mutex_unlock(&wl->mutex); | ||
| 509 | } | ||
| 510 | |||
| 511 | static int wl1251_op_add_interface(struct ieee80211_hw *hw, | ||
| 512 | struct ieee80211_vif *vif) | ||
| 513 | { | ||
| 514 | struct wl1251 *wl = hw->priv; | ||
| 515 | int ret = 0; | ||
| 516 | |||
| 517 | wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | ||
| 518 | vif->type, vif->addr); | ||
| 519 | |||
| 520 | mutex_lock(&wl->mutex); | ||
| 521 | if (wl->vif) { | ||
| 522 | ret = -EBUSY; | ||
| 523 | goto out; | ||
| 524 | } | ||
| 525 | |||
| 526 | wl->vif = vif; | ||
| 527 | |||
| 528 | switch (vif->type) { | ||
| 529 | case NL80211_IFTYPE_STATION: | ||
| 530 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
| 531 | break; | ||
| 532 | case NL80211_IFTYPE_ADHOC: | ||
| 533 | wl->bss_type = BSS_TYPE_IBSS; | ||
| 534 | break; | ||
| 535 | default: | ||
| 536 | ret = -EOPNOTSUPP; | ||
| 537 | goto out; | ||
| 538 | } | ||
| 539 | |||
| 540 | if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { | ||
| 541 | memcpy(wl->mac_addr, vif->addr, ETH_ALEN); | ||
| 542 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
| 543 | ret = wl1251_acx_station_id(wl); | ||
| 544 | if (ret < 0) | ||
| 545 | goto out; | ||
| 546 | } | ||
| 547 | |||
| 548 | out: | ||
| 549 | mutex_unlock(&wl->mutex); | ||
| 550 | return ret; | ||
| 551 | } | ||
| 552 | |||
| 553 | static void wl1251_op_remove_interface(struct ieee80211_hw *hw, | ||
| 554 | struct ieee80211_vif *vif) | ||
| 555 | { | ||
| 556 | struct wl1251 *wl = hw->priv; | ||
| 557 | |||
| 558 | mutex_lock(&wl->mutex); | ||
| 559 | wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
| 560 | wl->vif = NULL; | ||
| 561 | mutex_unlock(&wl->mutex); | ||
| 562 | } | ||
| 563 | |||
| 564 | static int wl1251_build_qos_null_data(struct wl1251 *wl) | ||
| 565 | { | ||
| 566 | struct ieee80211_qos_hdr template; | ||
| 567 | |||
| 568 | memset(&template, 0, sizeof(template)); | ||
| 569 | |||
| 570 | memcpy(template.addr1, wl->bssid, ETH_ALEN); | ||
| 571 | memcpy(template.addr2, wl->mac_addr, ETH_ALEN); | ||
| 572 | memcpy(template.addr3, wl->bssid, ETH_ALEN); | ||
| 573 | |||
| 574 | template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
| 575 | IEEE80211_STYPE_QOS_NULLFUNC | | ||
| 576 | IEEE80211_FCTL_TODS); | ||
| 577 | |||
| 578 | /* FIXME: not sure what priority to use here */ | ||
| 579 | template.qos_ctrl = cpu_to_le16(0); | ||
| 580 | |||
| 581 | return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, | ||
| 582 | sizeof(template)); | ||
| 583 | } | ||
| 584 | |||
| 585 | static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | ||
| 586 | { | ||
| 587 | struct wl1251 *wl = hw->priv; | ||
| 588 | struct ieee80211_conf *conf = &hw->conf; | ||
| 589 | int channel, ret = 0; | ||
| 590 | |||
| 591 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
| 592 | |||
| 593 | wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", | ||
| 594 | channel, | ||
| 595 | conf->flags & IEEE80211_CONF_PS ? "on" : "off", | ||
| 596 | conf->power_level); | ||
| 597 | |||
| 598 | mutex_lock(&wl->mutex); | ||
| 599 | |||
| 600 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 601 | if (ret < 0) | ||
| 602 | goto out; | ||
| 603 | |||
| 604 | if (channel != wl->channel) { | ||
| 605 | wl->channel = channel; | ||
| 606 | |||
| 607 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
| 608 | wl->beacon_int, wl->dtim_period); | ||
| 609 | if (ret < 0) | ||
| 610 | goto out_sleep; | ||
| 611 | } | ||
| 612 | |||
| 613 | if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { | ||
| 614 | wl1251_debug(DEBUG_PSM, "psm enabled"); | ||
| 615 | |||
| 616 | wl->psm_requested = true; | ||
| 617 | |||
| 618 | wl->dtim_period = conf->ps_dtim_period; | ||
| 619 | |||
| 620 | ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, | ||
| 621 | wl->dtim_period); | ||
| 622 | |||
| 623 | /* | ||
| 624 | * mac80211 enables PSM only if we're already associated. | ||
| 625 | */ | ||
| 626 | ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||
| 627 | if (ret < 0) | ||
| 628 | goto out_sleep; | ||
| 629 | } else if (!(conf->flags & IEEE80211_CONF_PS) && | ||
| 630 | wl->psm_requested) { | ||
| 631 | wl1251_debug(DEBUG_PSM, "psm disabled"); | ||
| 632 | |||
| 633 | wl->psm_requested = false; | ||
| 634 | |||
| 635 | if (wl->station_mode != STATION_ACTIVE_MODE) { | ||
| 636 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
| 637 | if (ret < 0) | ||
| 638 | goto out_sleep; | ||
| 639 | } | ||
| 640 | } | ||
| 641 | |||
| 642 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | ||
| 643 | if (conf->flags & IEEE80211_CONF_IDLE) { | ||
| 644 | ret = wl1251_ps_set_mode(wl, STATION_IDLE); | ||
| 645 | if (ret < 0) | ||
| 646 | goto out_sleep; | ||
| 647 | } else { | ||
| 648 | ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||
| 649 | if (ret < 0) | ||
| 650 | goto out_sleep; | ||
| 651 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
| 652 | wl->beacon_int, wl->dtim_period); | ||
| 653 | if (ret < 0) | ||
| 654 | goto out_sleep; | ||
| 655 | } | ||
| 656 | } | ||
| 657 | |||
| 658 | if (conf->power_level != wl->power_level) { | ||
| 659 | ret = wl1251_acx_tx_power(wl, conf->power_level); | ||
| 660 | if (ret < 0) | ||
| 661 | goto out_sleep; | ||
| 662 | |||
| 663 | wl->power_level = conf->power_level; | ||
| 664 | } | ||
| 665 | |||
| 666 | out_sleep: | ||
| 667 | wl1251_ps_elp_sleep(wl); | ||
| 668 | |||
| 669 | out: | ||
| 670 | mutex_unlock(&wl->mutex); | ||
| 671 | |||
| 672 | return ret; | ||
| 673 | } | ||
| 674 | |||
| 675 | #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ | ||
| 676 | FIF_ALLMULTI | \ | ||
| 677 | FIF_FCSFAIL | \ | ||
| 678 | FIF_BCN_PRBRESP_PROMISC | \ | ||
| 679 | FIF_CONTROL | \ | ||
| 680 | FIF_OTHER_BSS) | ||
| 681 | |||
| 682 | static void wl1251_op_configure_filter(struct ieee80211_hw *hw, | ||
| 683 | unsigned int changed, | ||
| 684 | unsigned int *total,u64 multicast) | ||
| 685 | { | ||
| 686 | struct wl1251 *wl = hw->priv; | ||
| 687 | |||
| 688 | wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); | ||
| 689 | |||
| 690 | *total &= WL1251_SUPPORTED_FILTERS; | ||
| 691 | changed &= WL1251_SUPPORTED_FILTERS; | ||
| 692 | |||
| 693 | if (changed == 0) | ||
| 694 | /* no filters which we support changed */ | ||
| 695 | return; | ||
| 696 | |||
| 697 | /* FIXME: wl->rx_config and wl->rx_filter are not protected */ | ||
| 698 | |||
| 699 | wl->rx_config = WL1251_DEFAULT_RX_CONFIG; | ||
| 700 | wl->rx_filter = WL1251_DEFAULT_RX_FILTER; | ||
| 701 | |||
| 702 | if (*total & FIF_PROMISC_IN_BSS) { | ||
| 703 | wl->rx_config |= CFG_BSSID_FILTER_EN; | ||
| 704 | wl->rx_config |= CFG_RX_ALL_GOOD; | ||
| 705 | } | ||
| 706 | if (*total & FIF_ALLMULTI) | ||
| 707 | /* | ||
| 708 | * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive | ||
| 709 | * all multicast frames | ||
| 710 | */ | ||
| 711 | wl->rx_config &= ~CFG_MC_FILTER_EN; | ||
| 712 | if (*total & FIF_FCSFAIL) | ||
| 713 | wl->rx_filter |= CFG_RX_FCS_ERROR; | ||
| 714 | if (*total & FIF_BCN_PRBRESP_PROMISC) { | ||
| 715 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; | ||
| 716 | wl->rx_config &= ~CFG_SSID_FILTER_EN; | ||
| 717 | } | ||
| 718 | if (*total & FIF_CONTROL) | ||
| 719 | wl->rx_filter |= CFG_RX_CTL_EN; | ||
| 720 | if (*total & FIF_OTHER_BSS) | ||
| 721 | wl->rx_filter &= ~CFG_BSSID_FILTER_EN; | ||
| 722 | |||
| 723 | /* | ||
| 724 | * FIXME: workqueues need to be properly cancelled on stop(), for | ||
| 725 | * now let's just disable changing the filter settings. They will | ||
| 726 | * be updated any on config(). | ||
| 727 | */ | ||
| 728 | /* schedule_work(&wl->filter_work); */ | ||
| 729 | } | ||
| 730 | |||
| 731 | /* HW encryption */ | ||
| 732 | static int wl1251_set_key_type(struct wl1251 *wl, | ||
| 733 | struct wl1251_cmd_set_keys *key, | ||
| 734 | enum set_key_cmd cmd, | ||
| 735 | struct ieee80211_key_conf *mac80211_key, | ||
| 736 | const u8 *addr) | ||
| 737 | { | ||
| 738 | switch (mac80211_key->cipher) { | ||
| 739 | case WLAN_CIPHER_SUITE_WEP40: | ||
| 740 | case WLAN_CIPHER_SUITE_WEP104: | ||
| 741 | if (is_broadcast_ether_addr(addr)) | ||
| 742 | key->key_type = KEY_WEP_DEFAULT; | ||
| 743 | else | ||
| 744 | key->key_type = KEY_WEP_ADDR; | ||
| 745 | |||
| 746 | mac80211_key->hw_key_idx = mac80211_key->keyidx; | ||
| 747 | break; | ||
| 748 | case WLAN_CIPHER_SUITE_TKIP: | ||
| 749 | if (is_broadcast_ether_addr(addr)) | ||
| 750 | key->key_type = KEY_TKIP_MIC_GROUP; | ||
| 751 | else | ||
| 752 | key->key_type = KEY_TKIP_MIC_PAIRWISE; | ||
| 753 | |||
| 754 | mac80211_key->hw_key_idx = mac80211_key->keyidx; | ||
| 755 | break; | ||
| 756 | case WLAN_CIPHER_SUITE_CCMP: | ||
| 757 | if (is_broadcast_ether_addr(addr)) | ||
| 758 | key->key_type = KEY_AES_GROUP; | ||
| 759 | else | ||
| 760 | key->key_type = KEY_AES_PAIRWISE; | ||
| 761 | mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
| 762 | break; | ||
| 763 | default: | ||
| 764 | wl1251_error("Unknown key cipher 0x%x", mac80211_key->cipher); | ||
| 765 | return -EOPNOTSUPP; | ||
| 766 | } | ||
| 767 | |||
| 768 | return 0; | ||
| 769 | } | ||
| 770 | |||
| 771 | static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
| 772 | struct ieee80211_vif *vif, | ||
| 773 | struct ieee80211_sta *sta, | ||
| 774 | struct ieee80211_key_conf *key) | ||
| 775 | { | ||
| 776 | struct wl1251 *wl = hw->priv; | ||
| 777 | struct wl1251_cmd_set_keys *wl_cmd; | ||
| 778 | const u8 *addr; | ||
| 779 | int ret; | ||
| 780 | |||
| 781 | static const u8 bcast_addr[ETH_ALEN] = | ||
| 782 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
| 783 | |||
| 784 | wl1251_debug(DEBUG_MAC80211, "mac80211 set key"); | ||
| 785 | |||
| 786 | wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL); | ||
| 787 | if (!wl_cmd) { | ||
| 788 | ret = -ENOMEM; | ||
| 789 | goto out; | ||
| 790 | } | ||
| 791 | |||
| 792 | addr = sta ? sta->addr : bcast_addr; | ||
| 793 | |||
| 794 | wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd); | ||
| 795 | wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN); | ||
| 796 | wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", | ||
| 797 | key->cipher, key->keyidx, key->keylen, key->flags); | ||
| 798 | wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen); | ||
| 799 | |||
| 800 | if (is_zero_ether_addr(addr)) { | ||
| 801 | /* We dont support TX only encryption */ | ||
| 802 | ret = -EOPNOTSUPP; | ||
| 803 | goto out; | ||
| 804 | } | ||
| 805 | |||
| 806 | mutex_lock(&wl->mutex); | ||
| 807 | |||
| 808 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 809 | if (ret < 0) | ||
| 810 | goto out_unlock; | ||
| 811 | |||
| 812 | switch (cmd) { | ||
| 813 | case SET_KEY: | ||
| 814 | wl_cmd->key_action = KEY_ADD_OR_REPLACE; | ||
| 815 | break; | ||
| 816 | case DISABLE_KEY: | ||
| 817 | wl_cmd->key_action = KEY_REMOVE; | ||
| 818 | break; | ||
| 819 | default: | ||
| 820 | wl1251_error("Unsupported key cmd 0x%x", cmd); | ||
| 821 | break; | ||
| 822 | } | ||
| 823 | |||
| 824 | ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); | ||
| 825 | if (ret < 0) { | ||
| 826 | wl1251_error("Set KEY type failed"); | ||
| 827 | goto out_sleep; | ||
| 828 | } | ||
| 829 | |||
| 830 | if (wl_cmd->key_type != KEY_WEP_DEFAULT) | ||
| 831 | memcpy(wl_cmd->addr, addr, ETH_ALEN); | ||
| 832 | |||
| 833 | if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) || | ||
| 834 | (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) { | ||
| 835 | /* | ||
| 836 | * We get the key in the following form: | ||
| 837 | * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) | ||
| 838 | * but the target is expecting: | ||
| 839 | * TKIP - RX MIC - TX MIC | ||
| 840 | */ | ||
| 841 | memcpy(wl_cmd->key, key->key, 16); | ||
| 842 | memcpy(wl_cmd->key + 16, key->key + 24, 8); | ||
| 843 | memcpy(wl_cmd->key + 24, key->key + 16, 8); | ||
| 844 | |||
| 845 | } else { | ||
| 846 | memcpy(wl_cmd->key, key->key, key->keylen); | ||
| 847 | } | ||
| 848 | wl_cmd->key_size = key->keylen; | ||
| 849 | |||
| 850 | wl_cmd->id = key->keyidx; | ||
| 851 | wl_cmd->ssid_profile = 0; | ||
| 852 | |||
| 853 | wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd)); | ||
| 854 | |||
| 855 | ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd)); | ||
| 856 | if (ret < 0) { | ||
| 857 | wl1251_warning("could not set keys"); | ||
| 858 | goto out_sleep; | ||
| 859 | } | ||
| 860 | |||
| 861 | out_sleep: | ||
| 862 | wl1251_ps_elp_sleep(wl); | ||
| 863 | |||
| 864 | out_unlock: | ||
| 865 | mutex_unlock(&wl->mutex); | ||
| 866 | |||
| 867 | out: | ||
| 868 | kfree(wl_cmd); | ||
| 869 | |||
| 870 | return ret; | ||
| 871 | } | ||
| 872 | |||
| 873 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | ||
| 874 | struct ieee80211_vif *vif, | ||
| 875 | struct cfg80211_scan_request *req) | ||
| 876 | { | ||
| 877 | struct wl1251 *wl = hw->priv; | ||
| 878 | struct sk_buff *skb; | ||
| 879 | size_t ssid_len = 0; | ||
| 880 | u8 *ssid = NULL; | ||
| 881 | int ret; | ||
| 882 | |||
| 883 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
| 884 | |||
| 885 | if (req->n_ssids) { | ||
| 886 | ssid = req->ssids[0].ssid; | ||
| 887 | ssid_len = req->ssids[0].ssid_len; | ||
| 888 | } | ||
| 889 | |||
| 890 | mutex_lock(&wl->mutex); | ||
| 891 | |||
| 892 | if (wl->scanning) { | ||
| 893 | wl1251_debug(DEBUG_SCAN, "scan already in progress"); | ||
| 894 | ret = -EINVAL; | ||
| 895 | goto out; | ||
| 896 | } | ||
| 897 | |||
| 898 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 899 | if (ret < 0) | ||
| 900 | goto out; | ||
| 901 | |||
| 902 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, | ||
| 903 | req->ie, req->ie_len); | ||
| 904 | if (!skb) { | ||
| 905 | ret = -ENOMEM; | ||
| 906 | goto out; | ||
| 907 | } | ||
| 908 | |||
| 909 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, | ||
| 910 | skb->len); | ||
| 911 | dev_kfree_skb(skb); | ||
| 912 | if (ret < 0) | ||
| 913 | goto out_sleep; | ||
| 914 | |||
| 915 | ret = wl1251_cmd_trigger_scan_to(wl, 0); | ||
| 916 | if (ret < 0) | ||
| 917 | goto out_sleep; | ||
| 918 | |||
| 919 | wl->scanning = true; | ||
| 920 | |||
| 921 | ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, | ||
| 922 | req->n_channels, WL1251_SCAN_NUM_PROBES); | ||
| 923 | if (ret < 0) { | ||
| 924 | wl->scanning = false; | ||
| 925 | goto out_sleep; | ||
| 926 | } | ||
| 927 | |||
| 928 | out_sleep: | ||
| 929 | wl1251_ps_elp_sleep(wl); | ||
| 930 | |||
| 931 | out: | ||
| 932 | mutex_unlock(&wl->mutex); | ||
| 933 | |||
| 934 | return ret; | ||
| 935 | } | ||
| 936 | |||
| 937 | static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
| 938 | { | ||
| 939 | struct wl1251 *wl = hw->priv; | ||
| 940 | int ret; | ||
| 941 | |||
| 942 | mutex_lock(&wl->mutex); | ||
| 943 | |||
| 944 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 945 | if (ret < 0) | ||
| 946 | goto out; | ||
| 947 | |||
| 948 | ret = wl1251_acx_rts_threshold(wl, (u16) value); | ||
| 949 | if (ret < 0) | ||
| 950 | wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret); | ||
| 951 | |||
| 952 | wl1251_ps_elp_sleep(wl); | ||
| 953 | |||
| 954 | out: | ||
| 955 | mutex_unlock(&wl->mutex); | ||
| 956 | |||
| 957 | return ret; | ||
| 958 | } | ||
| 959 | |||
| 960 | static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | ||
| 961 | struct ieee80211_vif *vif, | ||
| 962 | struct ieee80211_bss_conf *bss_conf, | ||
| 963 | u32 changed) | ||
| 964 | { | ||
| 965 | struct wl1251 *wl = hw->priv; | ||
| 966 | struct sk_buff *beacon, *skb; | ||
| 967 | int ret; | ||
| 968 | |||
| 969 | wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | ||
| 970 | |||
| 971 | mutex_lock(&wl->mutex); | ||
| 972 | |||
| 973 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 974 | if (ret < 0) | ||
| 975 | goto out; | ||
| 976 | |||
| 977 | if (changed & BSS_CHANGED_CQM) { | ||
| 978 | ret = wl1251_acx_low_rssi(wl, bss_conf->cqm_rssi_thold, | ||
| 979 | WL1251_DEFAULT_LOW_RSSI_WEIGHT, | ||
| 980 | WL1251_DEFAULT_LOW_RSSI_DEPTH, | ||
| 981 | WL1251_ACX_LOW_RSSI_TYPE_EDGE); | ||
| 982 | if (ret < 0) | ||
| 983 | goto out; | ||
| 984 | wl->rssi_thold = bss_conf->cqm_rssi_thold; | ||
| 985 | } | ||
| 986 | |||
| 987 | if (changed & BSS_CHANGED_BSSID) { | ||
| 988 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | ||
| 989 | |||
| 990 | skb = ieee80211_nullfunc_get(wl->hw, wl->vif); | ||
| 991 | if (!skb) | ||
| 992 | goto out_sleep; | ||
| 993 | |||
| 994 | ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, | ||
| 995 | skb->data, skb->len); | ||
| 996 | dev_kfree_skb(skb); | ||
| 997 | if (ret < 0) | ||
| 998 | goto out_sleep; | ||
| 999 | |||
| 1000 | ret = wl1251_build_qos_null_data(wl); | ||
| 1001 | if (ret < 0) | ||
| 1002 | goto out; | ||
| 1003 | |||
| 1004 | if (wl->bss_type != BSS_TYPE_IBSS) { | ||
| 1005 | ret = wl1251_join(wl, wl->bss_type, wl->channel, | ||
| 1006 | wl->beacon_int, wl->dtim_period); | ||
| 1007 | if (ret < 0) | ||
| 1008 | goto out_sleep; | ||
| 1009 | } | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | if (changed & BSS_CHANGED_ASSOC) { | ||
| 1013 | if (bss_conf->assoc) { | ||
| 1014 | wl->beacon_int = bss_conf->beacon_int; | ||
| 1015 | |||
| 1016 | skb = ieee80211_pspoll_get(wl->hw, wl->vif); | ||
| 1017 | if (!skb) | ||
| 1018 | goto out_sleep; | ||
| 1019 | |||
| 1020 | ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, | ||
| 1021 | skb->data, | ||
| 1022 | skb->len); | ||
| 1023 | dev_kfree_skb(skb); | ||
| 1024 | if (ret < 0) | ||
| 1025 | goto out_sleep; | ||
| 1026 | |||
| 1027 | ret = wl1251_acx_aid(wl, bss_conf->aid); | ||
| 1028 | if (ret < 0) | ||
| 1029 | goto out_sleep; | ||
| 1030 | } else { | ||
| 1031 | /* use defaults when not associated */ | ||
| 1032 | wl->beacon_int = WL1251_DEFAULT_BEACON_INT; | ||
| 1033 | wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; | ||
| 1034 | } | ||
| 1035 | } | ||
| 1036 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
| 1037 | if (bss_conf->use_short_slot) | ||
| 1038 | ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT); | ||
| 1039 | else | ||
| 1040 | ret = wl1251_acx_slot(wl, SLOT_TIME_LONG); | ||
| 1041 | if (ret < 0) { | ||
| 1042 | wl1251_warning("Set slot time failed %d", ret); | ||
| 1043 | goto out_sleep; | ||
| 1044 | } | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
| 1048 | if (bss_conf->use_short_preamble) | ||
| 1049 | wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT); | ||
| 1050 | else | ||
| 1051 | wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG); | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
| 1055 | if (bss_conf->use_cts_prot) | ||
| 1056 | ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE); | ||
| 1057 | else | ||
| 1058 | ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); | ||
| 1059 | if (ret < 0) { | ||
| 1060 | wl1251_warning("Set ctsprotect failed %d", ret); | ||
| 1061 | goto out_sleep; | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | if (changed & BSS_CHANGED_BEACON) { | ||
| 1066 | beacon = ieee80211_beacon_get(hw, vif); | ||
| 1067 | if (!beacon) | ||
| 1068 | goto out_sleep; | ||
| 1069 | |||
| 1070 | ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data, | ||
| 1071 | beacon->len); | ||
| 1072 | |||
| 1073 | if (ret < 0) { | ||
| 1074 | dev_kfree_skb(beacon); | ||
| 1075 | goto out_sleep; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, | ||
| 1079 | beacon->len); | ||
| 1080 | |||
| 1081 | dev_kfree_skb(beacon); | ||
| 1082 | |||
| 1083 | if (ret < 0) | ||
| 1084 | goto out_sleep; | ||
| 1085 | |||
| 1086 | ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, | ||
| 1087 | wl->channel, wl->dtim_period); | ||
| 1088 | |||
| 1089 | if (ret < 0) | ||
| 1090 | goto out_sleep; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | out_sleep: | ||
| 1094 | wl1251_ps_elp_sleep(wl); | ||
| 1095 | |||
| 1096 | out: | ||
| 1097 | mutex_unlock(&wl->mutex); | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | |||
| 1101 | /* can't be const, mac80211 writes to this */ | ||
| 1102 | static struct ieee80211_rate wl1251_rates[] = { | ||
| 1103 | { .bitrate = 10, | ||
| 1104 | .hw_value = 0x1, | ||
| 1105 | .hw_value_short = 0x1, }, | ||
| 1106 | { .bitrate = 20, | ||
| 1107 | .hw_value = 0x2, | ||
| 1108 | .hw_value_short = 0x2, | ||
| 1109 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
| 1110 | { .bitrate = 55, | ||
| 1111 | .hw_value = 0x4, | ||
| 1112 | .hw_value_short = 0x4, | ||
| 1113 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
| 1114 | { .bitrate = 110, | ||
| 1115 | .hw_value = 0x20, | ||
| 1116 | .hw_value_short = 0x20, | ||
| 1117 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | ||
| 1118 | { .bitrate = 60, | ||
| 1119 | .hw_value = 0x8, | ||
| 1120 | .hw_value_short = 0x8, }, | ||
| 1121 | { .bitrate = 90, | ||
| 1122 | .hw_value = 0x10, | ||
| 1123 | .hw_value_short = 0x10, }, | ||
| 1124 | { .bitrate = 120, | ||
| 1125 | .hw_value = 0x40, | ||
| 1126 | .hw_value_short = 0x40, }, | ||
| 1127 | { .bitrate = 180, | ||
| 1128 | .hw_value = 0x80, | ||
| 1129 | .hw_value_short = 0x80, }, | ||
| 1130 | { .bitrate = 240, | ||
| 1131 | .hw_value = 0x200, | ||
| 1132 | .hw_value_short = 0x200, }, | ||
| 1133 | { .bitrate = 360, | ||
| 1134 | .hw_value = 0x400, | ||
| 1135 | .hw_value_short = 0x400, }, | ||
| 1136 | { .bitrate = 480, | ||
| 1137 | .hw_value = 0x800, | ||
| 1138 | .hw_value_short = 0x800, }, | ||
| 1139 | { .bitrate = 540, | ||
| 1140 | .hw_value = 0x1000, | ||
| 1141 | .hw_value_short = 0x1000, }, | ||
| 1142 | }; | ||
| 1143 | |||
| 1144 | /* can't be const, mac80211 writes to this */ | ||
| 1145 | static struct ieee80211_channel wl1251_channels[] = { | ||
| 1146 | { .hw_value = 1, .center_freq = 2412}, | ||
| 1147 | { .hw_value = 2, .center_freq = 2417}, | ||
| 1148 | { .hw_value = 3, .center_freq = 2422}, | ||
| 1149 | { .hw_value = 4, .center_freq = 2427}, | ||
| 1150 | { .hw_value = 5, .center_freq = 2432}, | ||
| 1151 | { .hw_value = 6, .center_freq = 2437}, | ||
| 1152 | { .hw_value = 7, .center_freq = 2442}, | ||
| 1153 | { .hw_value = 8, .center_freq = 2447}, | ||
| 1154 | { .hw_value = 9, .center_freq = 2452}, | ||
| 1155 | { .hw_value = 10, .center_freq = 2457}, | ||
| 1156 | { .hw_value = 11, .center_freq = 2462}, | ||
| 1157 | { .hw_value = 12, .center_freq = 2467}, | ||
| 1158 | { .hw_value = 13, .center_freq = 2472}, | ||
| 1159 | }; | ||
| 1160 | |||
| 1161 | static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
| 1162 | const struct ieee80211_tx_queue_params *params) | ||
| 1163 | { | ||
| 1164 | enum wl1251_acx_ps_scheme ps_scheme; | ||
| 1165 | struct wl1251 *wl = hw->priv; | ||
| 1166 | int ret; | ||
| 1167 | |||
| 1168 | mutex_lock(&wl->mutex); | ||
| 1169 | |||
| 1170 | wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); | ||
| 1171 | |||
| 1172 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 1173 | if (ret < 0) | ||
| 1174 | goto out; | ||
| 1175 | |||
| 1176 | /* mac80211 uses units of 32 usec */ | ||
| 1177 | ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue), | ||
| 1178 | params->cw_min, params->cw_max, | ||
| 1179 | params->aifs, params->txop * 32); | ||
| 1180 | if (ret < 0) | ||
| 1181 | goto out_sleep; | ||
| 1182 | |||
| 1183 | if (params->uapsd) | ||
| 1184 | ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; | ||
| 1185 | else | ||
| 1186 | ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; | ||
| 1187 | |||
| 1188 | ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), | ||
| 1189 | CHANNEL_TYPE_EDCF, | ||
| 1190 | wl1251_tx_get_queue(queue), ps_scheme, | ||
| 1191 | WL1251_ACX_ACK_POLICY_LEGACY); | ||
| 1192 | if (ret < 0) | ||
| 1193 | goto out_sleep; | ||
| 1194 | |||
| 1195 | out_sleep: | ||
| 1196 | wl1251_ps_elp_sleep(wl); | ||
| 1197 | |||
| 1198 | out: | ||
| 1199 | mutex_unlock(&wl->mutex); | ||
| 1200 | |||
| 1201 | return ret; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | static int wl1251_op_get_survey(struct ieee80211_hw *hw, int idx, | ||
| 1205 | struct survey_info *survey) | ||
| 1206 | { | ||
| 1207 | struct wl1251 *wl = hw->priv; | ||
| 1208 | struct ieee80211_conf *conf = &hw->conf; | ||
| 1209 | |||
| 1210 | if (idx != 0) | ||
| 1211 | return -ENOENT; | ||
| 1212 | |||
| 1213 | survey->channel = conf->channel; | ||
| 1214 | survey->filled = SURVEY_INFO_NOISE_DBM; | ||
| 1215 | survey->noise = wl->noise; | ||
| 1216 | |||
| 1217 | return 0; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | /* can't be const, mac80211 writes to this */ | ||
| 1221 | static struct ieee80211_supported_band wl1251_band_2ghz = { | ||
| 1222 | .channels = wl1251_channels, | ||
| 1223 | .n_channels = ARRAY_SIZE(wl1251_channels), | ||
| 1224 | .bitrates = wl1251_rates, | ||
| 1225 | .n_bitrates = ARRAY_SIZE(wl1251_rates), | ||
| 1226 | }; | ||
| 1227 | |||
| 1228 | static const struct ieee80211_ops wl1251_ops = { | ||
| 1229 | .start = wl1251_op_start, | ||
| 1230 | .stop = wl1251_op_stop, | ||
| 1231 | .add_interface = wl1251_op_add_interface, | ||
| 1232 | .remove_interface = wl1251_op_remove_interface, | ||
| 1233 | .config = wl1251_op_config, | ||
| 1234 | .configure_filter = wl1251_op_configure_filter, | ||
| 1235 | .tx = wl1251_op_tx, | ||
| 1236 | .set_key = wl1251_op_set_key, | ||
| 1237 | .hw_scan = wl1251_op_hw_scan, | ||
| 1238 | .bss_info_changed = wl1251_op_bss_info_changed, | ||
| 1239 | .set_rts_threshold = wl1251_op_set_rts_threshold, | ||
| 1240 | .conf_tx = wl1251_op_conf_tx, | ||
| 1241 | .get_survey = wl1251_op_get_survey, | ||
| 1242 | }; | ||
| 1243 | |||
| 1244 | static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data) | ||
| 1245 | { | ||
| 1246 | unsigned long timeout; | ||
| 1247 | |||
| 1248 | wl1251_reg_write32(wl, EE_ADDR, offset); | ||
| 1249 | wl1251_reg_write32(wl, EE_CTL, EE_CTL_READ); | ||
| 1250 | |||
| 1251 | /* EE_CTL_READ clears when data is ready */ | ||
| 1252 | timeout = jiffies + msecs_to_jiffies(100); | ||
| 1253 | while (1) { | ||
| 1254 | if (!(wl1251_reg_read32(wl, EE_CTL) & EE_CTL_READ)) | ||
| 1255 | break; | ||
| 1256 | |||
| 1257 | if (time_after(jiffies, timeout)) | ||
| 1258 | return -ETIMEDOUT; | ||
| 1259 | |||
| 1260 | msleep(1); | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | *data = wl1251_reg_read32(wl, EE_DATA); | ||
| 1264 | return 0; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | static int wl1251_read_eeprom(struct wl1251 *wl, off_t offset, | ||
| 1268 | u8 *data, size_t len) | ||
| 1269 | { | ||
| 1270 | size_t i; | ||
| 1271 | int ret; | ||
| 1272 | |||
| 1273 | wl1251_reg_write32(wl, EE_START, 0); | ||
| 1274 | |||
| 1275 | for (i = 0; i < len; i++) { | ||
| 1276 | ret = wl1251_read_eeprom_byte(wl, offset + i, &data[i]); | ||
| 1277 | if (ret < 0) | ||
| 1278 | return ret; | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | return 0; | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | static int wl1251_read_eeprom_mac(struct wl1251 *wl) | ||
| 1285 | { | ||
| 1286 | u8 mac[ETH_ALEN]; | ||
| 1287 | int i, ret; | ||
| 1288 | |||
| 1289 | wl1251_set_partition(wl, 0, 0, REGISTERS_BASE, REGISTERS_DOWN_SIZE); | ||
| 1290 | |||
| 1291 | ret = wl1251_read_eeprom(wl, 0x1c, mac, sizeof(mac)); | ||
| 1292 | if (ret < 0) { | ||
| 1293 | wl1251_warning("failed to read MAC address from EEPROM"); | ||
| 1294 | return ret; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | /* MAC is stored in reverse order */ | ||
| 1298 | for (i = 0; i < ETH_ALEN; i++) | ||
| 1299 | wl->mac_addr[i] = mac[ETH_ALEN - i - 1]; | ||
| 1300 | |||
| 1301 | return 0; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | static int wl1251_register_hw(struct wl1251 *wl) | ||
| 1305 | { | ||
| 1306 | int ret; | ||
| 1307 | |||
| 1308 | if (wl->mac80211_registered) | ||
| 1309 | return 0; | ||
| 1310 | |||
| 1311 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
| 1312 | |||
| 1313 | ret = ieee80211_register_hw(wl->hw); | ||
| 1314 | if (ret < 0) { | ||
| 1315 | wl1251_error("unable to register mac80211 hw: %d", ret); | ||
| 1316 | return ret; | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | wl->mac80211_registered = true; | ||
| 1320 | |||
| 1321 | wl1251_notice("loaded"); | ||
| 1322 | |||
| 1323 | return 0; | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | int wl1251_init_ieee80211(struct wl1251 *wl) | ||
| 1327 | { | ||
| 1328 | int ret; | ||
| 1329 | |||
| 1330 | /* The tx descriptor buffer and the TKIP space */ | ||
| 1331 | wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc) | ||
| 1332 | + WL1251_TKIP_IV_SPACE; | ||
| 1333 | |||
| 1334 | /* unit us */ | ||
| 1335 | /* FIXME: find a proper value */ | ||
| 1336 | wl->hw->channel_change_time = 10000; | ||
| 1337 | |||
| 1338 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
| 1339 | IEEE80211_HW_SUPPORTS_PS | | ||
| 1340 | IEEE80211_HW_BEACON_FILTER | | ||
| 1341 | IEEE80211_HW_SUPPORTS_UAPSD | | ||
| 1342 | IEEE80211_HW_SUPPORTS_CQM_RSSI; | ||
| 1343 | |||
| 1344 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
| 1345 | BIT(NL80211_IFTYPE_ADHOC); | ||
| 1346 | wl->hw->wiphy->max_scan_ssids = 1; | ||
| 1347 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz; | ||
| 1348 | |||
| 1349 | wl->hw->queues = 4; | ||
| 1350 | |||
| 1351 | if (wl->use_eeprom) | ||
| 1352 | wl1251_read_eeprom_mac(wl); | ||
| 1353 | |||
| 1354 | ret = wl1251_register_hw(wl); | ||
| 1355 | if (ret) | ||
| 1356 | goto out; | ||
| 1357 | |||
| 1358 | wl1251_debugfs_init(wl); | ||
| 1359 | wl1251_notice("initialized"); | ||
| 1360 | |||
| 1361 | ret = 0; | ||
| 1362 | |||
| 1363 | out: | ||
| 1364 | return ret; | ||
| 1365 | } | ||
| 1366 | EXPORT_SYMBOL_GPL(wl1251_init_ieee80211); | ||
| 1367 | |||
| 1368 | struct ieee80211_hw *wl1251_alloc_hw(void) | ||
| 1369 | { | ||
| 1370 | struct ieee80211_hw *hw; | ||
| 1371 | struct wl1251 *wl; | ||
| 1372 | int i; | ||
| 1373 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
| 1374 | |||
| 1375 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops); | ||
| 1376 | if (!hw) { | ||
| 1377 | wl1251_error("could not alloc ieee80211_hw"); | ||
| 1378 | return ERR_PTR(-ENOMEM); | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | wl = hw->priv; | ||
| 1382 | memset(wl, 0, sizeof(*wl)); | ||
| 1383 | |||
| 1384 | wl->hw = hw; | ||
| 1385 | |||
| 1386 | wl->data_in_count = 0; | ||
| 1387 | |||
| 1388 | skb_queue_head_init(&wl->tx_queue); | ||
| 1389 | |||
| 1390 | INIT_WORK(&wl->filter_work, wl1251_filter_work); | ||
| 1391 | INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); | ||
| 1392 | wl->channel = WL1251_DEFAULT_CHANNEL; | ||
| 1393 | wl->scanning = false; | ||
| 1394 | wl->default_key = 0; | ||
| 1395 | wl->listen_int = 1; | ||
| 1396 | wl->rx_counter = 0; | ||
| 1397 | wl->rx_handled = 0; | ||
| 1398 | wl->rx_current_buffer = 0; | ||
| 1399 | wl->rx_last_id = 0; | ||
| 1400 | wl->rx_config = WL1251_DEFAULT_RX_CONFIG; | ||
| 1401 | wl->rx_filter = WL1251_DEFAULT_RX_FILTER; | ||
| 1402 | wl->elp = false; | ||
| 1403 | wl->station_mode = STATION_ACTIVE_MODE; | ||
| 1404 | wl->psm_requested = false; | ||
| 1405 | wl->tx_queue_stopped = false; | ||
| 1406 | wl->power_level = WL1251_DEFAULT_POWER_LEVEL; | ||
| 1407 | wl->rssi_thold = 0; | ||
| 1408 | wl->beacon_int = WL1251_DEFAULT_BEACON_INT; | ||
| 1409 | wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; | ||
| 1410 | wl->vif = NULL; | ||
| 1411 | |||
| 1412 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
| 1413 | wl->tx_frames[i] = NULL; | ||
| 1414 | |||
| 1415 | wl->next_tx_complete = 0; | ||
| 1416 | |||
| 1417 | INIT_WORK(&wl->irq_work, wl1251_irq_work); | ||
| 1418 | INIT_WORK(&wl->tx_work, wl1251_tx_work); | ||
| 1419 | |||
| 1420 | /* | ||
| 1421 | * In case our MAC address is not correctly set, | ||
| 1422 | * we use a random but Nokia MAC. | ||
| 1423 | */ | ||
| 1424 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
| 1425 | get_random_bytes(wl->mac_addr + 3, 3); | ||
| 1426 | |||
| 1427 | wl->state = WL1251_STATE_OFF; | ||
| 1428 | mutex_init(&wl->mutex); | ||
| 1429 | |||
| 1430 | wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE; | ||
| 1431 | wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE; | ||
| 1432 | |||
| 1433 | wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); | ||
| 1434 | if (!wl->rx_descriptor) { | ||
| 1435 | wl1251_error("could not allocate memory for rx descriptor"); | ||
| 1436 | ieee80211_free_hw(hw); | ||
| 1437 | return ERR_PTR(-ENOMEM); | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | return hw; | ||
| 1441 | } | ||
| 1442 | EXPORT_SYMBOL_GPL(wl1251_alloc_hw); | ||
| 1443 | |||
| 1444 | int wl1251_free_hw(struct wl1251 *wl) | ||
| 1445 | { | ||
| 1446 | ieee80211_unregister_hw(wl->hw); | ||
| 1447 | |||
| 1448 | wl1251_debugfs_exit(wl); | ||
| 1449 | |||
| 1450 | kfree(wl->target_mem_map); | ||
| 1451 | kfree(wl->data_path); | ||
| 1452 | vfree(wl->fw); | ||
| 1453 | wl->fw = NULL; | ||
| 1454 | kfree(wl->nvs); | ||
| 1455 | wl->nvs = NULL; | ||
| 1456 | |||
| 1457 | kfree(wl->rx_descriptor); | ||
| 1458 | wl->rx_descriptor = NULL; | ||
| 1459 | |||
| 1460 | ieee80211_free_hw(wl->hw); | ||
| 1461 | |||
| 1462 | return 0; | ||
| 1463 | } | ||
| 1464 | EXPORT_SYMBOL_GPL(wl1251_free_hw); | ||
| 1465 | |||
| 1466 | MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); | ||
| 1467 | MODULE_LICENSE("GPL"); | ||
| 1468 | MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); | ||
| 1469 | MODULE_FIRMWARE(WL1251_FW_NAME); | ||
diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c new file mode 100644 index 00000000000..db719f7d269 --- /dev/null +++ b/drivers/net/wireless/wl1251/ps.c | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Nokia Corporation | ||
| 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 "reg.h" | ||
| 23 | #include "ps.h" | ||
| 24 | #include "cmd.h" | ||
| 25 | #include "io.h" | ||
| 26 | |||
| 27 | /* in ms */ | ||
| 28 | #define WL1251_WAKEUP_TIMEOUT 100 | ||
| 29 | |||
| 30 | void wl1251_elp_work(struct work_struct *work) | ||
| 31 | { | ||
| 32 | struct delayed_work *dwork; | ||
| 33 | struct wl1251 *wl; | ||
| 34 | |||
| 35 | dwork = container_of(work, struct delayed_work, work); | ||
| 36 | wl = container_of(dwork, struct wl1251, elp_work); | ||
| 37 | |||
| 38 | wl1251_debug(DEBUG_PSM, "elp work"); | ||
| 39 | |||
| 40 | mutex_lock(&wl->mutex); | ||
| 41 | |||
| 42 | if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE) | ||
| 43 | goto out; | ||
| 44 | |||
| 45 | wl1251_debug(DEBUG_PSM, "chip to elp"); | ||
| 46 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||
| 47 | wl->elp = true; | ||
| 48 | |||
| 49 | out: | ||
| 50 | mutex_unlock(&wl->mutex); | ||
| 51 | } | ||
| 52 | |||
| 53 | #define ELP_ENTRY_DELAY 5 | ||
| 54 | |||
| 55 | /* Routines to toggle sleep mode while in ELP */ | ||
| 56 | void wl1251_ps_elp_sleep(struct wl1251 *wl) | ||
| 57 | { | ||
| 58 | unsigned long delay; | ||
| 59 | |||
| 60 | if (wl->station_mode != STATION_ACTIVE_MODE) { | ||
| 61 | delay = msecs_to_jiffies(ELP_ENTRY_DELAY); | ||
| 62 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | int wl1251_ps_elp_wakeup(struct wl1251 *wl) | ||
| 67 | { | ||
| 68 | unsigned long timeout, start; | ||
| 69 | u32 elp_reg; | ||
| 70 | |||
| 71 | if (delayed_work_pending(&wl->elp_work)) | ||
| 72 | cancel_delayed_work(&wl->elp_work); | ||
| 73 | |||
| 74 | if (!wl->elp) | ||
| 75 | return 0; | ||
| 76 | |||
| 77 | wl1251_debug(DEBUG_PSM, "waking up chip from elp"); | ||
| 78 | |||
| 79 | start = jiffies; | ||
| 80 | timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); | ||
| 81 | |||
| 82 | wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); | ||
| 83 | |||
| 84 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
| 85 | |||
| 86 | /* | ||
| 87 | * FIXME: we should wait for irq from chip but, as a temporary | ||
| 88 | * solution to simplify locking, let's poll instead | ||
| 89 | */ | ||
| 90 | while (!(elp_reg & ELPCTRL_WLAN_READY)) { | ||
| 91 | if (time_after(jiffies, timeout)) { | ||
| 92 | wl1251_error("elp wakeup timeout"); | ||
| 93 | return -ETIMEDOUT; | ||
| 94 | } | ||
| 95 | msleep(1); | ||
| 96 | elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); | ||
| 97 | } | ||
| 98 | |||
| 99 | wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", | ||
| 100 | jiffies_to_msecs(jiffies - start)); | ||
| 101 | |||
| 102 | wl->elp = false; | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode) | ||
| 108 | { | ||
| 109 | int ret; | ||
| 110 | |||
| 111 | switch (mode) { | ||
| 112 | case STATION_POWER_SAVE_MODE: | ||
| 113 | wl1251_debug(DEBUG_PSM, "entering psm"); | ||
| 114 | |||
| 115 | /* enable beacon filtering */ | ||
| 116 | ret = wl1251_acx_beacon_filter_opt(wl, true); | ||
| 117 | if (ret < 0) | ||
| 118 | return ret; | ||
| 119 | |||
| 120 | ret = wl1251_acx_wake_up_conditions(wl, | ||
| 121 | WAKE_UP_EVENT_DTIM_BITMAP, | ||
| 122 | wl->listen_int); | ||
| 123 | if (ret < 0) | ||
| 124 | return ret; | ||
| 125 | |||
| 126 | ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_ENABLE, | ||
| 127 | WL1251_DEFAULT_BET_CONSECUTIVE); | ||
| 128 | if (ret < 0) | ||
| 129 | return ret; | ||
| 130 | |||
| 131 | ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE); | ||
| 132 | if (ret < 0) | ||
| 133 | return ret; | ||
| 134 | |||
| 135 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); | ||
| 136 | if (ret < 0) | ||
| 137 | return ret; | ||
| 138 | break; | ||
| 139 | case STATION_IDLE: | ||
| 140 | wl1251_debug(DEBUG_PSM, "entering idle"); | ||
| 141 | |||
| 142 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); | ||
| 143 | if (ret < 0) | ||
| 144 | return ret; | ||
| 145 | |||
| 146 | ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0); | ||
| 147 | if (ret < 0) | ||
| 148 | return ret; | ||
| 149 | break; | ||
| 150 | case STATION_ACTIVE_MODE: | ||
| 151 | default: | ||
| 152 | wl1251_debug(DEBUG_PSM, "leaving psm"); | ||
| 153 | |||
| 154 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | ||
| 155 | if (ret < 0) | ||
| 156 | return ret; | ||
| 157 | |||
| 158 | /* disable BET */ | ||
| 159 | ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_DISABLE, | ||
| 160 | WL1251_DEFAULT_BET_CONSECUTIVE); | ||
| 161 | if (ret < 0) | ||
| 162 | return ret; | ||
| 163 | |||
| 164 | /* disable beacon filtering */ | ||
| 165 | ret = wl1251_acx_beacon_filter_opt(wl, false); | ||
| 166 | if (ret < 0) | ||
| 167 | return ret; | ||
| 168 | |||
| 169 | ret = wl1251_acx_wake_up_conditions(wl, | ||
| 170 | WAKE_UP_EVENT_DTIM_BITMAP, | ||
| 171 | wl->listen_int); | ||
| 172 | if (ret < 0) | ||
| 173 | return ret; | ||
| 174 | |||
| 175 | ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE); | ||
| 176 | if (ret < 0) | ||
| 177 | return ret; | ||
| 178 | |||
| 179 | break; | ||
| 180 | } | ||
| 181 | wl->station_mode = mode; | ||
| 182 | |||
| 183 | return ret; | ||
| 184 | } | ||
| 185 | |||
diff --git a/drivers/net/wireless/wl1251/ps.h b/drivers/net/wireless/wl1251/ps.h new file mode 100644 index 00000000000..75efad246d6 --- /dev/null +++ b/drivers/net/wireless/wl1251/ps.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __WL1251_PS_H__ | ||
| 24 | #define __WL1251_PS_H__ | ||
| 25 | |||
| 26 | #include "wl1251.h" | ||
| 27 | #include "acx.h" | ||
| 28 | |||
| 29 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode); | ||
| 30 | void wl1251_ps_elp_sleep(struct wl1251 *wl); | ||
| 31 | int wl1251_ps_elp_wakeup(struct wl1251 *wl); | ||
| 32 | void wl1251_elp_work(struct work_struct *work); | ||
| 33 | |||
| 34 | |||
| 35 | #endif /* __WL1251_PS_H__ */ | ||
diff --git a/drivers/net/wireless/wl1251/reg.h b/drivers/net/wireless/wl1251/reg.h new file mode 100644 index 00000000000..a5809019c5c --- /dev/null +++ b/drivers/net/wireless/wl1251/reg.h | |||
| @@ -0,0 +1,655 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl12xx | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __REG_H__ | ||
| 24 | #define __REG_H__ | ||
| 25 | |||
| 26 | #include <linux/bitops.h> | ||
| 27 | |||
| 28 | #define REGISTERS_BASE 0x00300000 | ||
| 29 | #define DRPW_BASE 0x00310000 | ||
| 30 | |||
| 31 | #define REGISTERS_DOWN_SIZE 0x00008800 | ||
| 32 | #define REGISTERS_WORK_SIZE 0x0000b000 | ||
| 33 | |||
| 34 | #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC | ||
| 35 | |||
| 36 | /* ELP register commands */ | ||
| 37 | #define ELPCTRL_WAKE_UP 0x1 | ||
| 38 | #define ELPCTRL_WAKE_UP_WLAN_READY 0x5 | ||
| 39 | #define ELPCTRL_SLEEP 0x0 | ||
| 40 | /* ELP WLAN_READY bit */ | ||
| 41 | #define ELPCTRL_WLAN_READY 0x2 | ||
| 42 | |||
| 43 | /* Device Configuration registers*/ | ||
| 44 | #define SOR_CFG (REGISTERS_BASE + 0x0800) | ||
| 45 | #define ECPU_CTRL (REGISTERS_BASE + 0x0804) | ||
| 46 | #define HI_CFG (REGISTERS_BASE + 0x0808) | ||
| 47 | |||
| 48 | /* EEPROM registers */ | ||
| 49 | #define EE_START (REGISTERS_BASE + 0x080C) | ||
| 50 | #define EE_CTL (REGISTERS_BASE + 0x2000) | ||
| 51 | #define EE_DATA (REGISTERS_BASE + 0x2004) | ||
| 52 | #define EE_ADDR (REGISTERS_BASE + 0x2008) | ||
| 53 | |||
| 54 | #define EE_CTL_READ 2 | ||
| 55 | |||
| 56 | #define CHIP_ID_B (REGISTERS_BASE + 0x5674) | ||
| 57 | |||
| 58 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
| 59 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
| 60 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
| 61 | |||
| 62 | #define ENABLE (REGISTERS_BASE + 0x5450) | ||
| 63 | |||
| 64 | /* Power Management registers */ | ||
| 65 | #define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) | ||
| 66 | #define ELP_CMD (REGISTERS_BASE + 0x5808) | ||
| 67 | #define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) | ||
| 68 | #define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) | ||
| 69 | #define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) | ||
| 70 | |||
| 71 | #define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) | ||
| 72 | |||
| 73 | /* Scratch Pad registers*/ | ||
| 74 | #define SCR_PAD0 (REGISTERS_BASE + 0x5608) | ||
| 75 | #define SCR_PAD1 (REGISTERS_BASE + 0x560C) | ||
| 76 | #define SCR_PAD2 (REGISTERS_BASE + 0x5610) | ||
| 77 | #define SCR_PAD3 (REGISTERS_BASE + 0x5614) | ||
| 78 | #define SCR_PAD4 (REGISTERS_BASE + 0x5618) | ||
| 79 | #define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) | ||
| 80 | #define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) | ||
| 81 | #define SCR_PAD5 (REGISTERS_BASE + 0x5624) | ||
| 82 | #define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) | ||
| 83 | #define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) | ||
| 84 | #define SCR_PAD6 (REGISTERS_BASE + 0x5630) | ||
| 85 | #define SCR_PAD7 (REGISTERS_BASE + 0x5634) | ||
| 86 | #define SCR_PAD8 (REGISTERS_BASE + 0x5638) | ||
| 87 | #define SCR_PAD9 (REGISTERS_BASE + 0x563C) | ||
| 88 | |||
| 89 | /* Spare registers*/ | ||
| 90 | #define SPARE_A1 (REGISTERS_BASE + 0x0994) | ||
| 91 | #define SPARE_A2 (REGISTERS_BASE + 0x0998) | ||
| 92 | #define SPARE_A3 (REGISTERS_BASE + 0x099C) | ||
| 93 | #define SPARE_A4 (REGISTERS_BASE + 0x09A0) | ||
| 94 | #define SPARE_A5 (REGISTERS_BASE + 0x09A4) | ||
| 95 | #define SPARE_A6 (REGISTERS_BASE + 0x09A8) | ||
| 96 | #define SPARE_A7 (REGISTERS_BASE + 0x09AC) | ||
| 97 | #define SPARE_A8 (REGISTERS_BASE + 0x09B0) | ||
| 98 | #define SPARE_B1 (REGISTERS_BASE + 0x5420) | ||
| 99 | #define SPARE_B2 (REGISTERS_BASE + 0x5424) | ||
| 100 | #define SPARE_B3 (REGISTERS_BASE + 0x5428) | ||
| 101 | #define SPARE_B4 (REGISTERS_BASE + 0x542C) | ||
| 102 | #define SPARE_B5 (REGISTERS_BASE + 0x5430) | ||
| 103 | #define SPARE_B6 (REGISTERS_BASE + 0x5434) | ||
| 104 | #define SPARE_B7 (REGISTERS_BASE + 0x5438) | ||
| 105 | #define SPARE_B8 (REGISTERS_BASE + 0x543C) | ||
| 106 | |||
| 107 | enum wl12xx_acx_int_reg { | ||
| 108 | ACX_REG_INTERRUPT_TRIG, | ||
| 109 | ACX_REG_INTERRUPT_TRIG_H, | ||
| 110 | |||
| 111 | /*============================================= | ||
| 112 | Host Interrupt Mask Register - 32bit (RW) | ||
| 113 | ------------------------------------------ | ||
| 114 | Setting a bit in this register masks the | ||
| 115 | corresponding interrupt to the host. | ||
| 116 | 0 - RX0 - Rx first dubble buffer Data Interrupt | ||
| 117 | 1 - TXD - Tx Data Interrupt | ||
| 118 | 2 - TXXFR - Tx Transfer Interrupt | ||
| 119 | 3 - RX1 - Rx second dubble buffer Data Interrupt | ||
| 120 | 4 - RXXFR - Rx Transfer Interrupt | ||
| 121 | 5 - EVENT_A - Event Mailbox interrupt | ||
| 122 | 6 - EVENT_B - Event Mailbox interrupt | ||
| 123 | 7 - WNONHST - Wake On Host Interrupt | ||
| 124 | 8 - TRACE_A - Debug Trace interrupt | ||
| 125 | 9 - TRACE_B - Debug Trace interrupt | ||
| 126 | 10 - CDCMP - Command Complete Interrupt | ||
| 127 | 11 - | ||
| 128 | 12 - | ||
| 129 | 13 - | ||
| 130 | 14 - ICOMP - Initialization Complete Interrupt | ||
| 131 | 16 - SG SE - Soft Gemini - Sense enable interrupt | ||
| 132 | 17 - SG SD - Soft Gemini - Sense disable interrupt | ||
| 133 | 18 - - | ||
| 134 | 19 - - | ||
| 135 | 20 - - | ||
| 136 | 21- - | ||
| 137 | Default: 0x0001 | ||
| 138 | *==============================================*/ | ||
| 139 | ACX_REG_INTERRUPT_MASK, | ||
| 140 | |||
| 141 | /*============================================= | ||
| 142 | Host Interrupt Mask Set 16bit, (Write only) | ||
| 143 | ------------------------------------------ | ||
| 144 | Setting a bit in this register sets | ||
| 145 | the corresponding bin in ACX_HINT_MASK register | ||
| 146 | without effecting the mask | ||
| 147 | state of other bits (0 = no effect). | ||
| 148 | ==============================================*/ | ||
| 149 | ACX_REG_HINT_MASK_SET, | ||
| 150 | |||
| 151 | /*============================================= | ||
| 152 | Host Interrupt Mask Clear 16bit,(Write only) | ||
| 153 | ------------------------------------------ | ||
| 154 | Setting a bit in this register clears | ||
| 155 | the corresponding bin in ACX_HINT_MASK register | ||
| 156 | without effecting the mask | ||
| 157 | state of other bits (0 = no effect). | ||
| 158 | =============================================*/ | ||
| 159 | ACX_REG_HINT_MASK_CLR, | ||
| 160 | |||
| 161 | /*============================================= | ||
| 162 | Host Interrupt Status Nondestructive Read | ||
| 163 | 16bit,(Read only) | ||
| 164 | ------------------------------------------ | ||
| 165 | The host can read this register to determine | ||
| 166 | which interrupts are active. | ||
| 167 | Reading this register doesn't | ||
| 168 | effect its content. | ||
| 169 | =============================================*/ | ||
| 170 | ACX_REG_INTERRUPT_NO_CLEAR, | ||
| 171 | |||
| 172 | /*============================================= | ||
| 173 | Host Interrupt Status Clear on Read Register | ||
| 174 | 16bit,(Read only) | ||
| 175 | ------------------------------------------ | ||
| 176 | The host can read this register to determine | ||
| 177 | which interrupts are active. | ||
| 178 | Reading this register clears it, | ||
| 179 | thus making all interrupts inactive. | ||
| 180 | ==============================================*/ | ||
| 181 | ACX_REG_INTERRUPT_CLEAR, | ||
| 182 | |||
| 183 | /*============================================= | ||
| 184 | Host Interrupt Acknowledge Register | ||
| 185 | 16bit,(Write only) | ||
| 186 | ------------------------------------------ | ||
| 187 | The host can set individual bits in this | ||
| 188 | register to clear (acknowledge) the corresp. | ||
| 189 | interrupt status bits in the HINT_STS_CLR and | ||
| 190 | HINT_STS_ND registers, thus making the | ||
| 191 | assotiated interrupt inactive. (0-no effect) | ||
| 192 | ==============================================*/ | ||
| 193 | ACX_REG_INTERRUPT_ACK, | ||
| 194 | |||
| 195 | /*=============================================== | ||
| 196 | Host Software Reset - 32bit RW | ||
| 197 | ------------------------------------------ | ||
| 198 | [31:1] Reserved | ||
| 199 | 0 SOFT_RESET Soft Reset - When this bit is set, | ||
| 200 | it holds the Wlan hardware in a soft reset state. | ||
| 201 | This reset disables all MAC and baseband processor | ||
| 202 | clocks except the CardBus/PCI interface clock. | ||
| 203 | It also initializes all MAC state machines except | ||
| 204 | the host interface. It does not reload the | ||
| 205 | contents of the EEPROM. When this bit is cleared | ||
| 206 | (not self-clearing), the Wlan hardware | ||
| 207 | exits the software reset state. | ||
| 208 | ===============================================*/ | ||
| 209 | ACX_REG_SLV_SOFT_RESET, | ||
| 210 | |||
| 211 | /*=============================================== | ||
| 212 | EEPROM Burst Read Start - 32bit RW | ||
| 213 | ------------------------------------------ | ||
| 214 | [31:1] Reserved | ||
| 215 | 0 ACX_EE_START - EEPROM Burst Read Start 0 | ||
| 216 | Setting this bit starts a burst read from | ||
| 217 | the external EEPROM. | ||
| 218 | If this bit is set (after reset) before an EEPROM read/write, | ||
| 219 | the burst read starts at EEPROM address 0. | ||
| 220 | Otherwise, it starts at the address | ||
| 221 | following the address of the previous access. | ||
| 222 | TheWlan hardware hardware clears this bit automatically. | ||
| 223 | |||
| 224 | Default: 0x00000000 | ||
| 225 | *================================================*/ | ||
| 226 | ACX_REG_EE_START, | ||
| 227 | |||
| 228 | /* Embedded ARM CPU Control */ | ||
| 229 | |||
| 230 | /*=============================================== | ||
| 231 | Halt eCPU - 32bit RW | ||
| 232 | ------------------------------------------ | ||
| 233 | 0 HALT_ECPU Halt Embedded CPU - This bit is the | ||
| 234 | compliment of bit 1 (MDATA2) in the SOR_CFG register. | ||
| 235 | During a hardware reset, this bit holds | ||
| 236 | the inverse of MDATA2. | ||
| 237 | When downloading firmware from the host, | ||
| 238 | set this bit (pull down MDATA2). | ||
| 239 | The host clears this bit after downloading the firmware into | ||
| 240 | zero-wait-state SSRAM. | ||
| 241 | When loading firmware from Flash, clear this bit (pull up MDATA2) | ||
| 242 | so that the eCPU can run the bootloader code in Flash | ||
| 243 | HALT_ECPU eCPU State | ||
| 244 | -------------------- | ||
| 245 | 1 halt eCPU | ||
| 246 | 0 enable eCPU | ||
| 247 | ===============================================*/ | ||
| 248 | ACX_REG_ECPU_CONTROL, | ||
| 249 | |||
| 250 | ACX_REG_TABLE_LEN | ||
| 251 | }; | ||
| 252 | |||
| 253 | #define ACX_SLV_SOFT_RESET_BIT BIT(0) | ||
| 254 | #define ACX_REG_EEPROM_START_BIT BIT(0) | ||
| 255 | |||
| 256 | /* Command/Information Mailbox Pointers */ | ||
| 257 | |||
| 258 | /*=============================================== | ||
| 259 | Command Mailbox Pointer - 32bit RW | ||
| 260 | ------------------------------------------ | ||
| 261 | This register holds the start address of | ||
| 262 | the command mailbox located in the Wlan hardware memory. | ||
| 263 | The host must read this pointer after a reset to | ||
| 264 | find the location of the command mailbox. | ||
| 265 | The Wlan hardware initializes the command mailbox | ||
| 266 | pointer with the default address of the command mailbox. | ||
| 267 | The command mailbox pointer is not valid until after | ||
| 268 | the host receives the Init Complete interrupt from | ||
| 269 | the Wlan hardware. | ||
| 270 | ===============================================*/ | ||
| 271 | #define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) | ||
| 272 | |||
| 273 | /*=============================================== | ||
| 274 | Information Mailbox Pointer - 32bit RW | ||
| 275 | ------------------------------------------ | ||
| 276 | This register holds the start address of | ||
| 277 | the information mailbox located in the Wlan hardware memory. | ||
| 278 | The host must read this pointer after a reset to find | ||
| 279 | the location of the information mailbox. | ||
| 280 | The Wlan hardware initializes the information mailbox pointer | ||
| 281 | with the default address of the information mailbox. | ||
| 282 | The information mailbox pointer is not valid | ||
| 283 | until after the host receives the Init Complete interrupt from | ||
| 284 | the Wlan hardware. | ||
| 285 | ===============================================*/ | ||
| 286 | #define REG_EVENT_MAILBOX_PTR (SCR_PAD1) | ||
| 287 | |||
| 288 | |||
| 289 | /* Misc */ | ||
| 290 | |||
| 291 | #define REG_ENABLE_TX_RX (ENABLE) | ||
| 292 | /* | ||
| 293 | * Rx configuration (filter) information element | ||
| 294 | * --------------------------------------------- | ||
| 295 | */ | ||
| 296 | #define REG_RX_CONFIG (RX_CFG) | ||
| 297 | #define REG_RX_FILTER (RX_FILTER_CFG) | ||
| 298 | |||
| 299 | |||
| 300 | #define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 | ||
| 301 | |||
| 302 | /* promiscuous - receives all valid frames */ | ||
| 303 | #define RX_CFG_PROMISCUOUS 0x0008 | ||
| 304 | |||
| 305 | /* receives frames from any BSSID */ | ||
| 306 | #define RX_CFG_BSSID 0x0020 | ||
| 307 | |||
| 308 | /* receives frames destined to any MAC address */ | ||
| 309 | #define RX_CFG_MAC 0x0010 | ||
| 310 | |||
| 311 | #define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 | ||
| 312 | #define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 | ||
| 313 | #define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 | ||
| 314 | #define RX_CFG_ENABLE_ANY_BSSID 0x0000 | ||
| 315 | |||
| 316 | /* discards all broadcast frames */ | ||
| 317 | #define RX_CFG_DISABLE_BCAST 0x0200 | ||
| 318 | |||
| 319 | #define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 | ||
| 320 | #define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 | ||
| 321 | #define RX_CFG_COPY_RX_STATUS 0x2000 | ||
| 322 | #define RX_CFG_TSF 0x10000 | ||
| 323 | |||
| 324 | #define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
| 325 | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
| 326 | |||
| 327 | #define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
| 328 | | RX_CFG_ENABLE_ANY_BSSID) | ||
| 329 | |||
| 330 | #define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ | ||
| 331 | RX_CFG_ENABLE_ANY_BSSID) | ||
| 332 | |||
| 333 | #define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ | ||
| 334 | | RX_CFG_ENABLE_ONLY_MY_BSSID) | ||
| 335 | |||
| 336 | #define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ | ||
| 337 | | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ | ||
| 338 | | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) | ||
| 339 | |||
| 340 | #define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) | ||
| 341 | |||
| 342 | #define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ | ||
| 343 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
| 344 | |||
| 345 | #define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ | ||
| 346 | RX_CFG_ENABLE_ONLY_MY_DEST_MAC) | ||
| 347 | |||
| 348 | #define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
| 349 | | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ | ||
| 350 | | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) | ||
| 351 | |||
| 352 | #define RX_FILTER_OPTION_FILTER_ALL 0 | ||
| 353 | |||
| 354 | #define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ | ||
| 355 | | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) | ||
| 356 | |||
| 357 | #define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ | ||
| 358 | | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ | ||
| 359 | | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ | ||
| 360 | | CFG_RX_PRSP_EN) | ||
| 361 | |||
| 362 | |||
| 363 | /*=============================================== | ||
| 364 | EEPROM Read/Write Request 32bit RW | ||
| 365 | ------------------------------------------ | ||
| 366 | 1 EE_READ - EEPROM Read Request 1 - Setting this bit | ||
| 367 | loads a single byte of data into the EE_DATA | ||
| 368 | register from the EEPROM location specified in | ||
| 369 | the EE_ADDR register. | ||
| 370 | The Wlan hardware hardware clears this bit automatically. | ||
| 371 | EE_DATA is valid when this bit is cleared. | ||
| 372 | |||
| 373 | 0 EE_WRITE - EEPROM Write Request - Setting this bit | ||
| 374 | writes a single byte of data from the EE_DATA register into the | ||
| 375 | EEPROM location specified in the EE_ADDR register. | ||
| 376 | The Wlan hardware hardware clears this bit automatically. | ||
| 377 | *===============================================*/ | ||
| 378 | #define EE_CTL (REGISTERS_BASE + 0x2000) | ||
| 379 | #define ACX_EE_CTL_REG EE_CTL | ||
| 380 | #define EE_WRITE 0x00000001ul | ||
| 381 | #define EE_READ 0x00000002ul | ||
| 382 | |||
| 383 | /*=============================================== | ||
| 384 | EEPROM Address - 32bit RW | ||
| 385 | ------------------------------------------ | ||
| 386 | This register specifies the address | ||
| 387 | within the EEPROM from/to which to read/write data. | ||
| 388 | ===============================================*/ | ||
| 389 | #define EE_ADDR (REGISTERS_BASE + 0x2008) | ||
| 390 | #define ACX_EE_ADDR_REG EE_ADDR | ||
| 391 | |||
| 392 | /*=============================================== | ||
| 393 | EEPROM Data - 32bit RW | ||
| 394 | ------------------------------------------ | ||
| 395 | This register either holds the read 8 bits of | ||
| 396 | data from the EEPROM or the write data | ||
| 397 | to be written to the EEPROM. | ||
| 398 | ===============================================*/ | ||
| 399 | #define EE_DATA (REGISTERS_BASE + 0x2004) | ||
| 400 | #define ACX_EE_DATA_REG EE_DATA | ||
| 401 | |||
| 402 | #define EEPROM_ACCESS_TO 10000 /* timeout counter */ | ||
| 403 | #define START_EEPROM_MGR 0x00000001 | ||
| 404 | |||
| 405 | /*=============================================== | ||
| 406 | EEPROM Base Address - 32bit RW | ||
| 407 | ------------------------------------------ | ||
| 408 | This register holds the upper nine bits | ||
| 409 | [23:15] of the 24-bit Wlan hardware memory | ||
| 410 | address for burst reads from EEPROM accesses. | ||
| 411 | The EEPROM provides the lower 15 bits of this address. | ||
| 412 | The MSB of the address from the EEPROM is ignored. | ||
| 413 | ===============================================*/ | ||
| 414 | #define ACX_EE_CFG EE_CFG | ||
| 415 | |||
| 416 | /*=============================================== | ||
| 417 | GPIO Output Values -32bit, RW | ||
| 418 | ------------------------------------------ | ||
| 419 | [31:16] Reserved | ||
| 420 | [15: 0] Specify the output values (at the output driver inputs) for | ||
| 421 | GPIO[15:0], respectively. | ||
| 422 | ===============================================*/ | ||
| 423 | #define ACX_GPIO_OUT_REG GPIO_OUT | ||
| 424 | #define ACX_MAX_GPIO_LINES 15 | ||
| 425 | |||
| 426 | /*=============================================== | ||
| 427 | Contention window -32bit, RW | ||
| 428 | ------------------------------------------ | ||
| 429 | [31:26] Reserved | ||
| 430 | [25:16] Max (0x3ff) | ||
| 431 | [15:07] Reserved | ||
| 432 | [06:00] Current contention window value - default is 0x1F | ||
| 433 | ===============================================*/ | ||
| 434 | #define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG | ||
| 435 | #define ACX_CONT_WIND_MIN_MASK 0x0000007f | ||
| 436 | #define ACX_CONT_WIND_MAX 0x03ff0000 | ||
| 437 | |||
| 438 | /*=============================================== | ||
| 439 | HI_CFG Interface Configuration Register Values | ||
| 440 | ------------------------------------------ | ||
| 441 | ===============================================*/ | ||
| 442 | #define HI_CFG_UART_ENABLE 0x00000004 | ||
| 443 | #define HI_CFG_RST232_ENABLE 0x00000008 | ||
| 444 | #define HI_CFG_CLOCK_REQ_SELECT 0x00000010 | ||
| 445 | #define HI_CFG_HOST_INT_ENABLE 0x00000020 | ||
| 446 | #define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 | ||
| 447 | #define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 | ||
| 448 | #define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 | ||
| 449 | #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 | ||
| 450 | #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 | ||
| 451 | |||
| 452 | /* | ||
| 453 | * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile | ||
| 454 | * for platforms using active high interrupt level | ||
| 455 | */ | ||
| 456 | #ifdef USE_ACTIVE_HIGH | ||
| 457 | #define HI_CFG_DEF_VAL \ | ||
| 458 | (HI_CFG_UART_ENABLE | \ | ||
| 459 | HI_CFG_RST232_ENABLE | \ | ||
| 460 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
| 461 | HI_CFG_HOST_INT_ENABLE) | ||
| 462 | #else | ||
| 463 | #define HI_CFG_DEF_VAL \ | ||
| 464 | (HI_CFG_UART_ENABLE | \ | ||
| 465 | HI_CFG_RST232_ENABLE | \ | ||
| 466 | HI_CFG_CLOCK_REQ_SELECT | \ | ||
| 467 | HI_CFG_HOST_INT_ENABLE) | ||
| 468 | |||
| 469 | #endif | ||
| 470 | |||
| 471 | #define REF_FREQ_19_2 0 | ||
| 472 | #define REF_FREQ_26_0 1 | ||
| 473 | #define REF_FREQ_38_4 2 | ||
| 474 | #define REF_FREQ_40_0 3 | ||
| 475 | #define REF_FREQ_33_6 4 | ||
| 476 | #define REF_FREQ_NUM 5 | ||
| 477 | |||
| 478 | #define LUT_PARAM_INTEGER_DIVIDER 0 | ||
| 479 | #define LUT_PARAM_FRACTIONAL_DIVIDER 1 | ||
| 480 | #define LUT_PARAM_ATTN_BB 2 | ||
| 481 | #define LUT_PARAM_ALPHA_BB 3 | ||
| 482 | #define LUT_PARAM_STOP_TIME_BB 4 | ||
| 483 | #define LUT_PARAM_BB_PLL_LOOP_FILTER 5 | ||
| 484 | #define LUT_PARAM_NUM 6 | ||
| 485 | |||
| 486 | #define ACX_EEPROMLESS_IND_REG (SCR_PAD4) | ||
| 487 | #define USE_EEPROM 0 | ||
| 488 | #define SOFT_RESET_MAX_TIME 1000000 | ||
| 489 | #define SOFT_RESET_STALL_TIME 1000 | ||
| 490 | #define NVS_DATA_BUNDARY_ALIGNMENT 4 | ||
| 491 | |||
| 492 | |||
| 493 | /* Firmware image load chunk size */ | ||
| 494 | #define CHUNK_SIZE 512 | ||
| 495 | |||
| 496 | /* Firmware image header size */ | ||
| 497 | #define FW_HDR_SIZE 8 | ||
| 498 | |||
| 499 | #define ECPU_CONTROL_HALT 0x00000101 | ||
| 500 | |||
| 501 | |||
| 502 | /****************************************************************************** | ||
| 503 | |||
| 504 | CHANNELS, BAND & REG DOMAINS definitions | ||
| 505 | |||
| 506 | ******************************************************************************/ | ||
| 507 | |||
| 508 | |||
| 509 | enum { | ||
| 510 | RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ | ||
| 511 | RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ | ||
| 512 | RADIO_BAND_JAPAN_4_9_GHZ = 2, | ||
| 513 | DEFAULT_BAND = RADIO_BAND_2_4GHZ, | ||
| 514 | INVALID_BAND = 0xFE, | ||
| 515 | MAX_RADIO_BANDS = 0xFF | ||
| 516 | }; | ||
| 517 | |||
| 518 | enum { | ||
| 519 | NO_RATE = 0, | ||
| 520 | RATE_1MBPS = 0x0A, | ||
| 521 | RATE_2MBPS = 0x14, | ||
| 522 | RATE_5_5MBPS = 0x37, | ||
| 523 | RATE_6MBPS = 0x0B, | ||
| 524 | RATE_9MBPS = 0x0F, | ||
| 525 | RATE_11MBPS = 0x6E, | ||
| 526 | RATE_12MBPS = 0x0A, | ||
| 527 | RATE_18MBPS = 0x0E, | ||
| 528 | RATE_22MBPS = 0xDC, | ||
| 529 | RATE_24MBPS = 0x09, | ||
| 530 | RATE_36MBPS = 0x0D, | ||
| 531 | RATE_48MBPS = 0x08, | ||
| 532 | RATE_54MBPS = 0x0C | ||
| 533 | }; | ||
| 534 | |||
| 535 | enum { | ||
| 536 | RATE_INDEX_1MBPS = 0, | ||
| 537 | RATE_INDEX_2MBPS = 1, | ||
| 538 | RATE_INDEX_5_5MBPS = 2, | ||
| 539 | RATE_INDEX_6MBPS = 3, | ||
| 540 | RATE_INDEX_9MBPS = 4, | ||
| 541 | RATE_INDEX_11MBPS = 5, | ||
| 542 | RATE_INDEX_12MBPS = 6, | ||
| 543 | RATE_INDEX_18MBPS = 7, | ||
| 544 | RATE_INDEX_22MBPS = 8, | ||
| 545 | RATE_INDEX_24MBPS = 9, | ||
| 546 | RATE_INDEX_36MBPS = 10, | ||
| 547 | RATE_INDEX_48MBPS = 11, | ||
| 548 | RATE_INDEX_54MBPS = 12, | ||
| 549 | RATE_INDEX_MAX = RATE_INDEX_54MBPS, | ||
| 550 | MAX_RATE_INDEX, | ||
| 551 | INVALID_RATE_INDEX = MAX_RATE_INDEX, | ||
| 552 | RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF | ||
| 553 | }; | ||
| 554 | |||
| 555 | enum { | ||
| 556 | RATE_MASK_1MBPS = 0x1, | ||
| 557 | RATE_MASK_2MBPS = 0x2, | ||
| 558 | RATE_MASK_5_5MBPS = 0x4, | ||
| 559 | RATE_MASK_11MBPS = 0x20, | ||
| 560 | }; | ||
| 561 | |||
| 562 | #define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ | ||
| 563 | #define OFDM_RATE_BIT BIT(6) | ||
| 564 | #define PBCC_RATE_BIT BIT(7) | ||
| 565 | |||
| 566 | enum { | ||
| 567 | CCK_LONG = 0, | ||
| 568 | CCK_SHORT = SHORT_PREAMBLE_BIT, | ||
| 569 | PBCC_LONG = PBCC_RATE_BIT, | ||
| 570 | PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, | ||
| 571 | OFDM = OFDM_RATE_BIT | ||
| 572 | }; | ||
| 573 | |||
| 574 | /****************************************************************************** | ||
| 575 | |||
| 576 | Transmit-Descriptor RATE-SET field definitions... | ||
| 577 | |||
| 578 | Define a new "Rate-Set" for TX path that incorporates the | ||
| 579 | Rate & Modulation info into a single 16-bit field. | ||
| 580 | |||
| 581 | TxdRateSet_t: | ||
| 582 | b15 - Indicates Preamble type (1=SHORT, 0=LONG). | ||
| 583 | Notes: | ||
| 584 | Must be LONG (0) for 1Mbps rate. | ||
| 585 | Does not apply (set to 0) for RevG-OFDM rates. | ||
| 586 | b14 - Indicates PBCC encoding (1=PBCC, 0=not). | ||
| 587 | Notes: | ||
| 588 | Does not apply (set to 0) for rates 1 and 2 Mbps. | ||
| 589 | Does not apply (set to 0) for RevG-OFDM rates. | ||
| 590 | b13 - Unused (set to 0). | ||
| 591 | b12-b0 - Supported Rate indicator bits as defined below. | ||
| 592 | |||
| 593 | ******************************************************************************/ | ||
| 594 | |||
| 595 | |||
| 596 | /************************************************************************* | ||
| 597 | |||
| 598 | Interrupt Trigger Register (Host -> WiLink) | ||
| 599 | |||
| 600 | **************************************************************************/ | ||
| 601 | |||
| 602 | /* Hardware to Embedded CPU Interrupts - first 32-bit register set */ | ||
| 603 | |||
| 604 | /* | ||
| 605 | * Host Command Interrupt. Setting this bit masks | ||
| 606 | * the interrupt that the host issues to inform | ||
| 607 | * the FW that it has sent a command | ||
| 608 | * to the Wlan hardware Command Mailbox. | ||
| 609 | */ | ||
| 610 | #define INTR_TRIG_CMD BIT(0) | ||
| 611 | |||
| 612 | /* | ||
| 613 | * Host Event Acknowlegde Interrupt. The host | ||
| 614 | * sets this bit to acknowledge that it received | ||
| 615 | * the unsolicited information from the event | ||
| 616 | * mailbox. | ||
| 617 | */ | ||
| 618 | #define INTR_TRIG_EVENT_ACK BIT(1) | ||
| 619 | |||
| 620 | /* | ||
| 621 | * The host sets this bit to inform the Wlan | ||
| 622 | * FW that a TX packet is in the XFER | ||
| 623 | * Buffer #0. | ||
| 624 | */ | ||
| 625 | #define INTR_TRIG_TX_PROC0 BIT(2) | ||
| 626 | |||
| 627 | /* | ||
| 628 | * The host sets this bit to inform the FW | ||
| 629 | * that it read a packet from RX XFER | ||
| 630 | * Buffer #0. | ||
| 631 | */ | ||
| 632 | #define INTR_TRIG_RX_PROC0 BIT(3) | ||
| 633 | |||
| 634 | #define INTR_TRIG_DEBUG_ACK BIT(4) | ||
| 635 | |||
| 636 | #define INTR_TRIG_STATE_CHANGED BIT(5) | ||
| 637 | |||
| 638 | |||
| 639 | /* Hardware to Embedded CPU Interrupts - second 32-bit register set */ | ||
| 640 | |||
| 641 | /* | ||
| 642 | * The host sets this bit to inform the FW | ||
| 643 | * that it read a packet from RX XFER | ||
| 644 | * Buffer #1. | ||
| 645 | */ | ||
| 646 | #define INTR_TRIG_RX_PROC1 BIT(17) | ||
| 647 | |||
| 648 | /* | ||
| 649 | * The host sets this bit to inform the Wlan | ||
| 650 | * hardware that a TX packet is in the XFER | ||
| 651 | * Buffer #1. | ||
| 652 | */ | ||
| 653 | #define INTR_TRIG_TX_PROC1 BIT(18) | ||
| 654 | |||
| 655 | #endif | ||
diff --git a/drivers/net/wireless/wl1251/rx.c b/drivers/net/wireless/wl1251/rx.c new file mode 100644 index 00000000000..6af35265c90 --- /dev/null +++ b/drivers/net/wireless/wl1251/rx.c | |||
| @@ -0,0 +1,235 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/skbuff.h> | ||
| 24 | #include <linux/gfp.h> | ||
| 25 | #include <net/mac80211.h> | ||
| 26 | |||
| 27 | #include "wl1251.h" | ||
| 28 | #include "reg.h" | ||
| 29 | #include "io.h" | ||
| 30 | #include "rx.h" | ||
| 31 | #include "cmd.h" | ||
| 32 | #include "acx.h" | ||
| 33 | |||
| 34 | static void wl1251_rx_header(struct wl1251 *wl, | ||
| 35 | struct wl1251_rx_descriptor *desc) | ||
| 36 | { | ||
| 37 | u32 rx_packet_ring_addr; | ||
| 38 | |||
| 39 | rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr; | ||
| 40 | if (wl->rx_current_buffer) | ||
| 41 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; | ||
| 42 | |||
| 43 | wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc)); | ||
| 44 | } | ||
| 45 | |||
| 46 | static void wl1251_rx_status(struct wl1251 *wl, | ||
| 47 | struct wl1251_rx_descriptor *desc, | ||
| 48 | struct ieee80211_rx_status *status, | ||
| 49 | u8 beacon) | ||
| 50 | { | ||
| 51 | u64 mactime; | ||
| 52 | int ret; | ||
| 53 | |||
| 54 | memset(status, 0, sizeof(struct ieee80211_rx_status)); | ||
| 55 | |||
| 56 | status->band = IEEE80211_BAND_2GHZ; | ||
| 57 | status->mactime = desc->timestamp; | ||
| 58 | |||
| 59 | /* | ||
| 60 | * The rx status timestamp is a 32 bits value while the TSF is a | ||
| 61 | * 64 bits one. | ||
| 62 | * For IBSS merging, TSF is mandatory, so we have to get it | ||
| 63 | * somehow, so we ask for ACX_TSF_INFO. | ||
| 64 | * That could be moved to the get_tsf() hook, but unfortunately, | ||
| 65 | * this one must be atomic, while our SPI routines can sleep. | ||
| 66 | */ | ||
| 67 | if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) { | ||
| 68 | ret = wl1251_acx_tsf_info(wl, &mactime); | ||
| 69 | if (ret == 0) | ||
| 70 | status->mactime = mactime; | ||
| 71 | } | ||
| 72 | |||
| 73 | status->signal = desc->rssi; | ||
| 74 | |||
| 75 | /* | ||
| 76 | * FIXME: guessing that snr needs to be divided by two, otherwise | ||
| 77 | * the values don't make any sense | ||
| 78 | */ | ||
| 79 | wl->noise = desc->rssi - desc->snr / 2; | ||
| 80 | |||
| 81 | status->freq = ieee80211_channel_to_frequency(desc->channel, | ||
| 82 | status->band); | ||
| 83 | |||
| 84 | status->flag |= RX_FLAG_MACTIME_MPDU; | ||
| 85 | |||
| 86 | if (desc->flags & RX_DESC_ENCRYPTION_MASK) { | ||
| 87 | status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; | ||
| 88 | |||
| 89 | if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) | ||
| 90 | status->flag |= RX_FLAG_DECRYPTED; | ||
| 91 | |||
| 92 | if (unlikely(desc->flags & RX_DESC_MIC_FAIL)) | ||
| 93 | status->flag |= RX_FLAG_MMIC_ERROR; | ||
| 94 | } | ||
| 95 | |||
| 96 | if (unlikely(!(desc->flags & RX_DESC_VALID_FCS))) | ||
| 97 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
| 98 | |||
| 99 | switch (desc->rate) { | ||
| 100 | /* skip 1 and 12 Mbps because they have same value 0x0a */ | ||
| 101 | case RATE_2MBPS: | ||
| 102 | status->rate_idx = 1; | ||
| 103 | break; | ||
| 104 | case RATE_5_5MBPS: | ||
| 105 | status->rate_idx = 2; | ||
| 106 | break; | ||
| 107 | case RATE_11MBPS: | ||
| 108 | status->rate_idx = 3; | ||
| 109 | break; | ||
| 110 | case RATE_6MBPS: | ||
| 111 | status->rate_idx = 4; | ||
| 112 | break; | ||
| 113 | case RATE_9MBPS: | ||
| 114 | status->rate_idx = 5; | ||
| 115 | break; | ||
| 116 | case RATE_18MBPS: | ||
| 117 | status->rate_idx = 7; | ||
| 118 | break; | ||
| 119 | case RATE_24MBPS: | ||
| 120 | status->rate_idx = 8; | ||
| 121 | break; | ||
| 122 | case RATE_36MBPS: | ||
| 123 | status->rate_idx = 9; | ||
| 124 | break; | ||
| 125 | case RATE_48MBPS: | ||
| 126 | status->rate_idx = 10; | ||
| 127 | break; | ||
| 128 | case RATE_54MBPS: | ||
| 129 | status->rate_idx = 11; | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | |||
| 133 | /* for 1 and 12 Mbps we have to check the modulation */ | ||
| 134 | if (desc->rate == RATE_1MBPS) { | ||
| 135 | if (!(desc->mod_pre & OFDM_RATE_BIT)) | ||
| 136 | /* CCK -> RATE_1MBPS */ | ||
| 137 | status->rate_idx = 0; | ||
| 138 | else | ||
| 139 | /* OFDM -> RATE_12MBPS */ | ||
| 140 | status->rate_idx = 6; | ||
| 141 | } | ||
| 142 | |||
| 143 | if (desc->mod_pre & SHORT_PREAMBLE_BIT) | ||
| 144 | status->flag |= RX_FLAG_SHORTPRE; | ||
| 145 | } | ||
| 146 | |||
| 147 | static void wl1251_rx_body(struct wl1251 *wl, | ||
| 148 | struct wl1251_rx_descriptor *desc) | ||
| 149 | { | ||
| 150 | struct sk_buff *skb; | ||
| 151 | struct ieee80211_rx_status status; | ||
| 152 | u8 *rx_buffer, beacon = 0; | ||
| 153 | u16 length, *fc; | ||
| 154 | u32 curr_id, last_id_inc, rx_packet_ring_addr; | ||
| 155 | |||
| 156 | length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH); | ||
| 157 | curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT; | ||
| 158 | last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1); | ||
| 159 | |||
| 160 | if (last_id_inc != curr_id) { | ||
| 161 | wl1251_warning("curr ID:%d, last ID inc:%d", | ||
| 162 | curr_id, last_id_inc); | ||
| 163 | wl->rx_last_id = curr_id; | ||
| 164 | } else { | ||
| 165 | wl->rx_last_id = last_id_inc; | ||
| 166 | } | ||
| 167 | |||
| 168 | rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr + | ||
| 169 | sizeof(struct wl1251_rx_descriptor) + 20; | ||
| 170 | if (wl->rx_current_buffer) | ||
| 171 | rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size; | ||
| 172 | |||
| 173 | skb = __dev_alloc_skb(length, GFP_KERNEL); | ||
| 174 | if (!skb) { | ||
| 175 | wl1251_error("Couldn't allocate RX frame"); | ||
| 176 | return; | ||
| 177 | } | ||
| 178 | |||
| 179 | rx_buffer = skb_put(skb, length); | ||
| 180 | wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); | ||
| 181 | |||
| 182 | /* The actual length doesn't include the target's alignment */ | ||
| 183 | skb->len = desc->length - PLCP_HEADER_LENGTH; | ||
| 184 | |||
| 185 | fc = (u16 *)skb->data; | ||
| 186 | |||
| 187 | if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) | ||
| 188 | beacon = 1; | ||
| 189 | |||
| 190 | wl1251_rx_status(wl, desc, &status, beacon); | ||
| 191 | |||
| 192 | wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, | ||
| 193 | beacon ? "beacon" : ""); | ||
| 194 | |||
| 195 | memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); | ||
| 196 | ieee80211_rx_ni(wl->hw, skb); | ||
| 197 | } | ||
| 198 | |||
| 199 | static void wl1251_rx_ack(struct wl1251 *wl) | ||
| 200 | { | ||
| 201 | u32 data, addr; | ||
| 202 | |||
| 203 | if (wl->rx_current_buffer) { | ||
| 204 | addr = ACX_REG_INTERRUPT_TRIG_H; | ||
| 205 | data = INTR_TRIG_RX_PROC1; | ||
| 206 | } else { | ||
| 207 | addr = ACX_REG_INTERRUPT_TRIG; | ||
| 208 | data = INTR_TRIG_RX_PROC0; | ||
| 209 | } | ||
| 210 | |||
| 211 | wl1251_reg_write32(wl, addr, data); | ||
| 212 | |||
| 213 | /* Toggle buffer ring */ | ||
| 214 | wl->rx_current_buffer = !wl->rx_current_buffer; | ||
| 215 | } | ||
| 216 | |||
| 217 | |||
| 218 | void wl1251_rx(struct wl1251 *wl) | ||
| 219 | { | ||
| 220 | struct wl1251_rx_descriptor *rx_desc; | ||
| 221 | |||
| 222 | if (wl->state != WL1251_STATE_ON) | ||
| 223 | return; | ||
| 224 | |||
| 225 | rx_desc = wl->rx_descriptor; | ||
| 226 | |||
| 227 | /* We first read the frame's header */ | ||
| 228 | wl1251_rx_header(wl, rx_desc); | ||
| 229 | |||
| 230 | /* Now we can read the body */ | ||
| 231 | wl1251_rx_body(wl, rx_desc); | ||
| 232 | |||
| 233 | /* Finally, we need to ACK the RX */ | ||
| 234 | wl1251_rx_ack(wl); | ||
| 235 | } | ||
diff --git a/drivers/net/wireless/wl1251/rx.h b/drivers/net/wireless/wl1251/rx.h new file mode 100644 index 00000000000..4448f635a4d --- /dev/null +++ b/drivers/net/wireless/wl1251/rx.h | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __WL1251_RX_H__ | ||
| 24 | #define __WL1251_RX_H__ | ||
| 25 | |||
| 26 | #include <linux/bitops.h> | ||
| 27 | |||
| 28 | #include "wl1251.h" | ||
| 29 | |||
| 30 | /* | ||
| 31 | * RX PATH | ||
| 32 | * | ||
| 33 | * The Rx path uses a double buffer and an rx_contro structure, each located | ||
| 34 | * at a fixed address in the device memory. The host keeps track of which | ||
| 35 | * buffer is available and alternates between them on a per packet basis. | ||
| 36 | * The size of each of the two buffers is large enough to hold the longest | ||
| 37 | * 802.3 packet. | ||
| 38 | * The RX path goes like that: | ||
| 39 | * 1) The target generates an interrupt each time a new packet is received. | ||
| 40 | * There are 2 RX interrupts, one for each buffer. | ||
| 41 | * 2) The host reads the received packet from one of the double buffers. | ||
| 42 | * 3) The host triggers a target interrupt. | ||
| 43 | * 4) The target prepares the next RX packet. | ||
| 44 | */ | ||
| 45 | |||
| 46 | #define WL1251_RX_MAX_RSSI -30 | ||
| 47 | #define WL1251_RX_MIN_RSSI -95 | ||
| 48 | |||
| 49 | #define WL1251_RX_ALIGN_TO 4 | ||
| 50 | #define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \ | ||
| 51 | ~(WL1251_RX_ALIGN_TO - 1)) | ||
| 52 | |||
| 53 | #define SHORT_PREAMBLE_BIT BIT(0) | ||
| 54 | #define OFDM_RATE_BIT BIT(6) | ||
| 55 | #define PBCC_RATE_BIT BIT(7) | ||
| 56 | |||
| 57 | #define PLCP_HEADER_LENGTH 8 | ||
| 58 | #define RX_DESC_PACKETID_SHIFT 11 | ||
| 59 | #define RX_MAX_PACKET_ID 3 | ||
| 60 | |||
| 61 | #define RX_DESC_VALID_FCS 0x0001 | ||
| 62 | #define RX_DESC_MATCH_RXADDR1 0x0002 | ||
| 63 | #define RX_DESC_MCAST 0x0004 | ||
| 64 | #define RX_DESC_STAINTIM 0x0008 | ||
| 65 | #define RX_DESC_VIRTUAL_BM 0x0010 | ||
| 66 | #define RX_DESC_BCAST 0x0020 | ||
| 67 | #define RX_DESC_MATCH_SSID 0x0040 | ||
| 68 | #define RX_DESC_MATCH_BSSID 0x0080 | ||
| 69 | #define RX_DESC_ENCRYPTION_MASK 0x0300 | ||
| 70 | #define RX_DESC_MEASURMENT 0x0400 | ||
| 71 | #define RX_DESC_SEQNUM_MASK 0x1800 | ||
| 72 | #define RX_DESC_MIC_FAIL 0x2000 | ||
| 73 | #define RX_DESC_DECRYPT_FAIL 0x4000 | ||
| 74 | |||
| 75 | struct wl1251_rx_descriptor { | ||
| 76 | u32 timestamp; /* In microseconds */ | ||
| 77 | u16 length; /* Paylod length, including headers */ | ||
| 78 | u16 flags; | ||
| 79 | |||
| 80 | /* | ||
| 81 | * 0 - 802.11 | ||
| 82 | * 1 - 802.3 | ||
| 83 | * 2 - IP | ||
| 84 | * 3 - Raw Codec | ||
| 85 | */ | ||
| 86 | u8 type; | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Received Rate: | ||
| 90 | * 0x0A - 1MBPS | ||
| 91 | * 0x14 - 2MBPS | ||
| 92 | * 0x37 - 5_5MBPS | ||
| 93 | * 0x0B - 6MBPS | ||
| 94 | * 0x0F - 9MBPS | ||
| 95 | * 0x6E - 11MBPS | ||
| 96 | * 0x0A - 12MBPS | ||
| 97 | * 0x0E - 18MBPS | ||
| 98 | * 0xDC - 22MBPS | ||
| 99 | * 0x09 - 24MBPS | ||
| 100 | * 0x0D - 36MBPS | ||
| 101 | * 0x08 - 48MBPS | ||
| 102 | * 0x0C - 54MBPS | ||
| 103 | */ | ||
| 104 | u8 rate; | ||
| 105 | |||
| 106 | u8 mod_pre; /* Modulation and preamble */ | ||
| 107 | u8 channel; | ||
| 108 | |||
| 109 | /* | ||
| 110 | * 0 - 2.4 Ghz | ||
| 111 | * 1 - 5 Ghz | ||
| 112 | */ | ||
| 113 | u8 band; | ||
| 114 | |||
| 115 | s8 rssi; /* in dB */ | ||
| 116 | u8 rcpi; /* in dB */ | ||
| 117 | u8 snr; /* in dB */ | ||
| 118 | } __packed; | ||
| 119 | |||
| 120 | void wl1251_rx(struct wl1251 *wl); | ||
| 121 | |||
| 122 | #endif | ||
diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c new file mode 100644 index 00000000000..f78694295c3 --- /dev/null +++ b/drivers/net/wireless/wl1251/sdio.c | |||
| @@ -0,0 +1,374 @@ | |||
| 1 | /* | ||
| 2 | * wl12xx SDIO routines | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, but | ||
| 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 11 | * General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program; if not, write to the Free Software | ||
| 15 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 16 | * 02110-1301 USA | ||
| 17 | * | ||
| 18 | * Copyright (C) 2005 Texas Instruments Incorporated | ||
| 19 | * Copyright (C) 2008 Google Inc | ||
| 20 | * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) | ||
| 21 | */ | ||
| 22 | #include <linux/interrupt.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/mod_devicetable.h> | ||
| 25 | #include <linux/mmc/sdio_func.h> | ||
| 26 | #include <linux/mmc/sdio_ids.h> | ||
| 27 | #include <linux/platform_device.h> | ||
| 28 | #include <linux/wl12xx.h> | ||
| 29 | #include <linux/irq.h> | ||
| 30 | #include <linux/pm_runtime.h> | ||
| 31 | |||
| 32 | #include "wl1251.h" | ||
| 33 | |||
| 34 | #ifndef SDIO_VENDOR_ID_TI | ||
| 35 | #define SDIO_VENDOR_ID_TI 0x104c | ||
| 36 | #endif | ||
| 37 | |||
| 38 | #ifndef SDIO_DEVICE_ID_TI_WL1251 | ||
| 39 | #define SDIO_DEVICE_ID_TI_WL1251 0x9066 | ||
| 40 | #endif | ||
| 41 | |||
| 42 | struct wl1251_sdio { | ||
| 43 | struct sdio_func *func; | ||
| 44 | u32 elp_val; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static struct sdio_func *wl_to_func(struct wl1251 *wl) | ||
| 48 | { | ||
| 49 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
| 50 | return wl_sdio->func; | ||
| 51 | } | ||
| 52 | |||
| 53 | static void wl1251_sdio_interrupt(struct sdio_func *func) | ||
| 54 | { | ||
| 55 | struct wl1251 *wl = sdio_get_drvdata(func); | ||
| 56 | |||
| 57 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
| 58 | |||
| 59 | /* FIXME should be synchronous for sdio */ | ||
| 60 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
| 61 | } | ||
| 62 | |||
| 63 | static const struct sdio_device_id wl1251_devices[] = { | ||
| 64 | { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1251) }, | ||
| 65 | {} | ||
| 66 | }; | ||
| 67 | MODULE_DEVICE_TABLE(sdio, wl1251_devices); | ||
| 68 | |||
| 69 | |||
| 70 | static void wl1251_sdio_read(struct wl1251 *wl, int addr, | ||
| 71 | void *buf, size_t len) | ||
| 72 | { | ||
| 73 | int ret; | ||
| 74 | struct sdio_func *func = wl_to_func(wl); | ||
| 75 | |||
| 76 | sdio_claim_host(func); | ||
| 77 | ret = sdio_memcpy_fromio(func, buf, addr, len); | ||
| 78 | if (ret) | ||
| 79 | wl1251_error("sdio read failed (%d)", ret); | ||
| 80 | sdio_release_host(func); | ||
| 81 | } | ||
| 82 | |||
| 83 | static void wl1251_sdio_write(struct wl1251 *wl, int addr, | ||
| 84 | void *buf, size_t len) | ||
| 85 | { | ||
| 86 | int ret; | ||
| 87 | struct sdio_func *func = wl_to_func(wl); | ||
| 88 | |||
| 89 | sdio_claim_host(func); | ||
| 90 | ret = sdio_memcpy_toio(func, addr, buf, len); | ||
| 91 | if (ret) | ||
| 92 | wl1251_error("sdio write failed (%d)", ret); | ||
| 93 | sdio_release_host(func); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val) | ||
| 97 | { | ||
| 98 | int ret = 0; | ||
| 99 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
| 100 | struct sdio_func *func = wl_sdio->func; | ||
| 101 | |||
| 102 | /* | ||
| 103 | * The hardware only supports RAW (read after write) access for | ||
| 104 | * reading, regular sdio_readb won't work here (it interprets | ||
| 105 | * the unused bits of CMD52 as write data even if we send read | ||
| 106 | * request). | ||
| 107 | */ | ||
| 108 | sdio_claim_host(func); | ||
| 109 | *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret); | ||
| 110 | sdio_release_host(func); | ||
| 111 | |||
| 112 | if (ret) | ||
| 113 | wl1251_error("sdio_readb failed (%d)", ret); | ||
| 114 | } | ||
| 115 | |||
| 116 | static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val) | ||
| 117 | { | ||
| 118 | int ret = 0; | ||
| 119 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
| 120 | struct sdio_func *func = wl_sdio->func; | ||
| 121 | |||
| 122 | sdio_claim_host(func); | ||
| 123 | sdio_writeb(func, val, addr, &ret); | ||
| 124 | sdio_release_host(func); | ||
| 125 | |||
| 126 | if (ret) | ||
| 127 | wl1251_error("sdio_writeb failed (%d)", ret); | ||
| 128 | else | ||
| 129 | wl_sdio->elp_val = val; | ||
| 130 | } | ||
| 131 | |||
| 132 | static void wl1251_sdio_reset(struct wl1251 *wl) | ||
| 133 | { | ||
| 134 | } | ||
| 135 | |||
| 136 | static void wl1251_sdio_enable_irq(struct wl1251 *wl) | ||
| 137 | { | ||
| 138 | struct sdio_func *func = wl_to_func(wl); | ||
| 139 | |||
| 140 | sdio_claim_host(func); | ||
| 141 | sdio_claim_irq(func, wl1251_sdio_interrupt); | ||
| 142 | sdio_release_host(func); | ||
| 143 | } | ||
| 144 | |||
| 145 | static void wl1251_sdio_disable_irq(struct wl1251 *wl) | ||
| 146 | { | ||
| 147 | struct sdio_func *func = wl_to_func(wl); | ||
| 148 | |||
| 149 | sdio_claim_host(func); | ||
| 150 | sdio_release_irq(func); | ||
| 151 | sdio_release_host(func); | ||
| 152 | } | ||
| 153 | |||
| 154 | /* Interrupts when using dedicated WLAN_IRQ pin */ | ||
| 155 | static irqreturn_t wl1251_line_irq(int irq, void *cookie) | ||
| 156 | { | ||
| 157 | struct wl1251 *wl = cookie; | ||
| 158 | |||
| 159 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
| 160 | |||
| 161 | return IRQ_HANDLED; | ||
| 162 | } | ||
| 163 | |||
| 164 | static void wl1251_enable_line_irq(struct wl1251 *wl) | ||
| 165 | { | ||
| 166 | return enable_irq(wl->irq); | ||
| 167 | } | ||
| 168 | |||
| 169 | static void wl1251_disable_line_irq(struct wl1251 *wl) | ||
| 170 | { | ||
| 171 | return disable_irq(wl->irq); | ||
| 172 | } | ||
| 173 | |||
| 174 | static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) | ||
| 175 | { | ||
| 176 | struct sdio_func *func = wl_to_func(wl); | ||
| 177 | int ret; | ||
| 178 | |||
| 179 | if (enable) { | ||
| 180 | /* | ||
| 181 | * Power is controlled by runtime PM, but we still call board | ||
| 182 | * callback in case it wants to do any additional setup, | ||
| 183 | * for example enabling clock buffer for the module. | ||
| 184 | */ | ||
| 185 | if (wl->set_power) | ||
| 186 | wl->set_power(true); | ||
| 187 | |||
| 188 | ret = pm_runtime_get_sync(&func->dev); | ||
| 189 | if (ret < 0) | ||
| 190 | goto out; | ||
| 191 | |||
| 192 | sdio_claim_host(func); | ||
| 193 | sdio_enable_func(func); | ||
| 194 | sdio_release_host(func); | ||
| 195 | } else { | ||
| 196 | sdio_claim_host(func); | ||
| 197 | sdio_disable_func(func); | ||
| 198 | sdio_release_host(func); | ||
| 199 | |||
| 200 | ret = pm_runtime_put_sync(&func->dev); | ||
| 201 | if (ret < 0) | ||
| 202 | goto out; | ||
| 203 | |||
| 204 | if (wl->set_power) | ||
| 205 | wl->set_power(false); | ||
| 206 | } | ||
| 207 | |||
| 208 | out: | ||
| 209 | return ret; | ||
| 210 | } | ||
| 211 | |||
| 212 | static struct wl1251_if_operations wl1251_sdio_ops = { | ||
| 213 | .read = wl1251_sdio_read, | ||
| 214 | .write = wl1251_sdio_write, | ||
| 215 | .write_elp = wl1251_sdio_write_elp, | ||
| 216 | .read_elp = wl1251_sdio_read_elp, | ||
| 217 | .reset = wl1251_sdio_reset, | ||
| 218 | .power = wl1251_sdio_set_power, | ||
| 219 | }; | ||
| 220 | |||
| 221 | static int wl1251_sdio_probe(struct sdio_func *func, | ||
| 222 | const struct sdio_device_id *id) | ||
| 223 | { | ||
| 224 | int ret; | ||
| 225 | struct wl1251 *wl; | ||
| 226 | struct ieee80211_hw *hw; | ||
| 227 | struct wl1251_sdio *wl_sdio; | ||
| 228 | const struct wl12xx_platform_data *wl12xx_board_data; | ||
| 229 | |||
| 230 | hw = wl1251_alloc_hw(); | ||
| 231 | if (IS_ERR(hw)) | ||
| 232 | return PTR_ERR(hw); | ||
| 233 | |||
| 234 | wl = hw->priv; | ||
| 235 | |||
| 236 | wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL); | ||
| 237 | if (wl_sdio == NULL) { | ||
| 238 | ret = -ENOMEM; | ||
| 239 | goto out_free_hw; | ||
| 240 | } | ||
| 241 | |||
| 242 | sdio_claim_host(func); | ||
| 243 | ret = sdio_enable_func(func); | ||
| 244 | if (ret) | ||
| 245 | goto release; | ||
| 246 | |||
| 247 | sdio_set_block_size(func, 512); | ||
| 248 | sdio_release_host(func); | ||
| 249 | |||
| 250 | SET_IEEE80211_DEV(hw, &func->dev); | ||
| 251 | wl_sdio->func = func; | ||
| 252 | wl->if_priv = wl_sdio; | ||
| 253 | wl->if_ops = &wl1251_sdio_ops; | ||
| 254 | |||
| 255 | wl12xx_board_data = wl12xx_get_platform_data(); | ||
| 256 | if (!IS_ERR(wl12xx_board_data)) { | ||
| 257 | wl->set_power = wl12xx_board_data->set_power; | ||
| 258 | wl->irq = wl12xx_board_data->irq; | ||
| 259 | wl->use_eeprom = wl12xx_board_data->use_eeprom; | ||
| 260 | } | ||
| 261 | |||
| 262 | if (wl->irq) { | ||
| 263 | ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); | ||
| 264 | if (ret < 0) { | ||
| 265 | wl1251_error("request_irq() failed: %d", ret); | ||
| 266 | goto disable; | ||
| 267 | } | ||
| 268 | |||
| 269 | irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
| 270 | disable_irq(wl->irq); | ||
| 271 | |||
| 272 | wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; | ||
| 273 | wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; | ||
| 274 | |||
| 275 | wl1251_info("using dedicated interrupt line"); | ||
| 276 | } else { | ||
| 277 | wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq; | ||
| 278 | wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq; | ||
| 279 | |||
| 280 | wl1251_info("using SDIO interrupt"); | ||
| 281 | } | ||
| 282 | |||
| 283 | ret = wl1251_init_ieee80211(wl); | ||
| 284 | if (ret) | ||
| 285 | goto out_free_irq; | ||
| 286 | |||
| 287 | sdio_set_drvdata(func, wl); | ||
| 288 | |||
| 289 | /* Tell PM core that we don't need the card to be powered now */ | ||
| 290 | pm_runtime_put_noidle(&func->dev); | ||
| 291 | |||
| 292 | return ret; | ||
| 293 | |||
| 294 | out_free_irq: | ||
| 295 | if (wl->irq) | ||
| 296 | free_irq(wl->irq, wl); | ||
| 297 | disable: | ||
| 298 | sdio_claim_host(func); | ||
| 299 | sdio_disable_func(func); | ||
| 300 | release: | ||
| 301 | sdio_release_host(func); | ||
| 302 | kfree(wl_sdio); | ||
| 303 | out_free_hw: | ||
| 304 | wl1251_free_hw(wl); | ||
| 305 | return ret; | ||
| 306 | } | ||
| 307 | |||
| 308 | static void __devexit wl1251_sdio_remove(struct sdio_func *func) | ||
| 309 | { | ||
| 310 | struct wl1251 *wl = sdio_get_drvdata(func); | ||
| 311 | struct wl1251_sdio *wl_sdio = wl->if_priv; | ||
| 312 | |||
| 313 | /* Undo decrement done above in wl1251_probe */ | ||
| 314 | pm_runtime_get_noresume(&func->dev); | ||
| 315 | |||
| 316 | if (wl->irq) | ||
| 317 | free_irq(wl->irq, wl); | ||
| 318 | kfree(wl_sdio); | ||
| 319 | wl1251_free_hw(wl); | ||
| 320 | |||
| 321 | sdio_claim_host(func); | ||
| 322 | sdio_release_irq(func); | ||
| 323 | sdio_disable_func(func); | ||
| 324 | sdio_release_host(func); | ||
| 325 | } | ||
| 326 | |||
| 327 | static int wl1251_suspend(struct device *dev) | ||
| 328 | { | ||
| 329 | /* | ||
| 330 | * Tell MMC/SDIO core it's OK to power down the card | ||
| 331 | * (if it isn't already), but not to remove it completely. | ||
| 332 | */ | ||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | |||
| 336 | static int wl1251_resume(struct device *dev) | ||
| 337 | { | ||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 341 | static const struct dev_pm_ops wl1251_sdio_pm_ops = { | ||
| 342 | .suspend = wl1251_suspend, | ||
| 343 | .resume = wl1251_resume, | ||
| 344 | }; | ||
| 345 | |||
| 346 | static struct sdio_driver wl1251_sdio_driver = { | ||
| 347 | .name = "wl1251_sdio", | ||
| 348 | .id_table = wl1251_devices, | ||
| 349 | .probe = wl1251_sdio_probe, | ||
| 350 | .remove = __devexit_p(wl1251_sdio_remove), | ||
| 351 | .drv.pm = &wl1251_sdio_pm_ops, | ||
| 352 | }; | ||
| 353 | |||
| 354 | static int __init wl1251_sdio_init(void) | ||
| 355 | { | ||
| 356 | int err; | ||
| 357 | |||
| 358 | err = sdio_register_driver(&wl1251_sdio_driver); | ||
| 359 | if (err) | ||
| 360 | wl1251_error("failed to register sdio driver: %d", err); | ||
| 361 | return err; | ||
| 362 | } | ||
| 363 | |||
| 364 | static void __exit wl1251_sdio_exit(void) | ||
| 365 | { | ||
| 366 | sdio_unregister_driver(&wl1251_sdio_driver); | ||
| 367 | wl1251_notice("unloaded"); | ||
| 368 | } | ||
| 369 | |||
| 370 | module_init(wl1251_sdio_init); | ||
| 371 | module_exit(wl1251_sdio_exit); | ||
| 372 | |||
| 373 | MODULE_LICENSE("GPL"); | ||
| 374 | MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); | ||
diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c new file mode 100644 index 00000000000..eaa5f955620 --- /dev/null +++ b/drivers/net/wireless/wl1251/spi.c | |||
| @@ -0,0 +1,356 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Nokia Corporation | ||
| 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 <linux/interrupt.h> | ||
| 23 | #include <linux/irq.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/crc7.h> | ||
| 27 | #include <linux/spi/spi.h> | ||
| 28 | #include <linux/wl12xx.h> | ||
| 29 | |||
| 30 | #include "wl1251.h" | ||
| 31 | #include "reg.h" | ||
| 32 | #include "spi.h" | ||
| 33 | |||
| 34 | static irqreturn_t wl1251_irq(int irq, void *cookie) | ||
| 35 | { | ||
| 36 | struct wl1251 *wl; | ||
| 37 | |||
| 38 | wl1251_debug(DEBUG_IRQ, "IRQ"); | ||
| 39 | |||
| 40 | wl = cookie; | ||
| 41 | |||
| 42 | ieee80211_queue_work(wl->hw, &wl->irq_work); | ||
| 43 | |||
| 44 | return IRQ_HANDLED; | ||
| 45 | } | ||
| 46 | |||
| 47 | static struct spi_device *wl_to_spi(struct wl1251 *wl) | ||
| 48 | { | ||
| 49 | return wl->if_priv; | ||
| 50 | } | ||
| 51 | |||
| 52 | static void wl1251_spi_reset(struct wl1251 *wl) | ||
| 53 | { | ||
| 54 | u8 *cmd; | ||
| 55 | struct spi_transfer t; | ||
| 56 | struct spi_message m; | ||
| 57 | |||
| 58 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
| 59 | if (!cmd) { | ||
| 60 | wl1251_error("could not allocate cmd for spi reset"); | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | |||
| 64 | memset(&t, 0, sizeof(t)); | ||
| 65 | spi_message_init(&m); | ||
| 66 | |||
| 67 | memset(cmd, 0xff, WSPI_INIT_CMD_LEN); | ||
| 68 | |||
| 69 | t.tx_buf = cmd; | ||
| 70 | t.len = WSPI_INIT_CMD_LEN; | ||
| 71 | spi_message_add_tail(&t, &m); | ||
| 72 | |||
| 73 | spi_sync(wl_to_spi(wl), &m); | ||
| 74 | |||
| 75 | wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void wl1251_spi_wake(struct wl1251 *wl) | ||
| 79 | { | ||
| 80 | u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd; | ||
| 81 | struct spi_transfer t; | ||
| 82 | struct spi_message m; | ||
| 83 | |||
| 84 | cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL); | ||
| 85 | if (!cmd) { | ||
| 86 | wl1251_error("could not allocate cmd for spi init"); | ||
| 87 | return; | ||
| 88 | } | ||
| 89 | |||
| 90 | memset(crc, 0, sizeof(crc)); | ||
| 91 | memset(&t, 0, sizeof(t)); | ||
| 92 | spi_message_init(&m); | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Set WSPI_INIT_COMMAND | ||
| 96 | * the data is being send from the MSB to LSB | ||
| 97 | */ | ||
| 98 | cmd[2] = 0xff; | ||
| 99 | cmd[3] = 0xff; | ||
| 100 | cmd[1] = WSPI_INIT_CMD_START | WSPI_INIT_CMD_TX; | ||
| 101 | cmd[0] = 0; | ||
| 102 | cmd[7] = 0; | ||
| 103 | cmd[6] |= HW_ACCESS_WSPI_INIT_CMD_MASK << 3; | ||
| 104 | cmd[6] |= HW_ACCESS_WSPI_FIXED_BUSY_LEN & WSPI_INIT_CMD_FIXEDBUSY_LEN; | ||
| 105 | |||
| 106 | if (HW_ACCESS_WSPI_FIXED_BUSY_LEN == 0) | ||
| 107 | cmd[5] |= WSPI_INIT_CMD_DIS_FIXEDBUSY; | ||
| 108 | else | ||
| 109 | cmd[5] |= WSPI_INIT_CMD_EN_FIXEDBUSY; | ||
| 110 | |||
| 111 | cmd[5] |= WSPI_INIT_CMD_IOD | WSPI_INIT_CMD_IP | WSPI_INIT_CMD_CS | ||
| 112 | | WSPI_INIT_CMD_WSPI | WSPI_INIT_CMD_WS; | ||
| 113 | |||
| 114 | crc[0] = cmd[1]; | ||
| 115 | crc[1] = cmd[0]; | ||
| 116 | crc[2] = cmd[7]; | ||
| 117 | crc[3] = cmd[6]; | ||
| 118 | crc[4] = cmd[5]; | ||
| 119 | |||
| 120 | cmd[4] |= crc7(0, crc, WSPI_INIT_CMD_CRC_LEN) << 1; | ||
| 121 | cmd[4] |= WSPI_INIT_CMD_END; | ||
| 122 | |||
| 123 | t.tx_buf = cmd; | ||
| 124 | t.len = WSPI_INIT_CMD_LEN; | ||
| 125 | spi_message_add_tail(&t, &m); | ||
| 126 | |||
| 127 | spi_sync(wl_to_spi(wl), &m); | ||
| 128 | |||
| 129 | wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); | ||
| 130 | } | ||
| 131 | |||
| 132 | static void wl1251_spi_reset_wake(struct wl1251 *wl) | ||
| 133 | { | ||
| 134 | wl1251_spi_reset(wl); | ||
| 135 | wl1251_spi_wake(wl); | ||
| 136 | } | ||
| 137 | |||
| 138 | static void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf, | ||
| 139 | size_t len) | ||
| 140 | { | ||
| 141 | struct spi_transfer t[3]; | ||
| 142 | struct spi_message m; | ||
| 143 | u8 *busy_buf; | ||
| 144 | u32 *cmd; | ||
| 145 | |||
| 146 | cmd = &wl->buffer_cmd; | ||
| 147 | busy_buf = wl->buffer_busyword; | ||
| 148 | |||
| 149 | *cmd = 0; | ||
| 150 | *cmd |= WSPI_CMD_READ; | ||
| 151 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
| 152 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
| 153 | |||
| 154 | spi_message_init(&m); | ||
| 155 | memset(t, 0, sizeof(t)); | ||
| 156 | |||
| 157 | t[0].tx_buf = cmd; | ||
| 158 | t[0].len = 4; | ||
| 159 | spi_message_add_tail(&t[0], &m); | ||
| 160 | |||
| 161 | /* Busy and non busy words read */ | ||
| 162 | t[1].rx_buf = busy_buf; | ||
| 163 | t[1].len = WL1251_BUSY_WORD_LEN; | ||
| 164 | spi_message_add_tail(&t[1], &m); | ||
| 165 | |||
| 166 | t[2].rx_buf = buf; | ||
| 167 | t[2].len = len; | ||
| 168 | spi_message_add_tail(&t[2], &m); | ||
| 169 | |||
| 170 | spi_sync(wl_to_spi(wl), &m); | ||
| 171 | |||
| 172 | /* FIXME: check busy words */ | ||
| 173 | |||
| 174 | wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); | ||
| 175 | wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); | ||
| 176 | } | ||
| 177 | |||
| 178 | static void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf, | ||
| 179 | size_t len) | ||
| 180 | { | ||
| 181 | struct spi_transfer t[2]; | ||
| 182 | struct spi_message m; | ||
| 183 | u32 *cmd; | ||
| 184 | |||
| 185 | cmd = &wl->buffer_cmd; | ||
| 186 | |||
| 187 | *cmd = 0; | ||
| 188 | *cmd |= WSPI_CMD_WRITE; | ||
| 189 | *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; | ||
| 190 | *cmd |= addr & WSPI_CMD_BYTE_ADDR; | ||
| 191 | |||
| 192 | spi_message_init(&m); | ||
| 193 | memset(t, 0, sizeof(t)); | ||
| 194 | |||
| 195 | t[0].tx_buf = cmd; | ||
| 196 | t[0].len = sizeof(*cmd); | ||
| 197 | spi_message_add_tail(&t[0], &m); | ||
| 198 | |||
| 199 | t[1].tx_buf = buf; | ||
| 200 | t[1].len = len; | ||
| 201 | spi_message_add_tail(&t[1], &m); | ||
| 202 | |||
| 203 | spi_sync(wl_to_spi(wl), &m); | ||
| 204 | |||
| 205 | wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd)); | ||
| 206 | wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); | ||
| 207 | } | ||
| 208 | |||
| 209 | static void wl1251_spi_enable_irq(struct wl1251 *wl) | ||
| 210 | { | ||
| 211 | return enable_irq(wl->irq); | ||
| 212 | } | ||
| 213 | |||
| 214 | static void wl1251_spi_disable_irq(struct wl1251 *wl) | ||
| 215 | { | ||
| 216 | return disable_irq(wl->irq); | ||
| 217 | } | ||
| 218 | |||
| 219 | static int wl1251_spi_set_power(struct wl1251 *wl, bool enable) | ||
| 220 | { | ||
| 221 | if (wl->set_power) | ||
| 222 | wl->set_power(enable); | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | static const struct wl1251_if_operations wl1251_spi_ops = { | ||
| 228 | .read = wl1251_spi_read, | ||
| 229 | .write = wl1251_spi_write, | ||
| 230 | .reset = wl1251_spi_reset_wake, | ||
| 231 | .enable_irq = wl1251_spi_enable_irq, | ||
| 232 | .disable_irq = wl1251_spi_disable_irq, | ||
| 233 | .power = wl1251_spi_set_power, | ||
| 234 | }; | ||
| 235 | |||
| 236 | static int __devinit wl1251_spi_probe(struct spi_device *spi) | ||
| 237 | { | ||
| 238 | struct wl12xx_platform_data *pdata; | ||
| 239 | struct ieee80211_hw *hw; | ||
| 240 | struct wl1251 *wl; | ||
| 241 | int ret; | ||
| 242 | |||
| 243 | pdata = spi->dev.platform_data; | ||
| 244 | if (!pdata) { | ||
| 245 | wl1251_error("no platform data"); | ||
| 246 | return -ENODEV; | ||
| 247 | } | ||
| 248 | |||
| 249 | hw = wl1251_alloc_hw(); | ||
| 250 | if (IS_ERR(hw)) | ||
| 251 | return PTR_ERR(hw); | ||
| 252 | |||
| 253 | wl = hw->priv; | ||
| 254 | |||
| 255 | SET_IEEE80211_DEV(hw, &spi->dev); | ||
| 256 | dev_set_drvdata(&spi->dev, wl); | ||
| 257 | wl->if_priv = spi; | ||
| 258 | wl->if_ops = &wl1251_spi_ops; | ||
| 259 | |||
| 260 | /* This is the only SPI value that we need to set here, the rest | ||
| 261 | * comes from the board-peripherals file */ | ||
| 262 | spi->bits_per_word = 32; | ||
| 263 | |||
| 264 | ret = spi_setup(spi); | ||
| 265 | if (ret < 0) { | ||
| 266 | wl1251_error("spi_setup failed"); | ||
| 267 | goto out_free; | ||
| 268 | } | ||
| 269 | |||
| 270 | wl->set_power = pdata->set_power; | ||
| 271 | if (!wl->set_power) { | ||
| 272 | wl1251_error("set power function missing in platform data"); | ||
| 273 | return -ENODEV; | ||
| 274 | } | ||
| 275 | |||
| 276 | wl->irq = spi->irq; | ||
| 277 | if (wl->irq < 0) { | ||
| 278 | wl1251_error("irq missing in platform data"); | ||
| 279 | return -ENODEV; | ||
| 280 | } | ||
| 281 | |||
| 282 | wl->use_eeprom = pdata->use_eeprom; | ||
| 283 | |||
| 284 | ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); | ||
| 285 | if (ret < 0) { | ||
| 286 | wl1251_error("request_irq() failed: %d", ret); | ||
| 287 | goto out_free; | ||
| 288 | } | ||
| 289 | |||
| 290 | irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); | ||
| 291 | |||
| 292 | disable_irq(wl->irq); | ||
| 293 | |||
| 294 | ret = wl1251_init_ieee80211(wl); | ||
| 295 | if (ret) | ||
| 296 | goto out_irq; | ||
| 297 | |||
| 298 | return 0; | ||
| 299 | |||
| 300 | out_irq: | ||
| 301 | free_irq(wl->irq, wl); | ||
| 302 | |||
| 303 | out_free: | ||
| 304 | ieee80211_free_hw(hw); | ||
| 305 | |||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | |||
| 309 | static int __devexit wl1251_spi_remove(struct spi_device *spi) | ||
| 310 | { | ||
| 311 | struct wl1251 *wl = dev_get_drvdata(&spi->dev); | ||
| 312 | |||
| 313 | free_irq(wl->irq, wl); | ||
| 314 | wl1251_free_hw(wl); | ||
| 315 | |||
| 316 | return 0; | ||
| 317 | } | ||
| 318 | |||
| 319 | static struct spi_driver wl1251_spi_driver = { | ||
| 320 | .driver = { | ||
| 321 | .name = DRIVER_NAME, | ||
| 322 | .bus = &spi_bus_type, | ||
| 323 | .owner = THIS_MODULE, | ||
| 324 | }, | ||
| 325 | |||
| 326 | .probe = wl1251_spi_probe, | ||
| 327 | .remove = __devexit_p(wl1251_spi_remove), | ||
| 328 | }; | ||
| 329 | |||
| 330 | static int __init wl1251_spi_init(void) | ||
| 331 | { | ||
| 332 | int ret; | ||
| 333 | |||
| 334 | ret = spi_register_driver(&wl1251_spi_driver); | ||
| 335 | if (ret < 0) { | ||
| 336 | wl1251_error("failed to register spi driver: %d", ret); | ||
| 337 | goto out; | ||
| 338 | } | ||
| 339 | |||
| 340 | out: | ||
| 341 | return ret; | ||
| 342 | } | ||
| 343 | |||
| 344 | static void __exit wl1251_spi_exit(void) | ||
| 345 | { | ||
| 346 | spi_unregister_driver(&wl1251_spi_driver); | ||
| 347 | |||
| 348 | wl1251_notice("unloaded"); | ||
| 349 | } | ||
| 350 | |||
| 351 | module_init(wl1251_spi_init); | ||
| 352 | module_exit(wl1251_spi_exit); | ||
| 353 | |||
| 354 | MODULE_LICENSE("GPL"); | ||
| 355 | MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); | ||
| 356 | MODULE_ALIAS("spi:wl1251"); | ||
diff --git a/drivers/net/wireless/wl1251/spi.h b/drivers/net/wireless/wl1251/spi.h new file mode 100644 index 00000000000..16d506955cc --- /dev/null +++ b/drivers/net/wireless/wl1251/spi.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __WL1251_SPI_H__ | ||
| 24 | #define __WL1251_SPI_H__ | ||
| 25 | |||
| 26 | #include "cmd.h" | ||
| 27 | #include "acx.h" | ||
| 28 | #include "reg.h" | ||
| 29 | |||
| 30 | #define WSPI_CMD_READ 0x40000000 | ||
| 31 | #define WSPI_CMD_WRITE 0x00000000 | ||
| 32 | #define WSPI_CMD_FIXED 0x20000000 | ||
| 33 | #define WSPI_CMD_BYTE_LENGTH 0x1FFE0000 | ||
| 34 | #define WSPI_CMD_BYTE_LENGTH_OFFSET 17 | ||
| 35 | #define WSPI_CMD_BYTE_ADDR 0x0001FFFF | ||
| 36 | |||
| 37 | #define WSPI_INIT_CMD_CRC_LEN 5 | ||
| 38 | |||
| 39 | #define WSPI_INIT_CMD_START 0x00 | ||
| 40 | #define WSPI_INIT_CMD_TX 0x40 | ||
| 41 | /* the extra bypass bit is sampled by the TNET as '1' */ | ||
| 42 | #define WSPI_INIT_CMD_BYPASS_BIT 0x80 | ||
| 43 | #define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07 | ||
| 44 | #define WSPI_INIT_CMD_EN_FIXEDBUSY 0x80 | ||
| 45 | #define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00 | ||
| 46 | #define WSPI_INIT_CMD_IOD 0x40 | ||
| 47 | #define WSPI_INIT_CMD_IP 0x20 | ||
| 48 | #define WSPI_INIT_CMD_CS 0x10 | ||
| 49 | #define WSPI_INIT_CMD_WS 0x08 | ||
| 50 | #define WSPI_INIT_CMD_WSPI 0x01 | ||
| 51 | #define WSPI_INIT_CMD_END 0x01 | ||
| 52 | |||
| 53 | #define WSPI_INIT_CMD_LEN 8 | ||
| 54 | |||
| 55 | #define HW_ACCESS_WSPI_FIXED_BUSY_LEN \ | ||
| 56 | ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32)) | ||
| 57 | #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 | ||
| 58 | |||
| 59 | #endif /* __WL1251_SPI_H__ */ | ||
diff --git a/drivers/net/wireless/wl1251/tx.c b/drivers/net/wireless/wl1251/tx.c new file mode 100644 index 00000000000..28121c590a2 --- /dev/null +++ b/drivers/net/wireless/wl1251/tx.c | |||
| @@ -0,0 +1,560 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | |||
| 26 | #include "wl1251.h" | ||
| 27 | #include "reg.h" | ||
| 28 | #include "tx.h" | ||
| 29 | #include "ps.h" | ||
| 30 | #include "io.h" | ||
| 31 | |||
| 32 | static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) | ||
| 33 | { | ||
| 34 | int used, data_in_count; | ||
| 35 | |||
| 36 | data_in_count = wl->data_in_count; | ||
| 37 | |||
| 38 | if (data_in_count < data_out_count) | ||
| 39 | /* data_in_count has wrapped */ | ||
| 40 | data_in_count += TX_STATUS_DATA_OUT_COUNT_MASK + 1; | ||
| 41 | |||
| 42 | used = data_in_count - data_out_count; | ||
| 43 | |||
| 44 | WARN_ON(used < 0); | ||
| 45 | WARN_ON(used > DP_TX_PACKET_RING_CHUNK_NUM); | ||
| 46 | |||
| 47 | if (used >= DP_TX_PACKET_RING_CHUNK_NUM) | ||
| 48 | return true; | ||
| 49 | else | ||
| 50 | return false; | ||
| 51 | } | ||
| 52 | |||
| 53 | static int wl1251_tx_path_status(struct wl1251 *wl) | ||
| 54 | { | ||
| 55 | u32 status, addr, data_out_count; | ||
| 56 | bool busy; | ||
| 57 | |||
| 58 | addr = wl->data_path->tx_control_addr; | ||
| 59 | status = wl1251_mem_read32(wl, addr); | ||
| 60 | data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK; | ||
| 61 | busy = wl1251_tx_double_buffer_busy(wl, data_out_count); | ||
| 62 | |||
| 63 | if (busy) | ||
| 64 | return -EBUSY; | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb) | ||
| 70 | { | ||
| 71 | int i; | ||
| 72 | |||
| 73 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
| 74 | if (wl->tx_frames[i] == NULL) { | ||
| 75 | wl->tx_frames[i] = skb; | ||
| 76 | return i; | ||
| 77 | } | ||
| 78 | |||
| 79 | return -EBUSY; | ||
| 80 | } | ||
| 81 | |||
| 82 | static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr, | ||
| 83 | struct ieee80211_tx_info *control, u16 fc) | ||
| 84 | { | ||
| 85 | *(u16 *)&tx_hdr->control = 0; | ||
| 86 | |||
| 87 | tx_hdr->control.rate_policy = 0; | ||
| 88 | |||
| 89 | /* 802.11 packets */ | ||
| 90 | tx_hdr->control.packet_type = 0; | ||
| 91 | |||
| 92 | if (control->flags & IEEE80211_TX_CTL_NO_ACK) | ||
| 93 | tx_hdr->control.ack_policy = 1; | ||
| 94 | |||
| 95 | tx_hdr->control.tx_complete = 1; | ||
| 96 | |||
| 97 | if ((fc & IEEE80211_FTYPE_DATA) && | ||
| 98 | ((fc & IEEE80211_STYPE_QOS_DATA) || | ||
| 99 | (fc & IEEE80211_STYPE_QOS_NULLFUNC))) | ||
| 100 | tx_hdr->control.qos = 1; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* RSN + MIC = 8 + 8 = 16 bytes (worst case - AES). */ | ||
| 104 | #define MAX_MSDU_SECURITY_LENGTH 16 | ||
| 105 | #define MAX_MPDU_SECURITY_LENGTH 16 | ||
| 106 | #define WLAN_QOS_HDR_LEN 26 | ||
| 107 | #define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \ | ||
| 108 | WLAN_QOS_HDR_LEN) | ||
| 109 | #define HW_BLOCK_SIZE 252 | ||
| 110 | static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr) | ||
| 111 | { | ||
| 112 | u16 payload_len, frag_threshold, mem_blocks; | ||
| 113 | u16 num_mpdus, mem_blocks_per_frag; | ||
| 114 | |||
| 115 | frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | ||
| 116 | tx_hdr->frag_threshold = cpu_to_le16(frag_threshold); | ||
| 117 | |||
| 118 | payload_len = le16_to_cpu(tx_hdr->length) + MAX_MSDU_SECURITY_LENGTH; | ||
| 119 | |||
| 120 | if (payload_len > frag_threshold) { | ||
| 121 | mem_blocks_per_frag = | ||
| 122 | ((frag_threshold + MAX_MPDU_HEADER_AND_SECURITY) / | ||
| 123 | HW_BLOCK_SIZE) + 1; | ||
| 124 | num_mpdus = payload_len / frag_threshold; | ||
| 125 | mem_blocks = num_mpdus * mem_blocks_per_frag; | ||
| 126 | payload_len -= num_mpdus * frag_threshold; | ||
| 127 | num_mpdus++; | ||
| 128 | |||
| 129 | } else { | ||
| 130 | mem_blocks_per_frag = 0; | ||
| 131 | mem_blocks = 0; | ||
| 132 | num_mpdus = 1; | ||
| 133 | } | ||
| 134 | |||
| 135 | mem_blocks += (payload_len / HW_BLOCK_SIZE) + 1; | ||
| 136 | |||
| 137 | if (num_mpdus > 1) | ||
| 138 | mem_blocks += min(num_mpdus, mem_blocks_per_frag); | ||
| 139 | |||
| 140 | tx_hdr->num_mem_blocks = mem_blocks; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, | ||
| 144 | struct ieee80211_tx_info *control) | ||
| 145 | { | ||
| 146 | struct tx_double_buffer_desc *tx_hdr; | ||
| 147 | struct ieee80211_rate *rate; | ||
| 148 | int id; | ||
| 149 | u16 fc; | ||
| 150 | |||
| 151 | if (!skb) | ||
| 152 | return -EINVAL; | ||
| 153 | |||
| 154 | id = wl1251_tx_id(wl, skb); | ||
| 155 | if (id < 0) | ||
| 156 | return id; | ||
| 157 | |||
| 158 | fc = *(u16 *)skb->data; | ||
| 159 | tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, | ||
| 160 | sizeof(*tx_hdr)); | ||
| 161 | |||
| 162 | tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); | ||
| 163 | rate = ieee80211_get_tx_rate(wl->hw, control); | ||
| 164 | tx_hdr->rate = cpu_to_le16(rate->hw_value); | ||
| 165 | tx_hdr->expiry_time = cpu_to_le32(1 << 16); | ||
| 166 | tx_hdr->id = id; | ||
| 167 | |||
| 168 | tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb)); | ||
| 169 | |||
| 170 | wl1251_tx_control(tx_hdr, control, fc); | ||
| 171 | wl1251_tx_frag_block_num(tx_hdr); | ||
| 172 | |||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | |||
| 176 | /* We copy the packet to the target */ | ||
| 177 | static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb, | ||
| 178 | struct ieee80211_tx_info *control) | ||
| 179 | { | ||
| 180 | struct tx_double_buffer_desc *tx_hdr; | ||
| 181 | int len; | ||
| 182 | u32 addr; | ||
| 183 | |||
| 184 | if (!skb) | ||
| 185 | return -EINVAL; | ||
| 186 | |||
| 187 | tx_hdr = (struct tx_double_buffer_desc *) skb->data; | ||
| 188 | |||
| 189 | if (control->control.hw_key && | ||
| 190 | control->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { | ||
| 191 | int hdrlen; | ||
| 192 | __le16 fc; | ||
| 193 | u16 length; | ||
| 194 | u8 *pos; | ||
| 195 | |||
| 196 | fc = *(__le16 *)(skb->data + sizeof(*tx_hdr)); | ||
| 197 | length = le16_to_cpu(tx_hdr->length) + WL1251_TKIP_IV_SPACE; | ||
| 198 | tx_hdr->length = cpu_to_le16(length); | ||
| 199 | |||
| 200 | hdrlen = ieee80211_hdrlen(fc); | ||
| 201 | |||
| 202 | pos = skb_push(skb, WL1251_TKIP_IV_SPACE); | ||
| 203 | memmove(pos, pos + WL1251_TKIP_IV_SPACE, | ||
| 204 | sizeof(*tx_hdr) + hdrlen); | ||
| 205 | } | ||
| 206 | |||
| 207 | /* Revisit. This is a workaround for getting non-aligned packets. | ||
| 208 | This happens at least with EAPOL packets from the user space. | ||
| 209 | Our DMA requires packets to be aligned on a 4-byte boundary. | ||
| 210 | */ | ||
| 211 | if (unlikely((long)skb->data & 0x03)) { | ||
| 212 | int offset = (4 - (long)skb->data) & 0x03; | ||
| 213 | wl1251_debug(DEBUG_TX, "skb offset %d", offset); | ||
| 214 | |||
| 215 | /* check whether the current skb can be used */ | ||
| 216 | if (skb_cloned(skb) || (skb_tailroom(skb) < offset)) { | ||
| 217 | struct sk_buff *newskb = skb_copy_expand(skb, 0, 3, | ||
| 218 | GFP_KERNEL); | ||
| 219 | |||
| 220 | if (unlikely(newskb == NULL)) { | ||
| 221 | wl1251_error("Can't allocate skb!"); | ||
| 222 | return -EINVAL; | ||
| 223 | } | ||
| 224 | |||
| 225 | tx_hdr = (struct tx_double_buffer_desc *) newskb->data; | ||
| 226 | |||
| 227 | dev_kfree_skb_any(skb); | ||
| 228 | wl->tx_frames[tx_hdr->id] = skb = newskb; | ||
| 229 | |||
| 230 | offset = (4 - (long)skb->data) & 0x03; | ||
| 231 | wl1251_debug(DEBUG_TX, "new skb offset %d", offset); | ||
| 232 | } | ||
| 233 | |||
| 234 | /* align the buffer on a 4-byte boundary */ | ||
| 235 | if (offset) { | ||
| 236 | unsigned char *src = skb->data; | ||
| 237 | skb_reserve(skb, offset); | ||
| 238 | memmove(skb->data, src, skb->len); | ||
| 239 | tx_hdr = (struct tx_double_buffer_desc *) skb->data; | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | /* Our skb->data at this point includes the HW header */ | ||
| 244 | len = WL1251_TX_ALIGN(skb->len); | ||
| 245 | |||
| 246 | if (wl->data_in_count & 0x1) | ||
| 247 | addr = wl->data_path->tx_packet_ring_addr + | ||
| 248 | wl->data_path->tx_packet_ring_chunk_size; | ||
| 249 | else | ||
| 250 | addr = wl->data_path->tx_packet_ring_addr; | ||
| 251 | |||
| 252 | wl1251_mem_write(wl, addr, skb->data, len); | ||
| 253 | |||
| 254 | wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x " | ||
| 255 | "queue %d", tx_hdr->id, skb, tx_hdr->length, | ||
| 256 | tx_hdr->rate, tx_hdr->xmit_queue); | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | static void wl1251_tx_trigger(struct wl1251 *wl) | ||
| 262 | { | ||
| 263 | u32 data, addr; | ||
| 264 | |||
| 265 | if (wl->data_in_count & 0x1) { | ||
| 266 | addr = ACX_REG_INTERRUPT_TRIG_H; | ||
| 267 | data = INTR_TRIG_TX_PROC1; | ||
| 268 | } else { | ||
| 269 | addr = ACX_REG_INTERRUPT_TRIG; | ||
| 270 | data = INTR_TRIG_TX_PROC0; | ||
| 271 | } | ||
| 272 | |||
| 273 | wl1251_reg_write32(wl, addr, data); | ||
| 274 | |||
| 275 | /* Bumping data in */ | ||
| 276 | wl->data_in_count = (wl->data_in_count + 1) & | ||
| 277 | TX_STATUS_DATA_OUT_COUNT_MASK; | ||
| 278 | } | ||
| 279 | |||
| 280 | /* caller must hold wl->mutex */ | ||
| 281 | static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) | ||
| 282 | { | ||
| 283 | struct ieee80211_tx_info *info; | ||
| 284 | int ret = 0; | ||
| 285 | u8 idx; | ||
| 286 | |||
| 287 | info = IEEE80211_SKB_CB(skb); | ||
| 288 | |||
| 289 | if (info->control.hw_key) { | ||
| 290 | idx = info->control.hw_key->hw_key_idx; | ||
| 291 | if (unlikely(wl->default_key != idx)) { | ||
| 292 | ret = wl1251_acx_default_key(wl, idx); | ||
| 293 | if (ret < 0) | ||
| 294 | return ret; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | ret = wl1251_tx_path_status(wl); | ||
| 299 | if (ret < 0) | ||
| 300 | return ret; | ||
| 301 | |||
| 302 | ret = wl1251_tx_fill_hdr(wl, skb, info); | ||
| 303 | if (ret < 0) | ||
| 304 | return ret; | ||
| 305 | |||
| 306 | ret = wl1251_tx_send_packet(wl, skb, info); | ||
| 307 | if (ret < 0) | ||
| 308 | return ret; | ||
| 309 | |||
| 310 | wl1251_tx_trigger(wl); | ||
| 311 | |||
| 312 | return ret; | ||
| 313 | } | ||
| 314 | |||
| 315 | void wl1251_tx_work(struct work_struct *work) | ||
| 316 | { | ||
| 317 | struct wl1251 *wl = container_of(work, struct wl1251, tx_work); | ||
| 318 | struct sk_buff *skb; | ||
| 319 | bool woken_up = false; | ||
| 320 | int ret; | ||
| 321 | |||
| 322 | mutex_lock(&wl->mutex); | ||
| 323 | |||
| 324 | if (unlikely(wl->state == WL1251_STATE_OFF)) | ||
| 325 | goto out; | ||
| 326 | |||
| 327 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
| 328 | if (!woken_up) { | ||
| 329 | ret = wl1251_ps_elp_wakeup(wl); | ||
| 330 | if (ret < 0) | ||
| 331 | goto out; | ||
| 332 | woken_up = true; | ||
| 333 | } | ||
| 334 | |||
| 335 | ret = wl1251_tx_frame(wl, skb); | ||
| 336 | if (ret == -EBUSY) { | ||
| 337 | skb_queue_head(&wl->tx_queue, skb); | ||
| 338 | goto out; | ||
| 339 | } else if (ret < 0) { | ||
| 340 | dev_kfree_skb(skb); | ||
| 341 | goto out; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | out: | ||
| 346 | if (woken_up) | ||
| 347 | wl1251_ps_elp_sleep(wl); | ||
| 348 | |||
| 349 | mutex_unlock(&wl->mutex); | ||
| 350 | } | ||
| 351 | |||
| 352 | static const char *wl1251_tx_parse_status(u8 status) | ||
| 353 | { | ||
| 354 | /* 8 bit status field, one character per bit plus null */ | ||
| 355 | static char buf[9]; | ||
| 356 | int i = 0; | ||
| 357 | |||
| 358 | memset(buf, 0, sizeof(buf)); | ||
| 359 | |||
| 360 | if (status & TX_DMA_ERROR) | ||
| 361 | buf[i++] = 'm'; | ||
| 362 | if (status & TX_DISABLED) | ||
| 363 | buf[i++] = 'd'; | ||
| 364 | if (status & TX_RETRY_EXCEEDED) | ||
| 365 | buf[i++] = 'r'; | ||
| 366 | if (status & TX_TIMEOUT) | ||
| 367 | buf[i++] = 't'; | ||
| 368 | if (status & TX_KEY_NOT_FOUND) | ||
| 369 | buf[i++] = 'k'; | ||
| 370 | if (status & TX_ENCRYPT_FAIL) | ||
| 371 | buf[i++] = 'e'; | ||
| 372 | if (status & TX_UNAVAILABLE_PRIORITY) | ||
| 373 | buf[i++] = 'p'; | ||
| 374 | |||
| 375 | /* bit 0 is unused apparently */ | ||
| 376 | |||
| 377 | return buf; | ||
| 378 | } | ||
| 379 | |||
| 380 | static void wl1251_tx_packet_cb(struct wl1251 *wl, | ||
| 381 | struct tx_result *result) | ||
| 382 | { | ||
| 383 | struct ieee80211_tx_info *info; | ||
| 384 | struct sk_buff *skb; | ||
| 385 | int hdrlen; | ||
| 386 | u8 *frame; | ||
| 387 | |||
| 388 | skb = wl->tx_frames[result->id]; | ||
| 389 | if (skb == NULL) { | ||
| 390 | wl1251_error("SKB for packet %d is NULL", result->id); | ||
| 391 | return; | ||
| 392 | } | ||
| 393 | |||
| 394 | info = IEEE80211_SKB_CB(skb); | ||
| 395 | |||
| 396 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && | ||
| 397 | (result->status == TX_SUCCESS)) | ||
| 398 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
| 399 | |||
| 400 | info->status.rates[0].count = result->ack_failures + 1; | ||
| 401 | wl->stats.retry_count += result->ack_failures; | ||
| 402 | |||
| 403 | /* | ||
| 404 | * We have to remove our private TX header before pushing | ||
| 405 | * the skb back to mac80211. | ||
| 406 | */ | ||
| 407 | frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc)); | ||
| 408 | if (info->control.hw_key && | ||
| 409 | info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { | ||
| 410 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
| 411 | memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen); | ||
| 412 | skb_pull(skb, WL1251_TKIP_IV_SPACE); | ||
| 413 | } | ||
| 414 | |||
| 415 | wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" | ||
| 416 | " status 0x%x (%s)", | ||
| 417 | result->id, skb, result->ack_failures, result->rate, | ||
| 418 | result->status, wl1251_tx_parse_status(result->status)); | ||
| 419 | |||
| 420 | |||
| 421 | ieee80211_tx_status(wl->hw, skb); | ||
| 422 | |||
| 423 | wl->tx_frames[result->id] = NULL; | ||
| 424 | } | ||
| 425 | |||
| 426 | /* Called upon reception of a TX complete interrupt */ | ||
| 427 | void wl1251_tx_complete(struct wl1251 *wl) | ||
| 428 | { | ||
| 429 | int i, result_index, num_complete = 0, queue_len; | ||
| 430 | struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr; | ||
| 431 | unsigned long flags; | ||
| 432 | |||
| 433 | if (unlikely(wl->state != WL1251_STATE_ON)) | ||
| 434 | return; | ||
| 435 | |||
| 436 | /* First we read the result */ | ||
| 437 | wl1251_mem_read(wl, wl->data_path->tx_complete_addr, | ||
| 438 | result, sizeof(result)); | ||
| 439 | |||
| 440 | result_index = wl->next_tx_complete; | ||
| 441 | |||
| 442 | for (i = 0; i < ARRAY_SIZE(result); i++) { | ||
| 443 | result_ptr = &result[result_index]; | ||
| 444 | |||
| 445 | if (result_ptr->done_1 == 1 && | ||
| 446 | result_ptr->done_2 == 1) { | ||
| 447 | wl1251_tx_packet_cb(wl, result_ptr); | ||
| 448 | |||
| 449 | result_ptr->done_1 = 0; | ||
| 450 | result_ptr->done_2 = 0; | ||
| 451 | |||
| 452 | result_index = (result_index + 1) & | ||
| 453 | (FW_TX_CMPLT_BLOCK_SIZE - 1); | ||
| 454 | num_complete++; | ||
| 455 | } else { | ||
| 456 | break; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 | queue_len = skb_queue_len(&wl->tx_queue); | ||
| 461 | |||
| 462 | if ((num_complete > 0) && (queue_len > 0)) { | ||
| 463 | /* firmware buffer has space, reschedule tx_work */ | ||
| 464 | wl1251_debug(DEBUG_TX, "tx_complete: reschedule tx_work"); | ||
| 465 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
| 466 | } | ||
| 467 | |||
| 468 | if (wl->tx_queue_stopped && | ||
| 469 | queue_len <= WL1251_TX_QUEUE_LOW_WATERMARK) { | ||
| 470 | /* tx_queue has space, restart queues */ | ||
| 471 | wl1251_debug(DEBUG_TX, "tx_complete: waking queues"); | ||
| 472 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
| 473 | ieee80211_wake_queues(wl->hw); | ||
| 474 | wl->tx_queue_stopped = false; | ||
| 475 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
| 476 | } | ||
| 477 | |||
| 478 | /* Every completed frame needs to be acknowledged */ | ||
| 479 | if (num_complete) { | ||
| 480 | /* | ||
| 481 | * If we've wrapped, we have to clear | ||
| 482 | * the results in 2 steps. | ||
| 483 | */ | ||
| 484 | if (result_index > wl->next_tx_complete) { | ||
| 485 | /* Only 1 write is needed */ | ||
| 486 | wl1251_mem_write(wl, | ||
| 487 | wl->data_path->tx_complete_addr + | ||
| 488 | (wl->next_tx_complete * | ||
| 489 | sizeof(struct tx_result)), | ||
| 490 | &result[wl->next_tx_complete], | ||
| 491 | num_complete * | ||
| 492 | sizeof(struct tx_result)); | ||
| 493 | |||
| 494 | |||
| 495 | } else if (result_index < wl->next_tx_complete) { | ||
| 496 | /* 2 writes are needed */ | ||
| 497 | wl1251_mem_write(wl, | ||
| 498 | wl->data_path->tx_complete_addr + | ||
| 499 | (wl->next_tx_complete * | ||
| 500 | sizeof(struct tx_result)), | ||
| 501 | &result[wl->next_tx_complete], | ||
| 502 | (FW_TX_CMPLT_BLOCK_SIZE - | ||
| 503 | wl->next_tx_complete) * | ||
| 504 | sizeof(struct tx_result)); | ||
| 505 | |||
| 506 | wl1251_mem_write(wl, | ||
| 507 | wl->data_path->tx_complete_addr, | ||
| 508 | result, | ||
| 509 | (num_complete - | ||
| 510 | FW_TX_CMPLT_BLOCK_SIZE + | ||
| 511 | wl->next_tx_complete) * | ||
| 512 | sizeof(struct tx_result)); | ||
| 513 | |||
| 514 | } else { | ||
| 515 | /* We have to write the whole array */ | ||
| 516 | wl1251_mem_write(wl, | ||
| 517 | wl->data_path->tx_complete_addr, | ||
| 518 | result, | ||
| 519 | FW_TX_CMPLT_BLOCK_SIZE * | ||
| 520 | sizeof(struct tx_result)); | ||
| 521 | } | ||
| 522 | |||
| 523 | } | ||
| 524 | |||
| 525 | wl->next_tx_complete = result_index; | ||
| 526 | } | ||
| 527 | |||
| 528 | /* caller must hold wl->mutex */ | ||
| 529 | void wl1251_tx_flush(struct wl1251 *wl) | ||
| 530 | { | ||
| 531 | int i; | ||
| 532 | struct sk_buff *skb; | ||
| 533 | struct ieee80211_tx_info *info; | ||
| 534 | |||
| 535 | /* TX failure */ | ||
| 536 | /* control->flags = 0; FIXME */ | ||
| 537 | |||
| 538 | while ((skb = skb_dequeue(&wl->tx_queue))) { | ||
| 539 | info = IEEE80211_SKB_CB(skb); | ||
| 540 | |||
| 541 | wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb); | ||
| 542 | |||
| 543 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
| 544 | continue; | ||
| 545 | |||
| 546 | ieee80211_tx_status(wl->hw, skb); | ||
| 547 | } | ||
| 548 | |||
| 549 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
| 550 | if (wl->tx_frames[i] != NULL) { | ||
| 551 | skb = wl->tx_frames[i]; | ||
| 552 | info = IEEE80211_SKB_CB(skb); | ||
| 553 | |||
| 554 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
| 555 | continue; | ||
| 556 | |||
| 557 | ieee80211_tx_status(wl->hw, skb); | ||
| 558 | wl->tx_frames[i] = NULL; | ||
| 559 | } | ||
| 560 | } | ||
diff --git a/drivers/net/wireless/wl1251/tx.h b/drivers/net/wireless/wl1251/tx.h new file mode 100644 index 00000000000..81338d39b43 --- /dev/null +++ b/drivers/net/wireless/wl1251/tx.h | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __WL1251_TX_H__ | ||
| 24 | #define __WL1251_TX_H__ | ||
| 25 | |||
| 26 | #include <linux/bitops.h> | ||
| 27 | #include "acx.h" | ||
| 28 | |||
| 29 | /* | ||
| 30 | * | ||
| 31 | * TX PATH | ||
| 32 | * | ||
| 33 | * The Tx path uses a double buffer and a tx_control structure, each located | ||
| 34 | * at a fixed address in the device's memory. On startup, the host retrieves | ||
| 35 | * the pointers to these addresses. A double buffer allows for continuous data | ||
| 36 | * flow towards the device. The host keeps track of which buffer is available | ||
| 37 | * and alternates between these two buffers on a per packet basis. | ||
| 38 | * | ||
| 39 | * The size of each of the two buffers is large enough to hold the longest | ||
| 40 | * 802.3 packet - maximum size Ethernet packet + header + descriptor. | ||
| 41 | * TX complete indication will be received a-synchronously in a TX done cyclic | ||
| 42 | * buffer which is composed of 16 tx_result descriptors structures and is used | ||
| 43 | * in a cyclic manner. | ||
| 44 | * | ||
| 45 | * The TX (HOST) procedure is as follows: | ||
| 46 | * 1. Read the Tx path status, that will give the data_out_count. | ||
| 47 | * 2. goto 1, if not possible. | ||
| 48 | * i.e. if data_in_count - data_out_count >= HwBuffer size (2 for double | ||
| 49 | * buffer). | ||
| 50 | * 3. Copy the packet (preceded by double_buffer_desc), if possible. | ||
| 51 | * i.e. if data_in_count - data_out_count < HwBuffer size (2 for double | ||
| 52 | * buffer). | ||
| 53 | * 4. increment data_in_count. | ||
| 54 | * 5. Inform the firmware by generating a firmware internal interrupt. | ||
| 55 | * 6. FW will increment data_out_count after it reads the buffer. | ||
| 56 | * | ||
| 57 | * The TX Complete procedure: | ||
| 58 | * 1. To get a TX complete indication the host enables the tx_complete flag in | ||
| 59 | * the TX descriptor Structure. | ||
| 60 | * 2. For each packet with a Tx Complete field set, the firmware adds the | ||
| 61 | * transmit results to the cyclic buffer (txDoneRing) and sets both done_1 | ||
| 62 | * and done_2 to 1 to indicate driver ownership. | ||
| 63 | * 3. The firmware sends a Tx Complete interrupt to the host to trigger the | ||
| 64 | * host to process the new data. Note: interrupt will be send per packet if | ||
| 65 | * TX complete indication was requested in tx_control or per crossing | ||
| 66 | * aggregation threshold. | ||
| 67 | * 4. After receiving the Tx Complete interrupt, the host reads the | ||
| 68 | * TxDescriptorDone information in a cyclic manner and clears both done_1 | ||
| 69 | * and done_2 fields. | ||
| 70 | * | ||
| 71 | */ | ||
| 72 | |||
| 73 | #define TX_COMPLETE_REQUIRED_BIT 0x80 | ||
| 74 | #define TX_STATUS_DATA_OUT_COUNT_MASK 0xf | ||
| 75 | |||
| 76 | #define WL1251_TX_ALIGN_TO 4 | ||
| 77 | #define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \ | ||
| 78 | ~(WL1251_TX_ALIGN_TO - 1)) | ||
| 79 | #define WL1251_TKIP_IV_SPACE 4 | ||
| 80 | |||
| 81 | struct tx_control { | ||
| 82 | /* Rate Policy (class) index */ | ||
| 83 | unsigned rate_policy:3; | ||
| 84 | |||
| 85 | /* When set, no ack policy is expected */ | ||
| 86 | unsigned ack_policy:1; | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Packet type: | ||
| 90 | * 0 -> 802.11 | ||
| 91 | * 1 -> 802.3 | ||
| 92 | * 2 -> IP | ||
| 93 | * 3 -> raw codec | ||
| 94 | */ | ||
| 95 | unsigned packet_type:2; | ||
| 96 | |||
| 97 | /* If set, this is a QoS-Null or QoS-Data frame */ | ||
| 98 | unsigned qos:1; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * If set, the target triggers the tx complete INT | ||
| 102 | * upon frame sending completion. | ||
| 103 | */ | ||
| 104 | unsigned tx_complete:1; | ||
| 105 | |||
| 106 | /* 2 bytes padding before packet header */ | ||
| 107 | unsigned xfer_pad:1; | ||
| 108 | |||
| 109 | unsigned reserved:7; | ||
| 110 | } __packed; | ||
| 111 | |||
| 112 | |||
| 113 | struct tx_double_buffer_desc { | ||
| 114 | /* Length of payload, including headers. */ | ||
| 115 | __le16 length; | ||
| 116 | |||
| 117 | /* | ||
| 118 | * A bit mask that specifies the initial rate to be used | ||
| 119 | * Possible values are: | ||
| 120 | * 0x0001 - 1Mbits | ||
| 121 | * 0x0002 - 2Mbits | ||
| 122 | * 0x0004 - 5.5Mbits | ||
| 123 | * 0x0008 - 6Mbits | ||
| 124 | * 0x0010 - 9Mbits | ||
| 125 | * 0x0020 - 11Mbits | ||
| 126 | * 0x0040 - 12Mbits | ||
| 127 | * 0x0080 - 18Mbits | ||
| 128 | * 0x0100 - 22Mbits | ||
| 129 | * 0x0200 - 24Mbits | ||
| 130 | * 0x0400 - 36Mbits | ||
| 131 | * 0x0800 - 48Mbits | ||
| 132 | * 0x1000 - 54Mbits | ||
| 133 | */ | ||
| 134 | __le16 rate; | ||
| 135 | |||
| 136 | /* Time in us that a packet can spend in the target */ | ||
| 137 | __le32 expiry_time; | ||
| 138 | |||
| 139 | /* index of the TX queue used for this packet */ | ||
| 140 | u8 xmit_queue; | ||
| 141 | |||
| 142 | /* Used to identify a packet */ | ||
| 143 | u8 id; | ||
| 144 | |||
| 145 | struct tx_control control; | ||
| 146 | |||
| 147 | /* | ||
| 148 | * The FW should cut the packet into fragments | ||
| 149 | * of this size. | ||
| 150 | */ | ||
| 151 | __le16 frag_threshold; | ||
| 152 | |||
| 153 | /* Numbers of HW queue blocks to be allocated */ | ||
| 154 | u8 num_mem_blocks; | ||
| 155 | |||
| 156 | u8 reserved; | ||
| 157 | } __packed; | ||
| 158 | |||
| 159 | enum { | ||
| 160 | TX_SUCCESS = 0, | ||
| 161 | TX_DMA_ERROR = BIT(7), | ||
| 162 | TX_DISABLED = BIT(6), | ||
| 163 | TX_RETRY_EXCEEDED = BIT(5), | ||
| 164 | TX_TIMEOUT = BIT(4), | ||
| 165 | TX_KEY_NOT_FOUND = BIT(3), | ||
| 166 | TX_ENCRYPT_FAIL = BIT(2), | ||
| 167 | TX_UNAVAILABLE_PRIORITY = BIT(1), | ||
| 168 | }; | ||
| 169 | |||
| 170 | struct tx_result { | ||
| 171 | /* | ||
| 172 | * Ownership synchronization between the host and | ||
| 173 | * the firmware. If done_1 and done_2 are cleared, | ||
| 174 | * owned by the FW (no info ready). | ||
| 175 | */ | ||
| 176 | u8 done_1; | ||
| 177 | |||
| 178 | /* same as double_buffer_desc->id */ | ||
| 179 | u8 id; | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Total air access duration consumed by this | ||
| 183 | * packet, including all retries and overheads. | ||
| 184 | */ | ||
| 185 | u16 medium_usage; | ||
| 186 | |||
| 187 | /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ | ||
| 188 | u32 medium_delay; | ||
| 189 | |||
| 190 | /* Time between host xfer and tx complete */ | ||
| 191 | u32 fw_hnadling_time; | ||
| 192 | |||
| 193 | /* The LS-byte of the last TKIP sequence number. */ | ||
| 194 | u8 lsb_seq_num; | ||
| 195 | |||
| 196 | /* Retry count */ | ||
| 197 | u8 ack_failures; | ||
| 198 | |||
| 199 | /* At which rate we got a ACK */ | ||
| 200 | u16 rate; | ||
| 201 | |||
| 202 | u16 reserved; | ||
| 203 | |||
| 204 | /* TX_* */ | ||
| 205 | u8 status; | ||
| 206 | |||
| 207 | /* See done_1 */ | ||
| 208 | u8 done_2; | ||
| 209 | } __packed; | ||
| 210 | |||
| 211 | static inline int wl1251_tx_get_queue(int queue) | ||
| 212 | { | ||
| 213 | switch (queue) { | ||
| 214 | case 0: | ||
| 215 | return QOS_AC_VO; | ||
| 216 | case 1: | ||
| 217 | return QOS_AC_VI; | ||
| 218 | case 2: | ||
| 219 | return QOS_AC_BE; | ||
| 220 | case 3: | ||
| 221 | return QOS_AC_BK; | ||
| 222 | default: | ||
| 223 | return QOS_AC_BE; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | void wl1251_tx_work(struct work_struct *work); | ||
| 228 | void wl1251_tx_complete(struct wl1251 *wl); | ||
| 229 | void wl1251_tx_flush(struct wl1251 *wl); | ||
| 230 | |||
| 231 | #endif | ||
diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h new file mode 100644 index 00000000000..a77f1bbbed0 --- /dev/null +++ b/drivers/net/wireless/wl1251/wl1251.h | |||
| @@ -0,0 +1,446 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of wl1251 | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2007 Texas Instruments Incorporated | ||
| 5 | * Copyright (C) 2008-2009 Nokia Corporation | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 19 | * 02110-1301 USA | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __WL1251_H__ | ||
| 24 | #define __WL1251_H__ | ||
| 25 | |||
| 26 | #include <linux/mutex.h> | ||
| 27 | #include <linux/list.h> | ||
| 28 | #include <linux/bitops.h> | ||
| 29 | #include <net/mac80211.h> | ||
| 30 | |||
| 31 | #define DRIVER_NAME "wl1251" | ||
| 32 | #define DRIVER_PREFIX DRIVER_NAME ": " | ||
| 33 | |||
| 34 | enum { | ||
| 35 | DEBUG_NONE = 0, | ||
| 36 | DEBUG_IRQ = BIT(0), | ||
| 37 | DEBUG_SPI = BIT(1), | ||
| 38 | DEBUG_BOOT = BIT(2), | ||
| 39 | DEBUG_MAILBOX = BIT(3), | ||
| 40 | DEBUG_NETLINK = BIT(4), | ||
| 41 | DEBUG_EVENT = BIT(5), | ||
| 42 | DEBUG_TX = BIT(6), | ||
| 43 | DEBUG_RX = BIT(7), | ||
| 44 | DEBUG_SCAN = BIT(8), | ||
| 45 | DEBUG_CRYPT = BIT(9), | ||
| 46 | DEBUG_PSM = BIT(10), | ||
| 47 | DEBUG_MAC80211 = BIT(11), | ||
| 48 | DEBUG_CMD = BIT(12), | ||
| 49 | DEBUG_ACX = BIT(13), | ||
| 50 | DEBUG_ALL = ~0, | ||
| 51 | }; | ||
| 52 | |||
| 53 | #define DEBUG_LEVEL (DEBUG_NONE) | ||
| 54 | |||
| 55 | #define DEBUG_DUMP_LIMIT 1024 | ||
| 56 | |||
| 57 | #define wl1251_error(fmt, arg...) \ | ||
| 58 | printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) | ||
| 59 | |||
| 60 | #define wl1251_warning(fmt, arg...) \ | ||
| 61 | printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) | ||
| 62 | |||
| 63 | #define wl1251_notice(fmt, arg...) \ | ||
| 64 | printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) | ||
| 65 | |||
| 66 | #define wl1251_info(fmt, arg...) \ | ||
| 67 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) | ||
| 68 | |||
| 69 | #define wl1251_debug(level, fmt, arg...) \ | ||
| 70 | do { \ | ||
| 71 | if (level & DEBUG_LEVEL) \ | ||
| 72 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ | ||
| 73 | } while (0) | ||
| 74 | |||
| 75 | #define wl1251_dump(level, prefix, buf, len) \ | ||
| 76 | do { \ | ||
| 77 | if (level & DEBUG_LEVEL) \ | ||
| 78 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
| 79 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
| 80 | buf, \ | ||
| 81 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
| 82 | 0); \ | ||
| 83 | } while (0) | ||
| 84 | |||
| 85 | #define wl1251_dump_ascii(level, prefix, buf, len) \ | ||
| 86 | do { \ | ||
| 87 | if (level & DEBUG_LEVEL) \ | ||
| 88 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | ||
| 89 | DUMP_PREFIX_OFFSET, 16, 1, \ | ||
| 90 | buf, \ | ||
| 91 | min_t(size_t, len, DEBUG_DUMP_LIMIT), \ | ||
| 92 | true); \ | ||
| 93 | } while (0) | ||
| 94 | |||
| 95 | #define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ | ||
| 96 | CFG_BSSID_FILTER_EN) | ||
| 97 | |||
| 98 | #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ | ||
| 99 | CFG_RX_MGMT_EN | \ | ||
| 100 | CFG_RX_DATA_EN | \ | ||
| 101 | CFG_RX_CTL_EN | \ | ||
| 102 | CFG_RX_BCN_EN | \ | ||
| 103 | CFG_RX_AUTH_EN | \ | ||
| 104 | CFG_RX_ASSOC_EN) | ||
| 105 | |||
| 106 | #define WL1251_BUSY_WORD_LEN 8 | ||
| 107 | |||
| 108 | struct boot_attr { | ||
| 109 | u32 radio_type; | ||
| 110 | u8 mac_clock; | ||
| 111 | u8 arm_clock; | ||
| 112 | int firmware_debug; | ||
| 113 | u32 minor; | ||
| 114 | u32 major; | ||
| 115 | u32 bugfix; | ||
| 116 | }; | ||
| 117 | |||
| 118 | enum wl1251_state { | ||
| 119 | WL1251_STATE_OFF, | ||
| 120 | WL1251_STATE_ON, | ||
| 121 | WL1251_STATE_PLT, | ||
| 122 | }; | ||
| 123 | |||
| 124 | enum wl1251_partition_type { | ||
| 125 | PART_DOWN, | ||
| 126 | PART_WORK, | ||
| 127 | PART_DRPW, | ||
| 128 | |||
| 129 | PART_TABLE_LEN | ||
| 130 | }; | ||
| 131 | |||
| 132 | enum wl1251_station_mode { | ||
| 133 | STATION_ACTIVE_MODE, | ||
| 134 | STATION_POWER_SAVE_MODE, | ||
| 135 | STATION_IDLE, | ||
| 136 | }; | ||
| 137 | |||
| 138 | struct wl1251_partition { | ||
| 139 | u32 size; | ||
| 140 | u32 start; | ||
| 141 | }; | ||
| 142 | |||
| 143 | struct wl1251_partition_set { | ||
| 144 | struct wl1251_partition mem; | ||
| 145 | struct wl1251_partition reg; | ||
| 146 | }; | ||
| 147 | |||
| 148 | struct wl1251; | ||
| 149 | |||
| 150 | struct wl1251_stats { | ||
| 151 | struct acx_statistics *fw_stats; | ||
| 152 | unsigned long fw_stats_update; | ||
| 153 | |||
| 154 | unsigned int retry_count; | ||
| 155 | unsigned int excessive_retries; | ||
| 156 | }; | ||
| 157 | |||
| 158 | struct wl1251_debugfs { | ||
| 159 | struct dentry *rootdir; | ||
| 160 | struct dentry *fw_statistics; | ||
| 161 | |||
| 162 | struct dentry *tx_internal_desc_overflow; | ||
| 163 | |||
| 164 | struct dentry *rx_out_of_mem; | ||
| 165 | struct dentry *rx_hdr_overflow; | ||
| 166 | struct dentry *rx_hw_stuck; | ||
| 167 | struct dentry *rx_dropped; | ||
| 168 | struct dentry *rx_fcs_err; | ||
| 169 | struct dentry *rx_xfr_hint_trig; | ||
| 170 | struct dentry *rx_path_reset; | ||
| 171 | struct dentry *rx_reset_counter; | ||
| 172 | |||
| 173 | struct dentry *dma_rx_requested; | ||
| 174 | struct dentry *dma_rx_errors; | ||
| 175 | struct dentry *dma_tx_requested; | ||
| 176 | struct dentry *dma_tx_errors; | ||
| 177 | |||
| 178 | struct dentry *isr_cmd_cmplt; | ||
| 179 | struct dentry *isr_fiqs; | ||
| 180 | struct dentry *isr_rx_headers; | ||
| 181 | struct dentry *isr_rx_mem_overflow; | ||
| 182 | struct dentry *isr_rx_rdys; | ||
| 183 | struct dentry *isr_irqs; | ||
| 184 | struct dentry *isr_tx_procs; | ||
| 185 | struct dentry *isr_decrypt_done; | ||
| 186 | struct dentry *isr_dma0_done; | ||
| 187 | struct dentry *isr_dma1_done; | ||
| 188 | struct dentry *isr_tx_exch_complete; | ||
| 189 | struct dentry *isr_commands; | ||
| 190 | struct dentry *isr_rx_procs; | ||
| 191 | struct dentry *isr_hw_pm_mode_changes; | ||
| 192 | struct dentry *isr_host_acknowledges; | ||
| 193 | struct dentry *isr_pci_pm; | ||
| 194 | struct dentry *isr_wakeups; | ||
| 195 | struct dentry *isr_low_rssi; | ||
| 196 | |||
| 197 | struct dentry *wep_addr_key_count; | ||
| 198 | struct dentry *wep_default_key_count; | ||
| 199 | /* skipping wep.reserved */ | ||
| 200 | struct dentry *wep_key_not_found; | ||
| 201 | struct dentry *wep_decrypt_fail; | ||
| 202 | struct dentry *wep_packets; | ||
| 203 | struct dentry *wep_interrupt; | ||
| 204 | |||
| 205 | struct dentry *pwr_ps_enter; | ||
| 206 | struct dentry *pwr_elp_enter; | ||
| 207 | struct dentry *pwr_missing_bcns; | ||
| 208 | struct dentry *pwr_wake_on_host; | ||
| 209 | struct dentry *pwr_wake_on_timer_exp; | ||
| 210 | struct dentry *pwr_tx_with_ps; | ||
| 211 | struct dentry *pwr_tx_without_ps; | ||
| 212 | struct dentry *pwr_rcvd_beacons; | ||
| 213 | struct dentry *pwr_power_save_off; | ||
| 214 | struct dentry *pwr_enable_ps; | ||
| 215 | struct dentry *pwr_disable_ps; | ||
| 216 | struct dentry *pwr_fix_tsf_ps; | ||
| 217 | /* skipping cont_miss_bcns_spread for now */ | ||
| 218 | struct dentry *pwr_rcvd_awake_beacons; | ||
| 219 | |||
| 220 | struct dentry *mic_rx_pkts; | ||
| 221 | struct dentry *mic_calc_failure; | ||
| 222 | |||
| 223 | struct dentry *aes_encrypt_fail; | ||
| 224 | struct dentry *aes_decrypt_fail; | ||
| 225 | struct dentry *aes_encrypt_packets; | ||
| 226 | struct dentry *aes_decrypt_packets; | ||
| 227 | struct dentry *aes_encrypt_interrupt; | ||
| 228 | struct dentry *aes_decrypt_interrupt; | ||
| 229 | |||
| 230 | struct dentry *event_heart_beat; | ||
| 231 | struct dentry *event_calibration; | ||
| 232 | struct dentry *event_rx_mismatch; | ||
| 233 | struct dentry *event_rx_mem_empty; | ||
| 234 | struct dentry *event_rx_pool; | ||
| 235 | struct dentry *event_oom_late; | ||
| 236 | struct dentry *event_phy_transmit_error; | ||
| 237 | struct dentry *event_tx_stuck; | ||
| 238 | |||
| 239 | struct dentry *ps_pspoll_timeouts; | ||
| 240 | struct dentry *ps_upsd_timeouts; | ||
| 241 | struct dentry *ps_upsd_max_sptime; | ||
| 242 | struct dentry *ps_upsd_max_apturn; | ||
| 243 | struct dentry *ps_pspoll_max_apturn; | ||
| 244 | struct dentry *ps_pspoll_utilization; | ||
| 245 | struct dentry *ps_upsd_utilization; | ||
| 246 | |||
| 247 | struct dentry *rxpipe_rx_prep_beacon_drop; | ||
| 248 | struct dentry *rxpipe_descr_host_int_trig_rx_data; | ||
| 249 | struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; | ||
| 250 | struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; | ||
| 251 | struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; | ||
| 252 | |||
| 253 | struct dentry *tx_queue_len; | ||
| 254 | struct dentry *tx_queue_status; | ||
| 255 | |||
| 256 | struct dentry *retry_count; | ||
| 257 | struct dentry *excessive_retries; | ||
| 258 | }; | ||
| 259 | |||
| 260 | struct wl1251_if_operations { | ||
| 261 | void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
| 262 | void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); | ||
| 263 | void (*read_elp)(struct wl1251 *wl, int addr, u32 *val); | ||
| 264 | void (*write_elp)(struct wl1251 *wl, int addr, u32 val); | ||
| 265 | int (*power)(struct wl1251 *wl, bool enable); | ||
| 266 | void (*reset)(struct wl1251 *wl); | ||
| 267 | void (*enable_irq)(struct wl1251 *wl); | ||
| 268 | void (*disable_irq)(struct wl1251 *wl); | ||
| 269 | }; | ||
| 270 | |||
| 271 | struct wl1251 { | ||
| 272 | struct ieee80211_hw *hw; | ||
| 273 | bool mac80211_registered; | ||
| 274 | |||
| 275 | void *if_priv; | ||
| 276 | const struct wl1251_if_operations *if_ops; | ||
| 277 | |||
| 278 | void (*set_power)(bool enable); | ||
| 279 | int irq; | ||
| 280 | bool use_eeprom; | ||
| 281 | |||
| 282 | spinlock_t wl_lock; | ||
| 283 | |||
| 284 | enum wl1251_state state; | ||
| 285 | struct mutex mutex; | ||
| 286 | |||
| 287 | int physical_mem_addr; | ||
| 288 | int physical_reg_addr; | ||
| 289 | int virtual_mem_addr; | ||
| 290 | int virtual_reg_addr; | ||
| 291 | |||
| 292 | int cmd_box_addr; | ||
| 293 | int event_box_addr; | ||
| 294 | struct boot_attr boot_attr; | ||
| 295 | |||
| 296 | u8 *fw; | ||
| 297 | size_t fw_len; | ||
| 298 | u8 *nvs; | ||
| 299 | size_t nvs_len; | ||
| 300 | |||
| 301 | u8 bssid[ETH_ALEN]; | ||
| 302 | u8 mac_addr[ETH_ALEN]; | ||
| 303 | u8 bss_type; | ||
| 304 | u8 listen_int; | ||
| 305 | int channel; | ||
| 306 | |||
| 307 | void *target_mem_map; | ||
| 308 | struct acx_data_path_params_resp *data_path; | ||
| 309 | |||
| 310 | /* Number of TX packets transferred to the FW, modulo 16 */ | ||
| 311 | u32 data_in_count; | ||
| 312 | |||
| 313 | /* Frames scheduled for transmission, not handled yet */ | ||
| 314 | struct sk_buff_head tx_queue; | ||
| 315 | bool tx_queue_stopped; | ||
| 316 | |||
| 317 | struct work_struct tx_work; | ||
| 318 | struct work_struct filter_work; | ||
| 319 | |||
| 320 | /* Pending TX frames */ | ||
| 321 | struct sk_buff *tx_frames[16]; | ||
| 322 | |||
| 323 | /* | ||
| 324 | * Index pointing to the next TX complete entry | ||
| 325 | * in the cyclic XT complete array we get from | ||
| 326 | * the FW. | ||
| 327 | */ | ||
| 328 | u32 next_tx_complete; | ||
| 329 | |||
| 330 | /* FW Rx counter */ | ||
| 331 | u32 rx_counter; | ||
| 332 | |||
| 333 | /* Rx frames handled */ | ||
| 334 | u32 rx_handled; | ||
| 335 | |||
| 336 | /* Current double buffer */ | ||
| 337 | u32 rx_current_buffer; | ||
| 338 | u32 rx_last_id; | ||
| 339 | |||
| 340 | /* The target interrupt mask */ | ||
| 341 | u32 intr_mask; | ||
| 342 | struct work_struct irq_work; | ||
| 343 | |||
| 344 | /* The mbox event mask */ | ||
| 345 | u32 event_mask; | ||
| 346 | |||
| 347 | /* Mailbox pointers */ | ||
| 348 | u32 mbox_ptr[2]; | ||
| 349 | |||
| 350 | /* Are we currently scanning */ | ||
| 351 | bool scanning; | ||
| 352 | |||
| 353 | /* Default key (for WEP) */ | ||
| 354 | u32 default_key; | ||
| 355 | |||
| 356 | unsigned int tx_mgmt_frm_rate; | ||
| 357 | unsigned int tx_mgmt_frm_mod; | ||
| 358 | |||
| 359 | unsigned int rx_config; | ||
| 360 | unsigned int rx_filter; | ||
| 361 | |||
| 362 | /* is firmware in elp mode */ | ||
| 363 | bool elp; | ||
| 364 | |||
| 365 | struct delayed_work elp_work; | ||
| 366 | |||
| 367 | enum wl1251_station_mode station_mode; | ||
| 368 | |||
| 369 | /* PSM mode requested */ | ||
| 370 | bool psm_requested; | ||
| 371 | |||
| 372 | u16 beacon_int; | ||
| 373 | u8 dtim_period; | ||
| 374 | |||
| 375 | /* in dBm */ | ||
| 376 | int power_level; | ||
| 377 | |||
| 378 | int rssi_thold; | ||
| 379 | |||
| 380 | struct wl1251_stats stats; | ||
| 381 | struct wl1251_debugfs debugfs; | ||
| 382 | |||
| 383 | u32 buffer_32; | ||
| 384 | u32 buffer_cmd; | ||
| 385 | u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; | ||
| 386 | struct wl1251_rx_descriptor *rx_descriptor; | ||
| 387 | |||
| 388 | struct ieee80211_vif *vif; | ||
| 389 | |||
| 390 | u32 chip_id; | ||
| 391 | char fw_ver[21]; | ||
| 392 | |||
| 393 | /* Most recently reported noise in dBm */ | ||
| 394 | s8 noise; | ||
| 395 | }; | ||
| 396 | |||
| 397 | int wl1251_plt_start(struct wl1251 *wl); | ||
| 398 | int wl1251_plt_stop(struct wl1251 *wl); | ||
| 399 | |||
| 400 | struct ieee80211_hw *wl1251_alloc_hw(void); | ||
| 401 | int wl1251_free_hw(struct wl1251 *wl); | ||
| 402 | int wl1251_init_ieee80211(struct wl1251 *wl); | ||
| 403 | void wl1251_enable_interrupts(struct wl1251 *wl); | ||
| 404 | void wl1251_disable_interrupts(struct wl1251 *wl); | ||
| 405 | |||
| 406 | #define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */ | ||
| 407 | #define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS | ||
| 408 | #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ | ||
| 409 | |||
| 410 | #define WL1251_DEFAULT_POWER_LEVEL 20 | ||
| 411 | |||
| 412 | #define WL1251_TX_QUEUE_LOW_WATERMARK 10 | ||
| 413 | #define WL1251_TX_QUEUE_HIGH_WATERMARK 25 | ||
| 414 | |||
| 415 | #define WL1251_DEFAULT_BEACON_INT 100 | ||
| 416 | #define WL1251_DEFAULT_DTIM_PERIOD 1 | ||
| 417 | |||
| 418 | #define WL1251_DEFAULT_CHANNEL 0 | ||
| 419 | |||
| 420 | #define WL1251_DEFAULT_BET_CONSECUTIVE 10 | ||
| 421 | |||
| 422 | #define CHIP_ID_1251_PG10 (0x7010101) | ||
| 423 | #define CHIP_ID_1251_PG11 (0x7020101) | ||
| 424 | #define CHIP_ID_1251_PG12 (0x7030101) | ||
| 425 | #define CHIP_ID_1271_PG10 (0x4030101) | ||
| 426 | #define CHIP_ID_1271_PG20 (0x4030111) | ||
| 427 | |||
| 428 | #define WL1251_FW_NAME "wl1251-fw.bin" | ||
| 429 | #define WL1251_NVS_NAME "wl1251-nvs.bin" | ||
| 430 | |||
| 431 | #define WL1251_POWER_ON_SLEEP 10 /* in milliseconds */ | ||
| 432 | |||
| 433 | #define WL1251_PART_DOWN_MEM_START 0x0 | ||
| 434 | #define WL1251_PART_DOWN_MEM_SIZE 0x16800 | ||
| 435 | #define WL1251_PART_DOWN_REG_START REGISTERS_BASE | ||
| 436 | #define WL1251_PART_DOWN_REG_SIZE REGISTERS_DOWN_SIZE | ||
| 437 | |||
| 438 | #define WL1251_PART_WORK_MEM_START 0x28000 | ||
| 439 | #define WL1251_PART_WORK_MEM_SIZE 0x14000 | ||
| 440 | #define WL1251_PART_WORK_REG_START REGISTERS_BASE | ||
| 441 | #define WL1251_PART_WORK_REG_SIZE REGISTERS_WORK_SIZE | ||
| 442 | |||
| 443 | #define WL1251_DEFAULT_LOW_RSSI_WEIGHT 10 | ||
| 444 | #define WL1251_DEFAULT_LOW_RSSI_DEPTH 10 | ||
| 445 | |||
| 446 | #endif | ||
diff --git a/drivers/net/wireless/wl1251/wl12xx_80211.h b/drivers/net/wireless/wl1251/wl12xx_80211.h new file mode 100644 index 00000000000..1417b1445c3 --- /dev/null +++ b/drivers/net/wireless/wl1251/wl12xx_80211.h | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | #ifndef __WL12XX_80211_H__ | ||
| 2 | #define __WL12XX_80211_H__ | ||
| 3 | |||
| 4 | #include <linux/if_ether.h> /* ETH_ALEN */ | ||
| 5 | |||
| 6 | /* RATES */ | ||
| 7 | #define IEEE80211_CCK_RATE_1MB 0x02 | ||
| 8 | #define IEEE80211_CCK_RATE_2MB 0x04 | ||
| 9 | #define IEEE80211_CCK_RATE_5MB 0x0B | ||
| 10 | #define IEEE80211_CCK_RATE_11MB 0x16 | ||
| 11 | #define IEEE80211_OFDM_RATE_6MB 0x0C | ||
| 12 | #define IEEE80211_OFDM_RATE_9MB 0x12 | ||
| 13 | #define IEEE80211_OFDM_RATE_12MB 0x18 | ||
| 14 | #define IEEE80211_OFDM_RATE_18MB 0x24 | ||
| 15 | #define IEEE80211_OFDM_RATE_24MB 0x30 | ||
| 16 | #define IEEE80211_OFDM_RATE_36MB 0x48 | ||
| 17 | #define IEEE80211_OFDM_RATE_48MB 0x60 | ||
| 18 | #define IEEE80211_OFDM_RATE_54MB 0x6C | ||
| 19 | #define IEEE80211_BASIC_RATE_MASK 0x80 | ||
| 20 | |||
| 21 | #define IEEE80211_CCK_RATE_1MB_MASK (1<<0) | ||
| 22 | #define IEEE80211_CCK_RATE_2MB_MASK (1<<1) | ||
| 23 | #define IEEE80211_CCK_RATE_5MB_MASK (1<<2) | ||
| 24 | #define IEEE80211_CCK_RATE_11MB_MASK (1<<3) | ||
| 25 | #define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) | ||
| 26 | #define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) | ||
| 27 | #define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) | ||
| 28 | #define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) | ||
| 29 | #define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) | ||
| 30 | #define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) | ||
| 31 | #define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) | ||
| 32 | #define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) | ||
| 33 | |||
| 34 | #define IEEE80211_CCK_RATES_MASK 0x0000000F | ||
| 35 | #define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ | ||
| 36 | IEEE80211_CCK_RATE_2MB_MASK) | ||
| 37 | #define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ | ||
| 38 | IEEE80211_CCK_RATE_5MB_MASK | \ | ||
| 39 | IEEE80211_CCK_RATE_11MB_MASK) | ||
| 40 | |||
| 41 | #define IEEE80211_OFDM_RATES_MASK 0x00000FF0 | ||
| 42 | #define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ | ||
| 43 | IEEE80211_OFDM_RATE_12MB_MASK | \ | ||
| 44 | IEEE80211_OFDM_RATE_24MB_MASK) | ||
| 45 | #define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ | ||
| 46 | IEEE80211_OFDM_RATE_9MB_MASK | \ | ||
| 47 | IEEE80211_OFDM_RATE_18MB_MASK | \ | ||
| 48 | IEEE80211_OFDM_RATE_36MB_MASK | \ | ||
| 49 | IEEE80211_OFDM_RATE_48MB_MASK | \ | ||
| 50 | IEEE80211_OFDM_RATE_54MB_MASK) | ||
| 51 | #define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ | ||
| 52 | IEEE80211_CCK_DEFAULT_RATES_MASK) | ||
| 53 | |||
| 54 | |||
| 55 | /* This really should be 8, but not for our firmware */ | ||
| 56 | #define MAX_SUPPORTED_RATES 32 | ||
| 57 | #define MAX_COUNTRY_TRIPLETS 32 | ||
| 58 | |||
| 59 | /* Headers */ | ||
| 60 | struct ieee80211_header { | ||
| 61 | __le16 frame_ctl; | ||
| 62 | __le16 duration_id; | ||
| 63 | u8 da[ETH_ALEN]; | ||
| 64 | u8 sa[ETH_ALEN]; | ||
| 65 | u8 bssid[ETH_ALEN]; | ||
| 66 | __le16 seq_ctl; | ||
| 67 | u8 payload[0]; | ||
| 68 | } __packed; | ||
| 69 | |||
| 70 | struct wl12xx_ie_header { | ||
| 71 | u8 id; | ||
| 72 | u8 len; | ||
| 73 | } __packed; | ||
| 74 | |||
| 75 | /* IEs */ | ||
| 76 | |||
| 77 | struct wl12xx_ie_ssid { | ||
| 78 | struct wl12xx_ie_header header; | ||
| 79 | char ssid[IW_ESSID_MAX_SIZE]; | ||
| 80 | } __packed; | ||
| 81 | |||
| 82 | struct wl12xx_ie_rates { | ||
| 83 | struct wl12xx_ie_header header; | ||
| 84 | u8 rates[MAX_SUPPORTED_RATES]; | ||
| 85 | } __packed; | ||
| 86 | |||
| 87 | struct wl12xx_ie_ds_params { | ||
| 88 | struct wl12xx_ie_header header; | ||
| 89 | u8 channel; | ||
| 90 | } __packed; | ||
| 91 | |||
| 92 | struct country_triplet { | ||
| 93 | u8 channel; | ||
| 94 | u8 num_channels; | ||
| 95 | u8 max_tx_power; | ||
| 96 | } __packed; | ||
| 97 | |||
| 98 | struct wl12xx_ie_country { | ||
| 99 | struct wl12xx_ie_header header; | ||
| 100 | u8 country_string[IEEE80211_COUNTRY_STRING_LEN]; | ||
| 101 | struct country_triplet triplets[MAX_COUNTRY_TRIPLETS]; | ||
| 102 | } __packed; | ||
| 103 | |||
| 104 | |||
| 105 | /* Templates */ | ||
| 106 | |||
| 107 | struct wl12xx_beacon_template { | ||
| 108 | struct ieee80211_header header; | ||
| 109 | __le32 time_stamp[2]; | ||
| 110 | __le16 beacon_interval; | ||
| 111 | __le16 capability; | ||
| 112 | struct wl12xx_ie_ssid ssid; | ||
| 113 | struct wl12xx_ie_rates rates; | ||
| 114 | struct wl12xx_ie_rates ext_rates; | ||
| 115 | struct wl12xx_ie_ds_params ds_params; | ||
| 116 | struct wl12xx_ie_country country; | ||
| 117 | } __packed; | ||
| 118 | |||
| 119 | struct wl12xx_null_data_template { | ||
| 120 | struct ieee80211_header header; | ||
| 121 | } __packed; | ||
| 122 | |||
| 123 | struct wl12xx_ps_poll_template { | ||
| 124 | __le16 fc; | ||
| 125 | __le16 aid; | ||
| 126 | u8 bssid[ETH_ALEN]; | ||
| 127 | u8 ta[ETH_ALEN]; | ||
| 128 | } __packed; | ||
| 129 | |||
| 130 | struct wl12xx_qos_null_data_template { | ||
| 131 | struct ieee80211_header header; | ||
| 132 | __le16 qos_ctl; | ||
| 133 | } __packed; | ||
| 134 | |||
| 135 | struct wl12xx_probe_req_template { | ||
| 136 | struct ieee80211_header header; | ||
| 137 | struct wl12xx_ie_ssid ssid; | ||
| 138 | struct wl12xx_ie_rates rates; | ||
| 139 | struct wl12xx_ie_rates ext_rates; | ||
| 140 | } __packed; | ||
| 141 | |||
| 142 | |||
| 143 | struct wl12xx_probe_resp_template { | ||
| 144 | struct ieee80211_header header; | ||
| 145 | __le32 time_stamp[2]; | ||
| 146 | __le16 beacon_interval; | ||
| 147 | __le16 capability; | ||
| 148 | struct wl12xx_ie_ssid ssid; | ||
| 149 | struct wl12xx_ie_rates rates; | ||
| 150 | struct wl12xx_ie_rates ext_rates; | ||
| 151 | struct wl12xx_ie_ds_params ds_params; | ||
| 152 | struct wl12xx_ie_country country; | ||
| 153 | } __packed; | ||
| 154 | |||
| 155 | #endif | ||
