Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 17431928194b36a0f88082df875e2e036da7fddf 1001 lines 28 kB view raw
1/* 2 * Intel Wireless Multicomm 3200 WiFi driver 3 * 4 * Copyright (C) 2009 Intel Corporation. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * * Neither the name of Intel Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * 33 * Intel Corporation <ilw@linux.intel.com> 34 * Samuel Ortiz <samuel.ortiz@intel.com> 35 * Zhu Yi <yi.zhu@intel.com> 36 * 37 */ 38 39#include <linux/kernel.h> 40#include <linux/wireless.h> 41#include <linux/etherdevice.h> 42#include <linux/ieee80211.h> 43#include <linux/sched.h> 44#include <linux/slab.h> 45 46#include "iwm.h" 47#include "bus.h" 48#include "hal.h" 49#include "umac.h" 50#include "commands.h" 51#include "debug.h" 52 53static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, 54 u8 lmac_cmd_id, 55 const void *lmac_payload, 56 u16 lmac_payload_size, 57 u8 resp) 58{ 59 struct iwm_udma_wifi_cmd udma_cmd = UDMA_LMAC_INIT; 60 struct iwm_umac_cmd umac_cmd; 61 struct iwm_lmac_cmd lmac_cmd; 62 63 lmac_cmd.id = lmac_cmd_id; 64 65 umac_cmd.id = UMAC_CMD_OPCODE_WIFI_PASS_THROUGH; 66 umac_cmd.resp = resp; 67 68 return iwm_hal_send_host_cmd(iwm, &udma_cmd, &umac_cmd, &lmac_cmd, 69 lmac_payload, lmac_payload_size); 70} 71 72int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, 73 bool resp) 74{ 75 struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload; 76 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 77 struct iwm_umac_cmd umac_cmd; 78 int ret; 79 u8 oid = hdr->oid; 80 81 if (!test_bit(IWM_STATUS_READY, &iwm->status)) { 82 IWM_ERR(iwm, "Interface is not ready yet"); 83 return -EAGAIN; 84 } 85 86 umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; 87 umac_cmd.resp = resp; 88 89 ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, 90 payload, payload_size); 91 92 if (resp) { 93 ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue, 94 test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), 95 3 * HZ); 96 97 return ret ? 0 : -EBUSY; 98 } 99 100 return ret; 101} 102 103static int modparam_wiwi = COEX_MODE_CM; 104module_param_named(wiwi, modparam_wiwi, int, 0644); 105MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)"); 106 107static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = 108{ 109 {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, 110 {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, 111 {4, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, 112 {4, 3, 0, COEX_CALIBRATION_FLAGS}, 113 {4, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, 114 {4, 3, 0, COEX_CONNECTION_ESTAB_FLAGS}, 115 {4, 3, 0, COEX_ASSOCIATED_IDLE_FLAGS}, 116 {4, 3, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, 117 {4, 3, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, 118 {4, 3, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, 119 {6, 3, 0, COEX_XOR_RF_ON_FLAGS}, 120 {4, 3, 0, COEX_RF_OFF_FLAGS}, 121 {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, 122 {4, 3, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, 123 {4, 3, 0, COEX_RSRVD1_FLAGS}, 124 {4, 3, 0, COEX_RSRVD2_FLAGS} 125}; 126 127static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = 128{ 129 {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, 130 {4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, 131 {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, 132 {6, 6, 0, COEX_CALIBRATION_FLAGS}, 133 {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, 134 {6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS}, 135 {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, 136 {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, 137 {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, 138 {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, 139 {1, 1, 0, COEX_RF_ON_FLAGS}, 140 {1, 1, 0, COEX_RF_OFF_FLAGS}, 141 {7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, 142 {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, 143 {1, 1, 0, COEX_RSRVD1_FLAGS}, 144 {1, 1, 0, COEX_RSRVD2_FLAGS} 145}; 146 147int iwm_send_prio_table(struct iwm_priv *iwm) 148{ 149 struct iwm_coex_prio_table_cmd coex_table_cmd; 150 u32 coex_enabled, mode_enabled; 151 152 memset(&coex_table_cmd, 0, sizeof(struct iwm_coex_prio_table_cmd)); 153 154 coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; 155 156 switch (modparam_wiwi) { 157 case COEX_MODE_XOR: 158 case COEX_MODE_CM: 159 coex_enabled = 1; 160 break; 161 default: 162 coex_enabled = 0; 163 break; 164 } 165 166 switch (iwm->conf.mode) { 167 case UMAC_MODE_BSS: 168 case UMAC_MODE_IBSS: 169 mode_enabled = 1; 170 break; 171 default: 172 mode_enabled = 0; 173 break; 174 } 175 176 if (coex_enabled && mode_enabled) { 177 coex_table_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK | 178 COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | 179 COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; 180 181 switch (modparam_wiwi) { 182 case COEX_MODE_XOR: 183 memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, 184 sizeof(iwm_sta_xor_prio_tbl)); 185 break; 186 case COEX_MODE_CM: 187 memcpy(coex_table_cmd.sta_prio, iwm_sta_cm_prio_tbl, 188 sizeof(iwm_sta_cm_prio_tbl)); 189 break; 190 default: 191 IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", 192 modparam_wiwi); 193 break; 194 } 195 } else 196 IWM_WARN(iwm, "coexistense disabled\n"); 197 198 return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, 199 &coex_table_cmd, 200 sizeof(struct iwm_coex_prio_table_cmd), 0); 201} 202 203int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) 204{ 205 struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; 206 207 memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); 208 209 cal_cfg_cmd.ucode_cfg.init.enable = cpu_to_le32(calib_requested); 210 cal_cfg_cmd.ucode_cfg.init.start = cpu_to_le32(calib_requested); 211 cal_cfg_cmd.ucode_cfg.init.send_res = cpu_to_le32(calib_requested); 212 cal_cfg_cmd.ucode_cfg.flags = 213 cpu_to_le32(CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK); 214 215 return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, 216 sizeof(struct iwm_lmac_cal_cfg_cmd), 1); 217} 218 219int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) 220{ 221 struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; 222 223 memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); 224 225 cal_cfg_cmd.ucode_cfg.periodic.enable = cpu_to_le32(calib_requested); 226 cal_cfg_cmd.ucode_cfg.periodic.start = cpu_to_le32(calib_requested); 227 228 return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, 229 sizeof(struct iwm_lmac_cal_cfg_cmd), 0); 230} 231 232int iwm_store_rxiq_calib_result(struct iwm_priv *iwm) 233{ 234 struct iwm_calib_rxiq *rxiq; 235 u8 *eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); 236 int grplen = sizeof(struct iwm_calib_rxiq_group); 237 238 rxiq = kzalloc(sizeof(struct iwm_calib_rxiq), GFP_KERNEL); 239 if (!rxiq) { 240 IWM_ERR(iwm, "Couldn't alloc memory for RX IQ\n"); 241 return -ENOMEM; 242 } 243 244 eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); 245 if (IS_ERR(eeprom_rxiq)) { 246 IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n"); 247 kfree(rxiq); 248 return PTR_ERR(eeprom_rxiq); 249 } 250 251 iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].buf = (u8 *)rxiq; 252 iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].size = sizeof(*rxiq); 253 254 rxiq->hdr.opcode = SHILOH_PHY_CALIBRATE_RX_IQ_CMD; 255 rxiq->hdr.first_grp = 0; 256 rxiq->hdr.grp_num = 1; 257 rxiq->hdr.all_data_valid = 1; 258 259 memcpy(&rxiq->group[0], eeprom_rxiq, 4 * grplen); 260 memcpy(&rxiq->group[4], eeprom_rxiq + 6 * grplen, grplen); 261 262 return 0; 263} 264 265int iwm_send_calib_results(struct iwm_priv *iwm) 266{ 267 int i, ret = 0; 268 269 for (i = PHY_CALIBRATE_OPCODES_NUM; i < CALIBRATION_CMD_NUM; i++) { 270 if (test_bit(i - PHY_CALIBRATE_OPCODES_NUM, 271 &iwm->calib_done_map)) { 272 IWM_DBG_CMD(iwm, DBG, 273 "Send calibration %d result\n", i); 274 ret |= iwm_send_lmac_ptrough_cmd(iwm, 275 REPLY_PHY_CALIBRATION_CMD, 276 iwm->calib_res[i].buf, 277 iwm->calib_res[i].size, 0); 278 279 kfree(iwm->calib_res[i].buf); 280 iwm->calib_res[i].buf = NULL; 281 iwm->calib_res[i].size = 0; 282 } 283 } 284 285 return ret; 286} 287 288int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit) 289{ 290 struct iwm_ct_kill_cfg_cmd cmd; 291 292 cmd.entry_threshold = entry; 293 cmd.exit_threshold = exit; 294 295 return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd, 296 sizeof(struct iwm_ct_kill_cfg_cmd), 0); 297} 298 299int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) 300{ 301 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 302 struct iwm_umac_cmd umac_cmd; 303 struct iwm_umac_cmd_reset reset; 304 305 reset.flags = reset_flags; 306 307 umac_cmd.id = UMAC_CMD_OPCODE_RESET; 308 umac_cmd.resp = resp; 309 310 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &reset, 311 sizeof(struct iwm_umac_cmd_reset)); 312} 313 314int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value) 315{ 316 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 317 struct iwm_umac_cmd umac_cmd; 318 struct iwm_umac_cmd_set_param_fix param; 319 320 if ((tbl != UMAC_PARAM_TBL_CFG_FIX) && 321 (tbl != UMAC_PARAM_TBL_FA_CFG_FIX)) 322 return -EINVAL; 323 324 umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_FIX; 325 umac_cmd.resp = 0; 326 327 param.tbl = cpu_to_le16(tbl); 328 param.key = cpu_to_le16(key); 329 param.value = cpu_to_le32(value); 330 331 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &param, 332 sizeof(struct iwm_umac_cmd_set_param_fix)); 333} 334 335int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, 336 void *payload, u16 payload_size) 337{ 338 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 339 struct iwm_umac_cmd umac_cmd; 340 struct iwm_umac_cmd_set_param_var *param_hdr; 341 u8 *param; 342 int ret; 343 344 param = kzalloc(payload_size + 345 sizeof(struct iwm_umac_cmd_set_param_var), GFP_KERNEL); 346 if (!param) { 347 IWM_ERR(iwm, "Couldn't allocate param\n"); 348 return -ENOMEM; 349 } 350 351 param_hdr = (struct iwm_umac_cmd_set_param_var *)param; 352 353 umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_VAR; 354 umac_cmd.resp = 0; 355 356 param_hdr->tbl = cpu_to_le16(UMAC_PARAM_TBL_CFG_VAR); 357 param_hdr->key = cpu_to_le16(key); 358 param_hdr->len = cpu_to_le16(payload_size); 359 memcpy(param + sizeof(struct iwm_umac_cmd_set_param_var), 360 payload, payload_size); 361 362 ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, param, 363 sizeof(struct iwm_umac_cmd_set_param_var) + 364 payload_size); 365 kfree(param); 366 367 return ret; 368} 369 370int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags) 371{ 372 int ret; 373 374 /* Use UMAC default values */ 375 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 376 CFG_POWER_INDEX, iwm->conf.power_index); 377 if (ret < 0) 378 return ret; 379 380 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, 381 CFG_FRAG_THRESHOLD, 382 iwm->conf.frag_threshold); 383 if (ret < 0) 384 return ret; 385 386 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 387 CFG_RTS_THRESHOLD, 388 iwm->conf.rts_threshold); 389 if (ret < 0) 390 return ret; 391 392 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 393 CFG_CTS_TO_SELF, iwm->conf.cts_to_self); 394 if (ret < 0) 395 return ret; 396 397 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 398 CFG_WIRELESS_MODE, 399 iwm->conf.wireless_mode); 400 if (ret < 0) 401 return ret; 402 403 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 404 CFG_COEX_MODE, modparam_wiwi); 405 if (ret < 0) 406 return ret; 407 408 /* 409 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 410 CFG_ASSOCIATION_TIMEOUT, 411 iwm->conf.assoc_timeout); 412 if (ret < 0) 413 return ret; 414 415 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 416 CFG_ROAM_TIMEOUT, 417 iwm->conf.roam_timeout); 418 if (ret < 0) 419 return ret; 420 421 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 422 CFG_WIRELESS_MODE, 423 WIRELESS_MODE_11A | WIRELESS_MODE_11G); 424 if (ret < 0) 425 return ret; 426 */ 427 428 ret = iwm_umac_set_config_var(iwm, CFG_NET_ADDR, 429 iwm_to_ndev(iwm)->dev_addr, ETH_ALEN); 430 if (ret < 0) 431 return ret; 432 433 /* UMAC PM static configurations */ 434 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 435 CFG_PM_LEGACY_RX_TIMEOUT, 0x12C); 436 if (ret < 0) 437 return ret; 438 439 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 440 CFG_PM_LEGACY_TX_TIMEOUT, 0x15E); 441 if (ret < 0) 442 return ret; 443 444 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 445 CFG_PM_CTRL_FLAGS, 0x1); 446 if (ret < 0) 447 return ret; 448 449 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 450 CFG_PM_KEEP_ALIVE_IN_BEACONS, 0x80); 451 if (ret < 0) 452 return ret; 453 454 /* reset UMAC */ 455 ret = iwm_send_umac_reset(iwm, reset_flags, 1); 456 if (ret < 0) 457 return ret; 458 459 ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, 460 WAIT_NOTIF_TIMEOUT); 461 if (ret) { 462 IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); 463 return ret; 464 } 465 466 return ret; 467} 468 469int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id) 470{ 471 struct iwm_udma_wifi_cmd udma_cmd; 472 struct iwm_umac_cmd umac_cmd; 473 struct iwm_tx_info *tx_info = skb_to_tx_info(skb); 474 475 udma_cmd.eop = 1; /* always set eop for non-concatenated Tx */ 476 udma_cmd.credit_group = pool_id; 477 udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; 478 udma_cmd.lmac_offset = 0; 479 480 umac_cmd.id = REPLY_TX; 481 umac_cmd.color = tx_info->color; 482 umac_cmd.resp = 0; 483 484 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, 485 skb->data, skb->len); 486} 487 488static int iwm_target_read(struct iwm_priv *iwm, __le32 address, 489 u8 *response, u32 resp_size) 490{ 491 struct iwm_udma_nonwifi_cmd target_cmd; 492 struct iwm_nonwifi_cmd *cmd; 493 u16 seq_num; 494 int ret = 0; 495 496 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ; 497 target_cmd.addr = address; 498 target_cmd.op1_sz = cpu_to_le32(resp_size); 499 target_cmd.op2 = 0; 500 target_cmd.handle_by_hw = 0; 501 target_cmd.resp = 1; 502 target_cmd.eop = 1; 503 504 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); 505 if (ret < 0) { 506 IWM_ERR(iwm, "Couldn't send READ command\n"); 507 return ret; 508 } 509 510 /* When succeeding, the send_target routine returns the seq number */ 511 seq_num = ret; 512 513 ret = wait_event_interruptible_timeout(iwm->nonwifi_queue, 514 (cmd = iwm_get_pending_nonwifi_cmd(iwm, seq_num, 515 UMAC_HDI_OUT_OPCODE_READ)) != NULL, 516 2 * HZ); 517 518 if (!ret) { 519 IWM_ERR(iwm, "Didn't receive a target READ answer\n"); 520 return ret; 521 } 522 523 memcpy(response, cmd->buf.hdr + sizeof(struct iwm_udma_in_hdr), 524 resp_size); 525 526 kfree(cmd); 527 528 return 0; 529} 530 531int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) 532{ 533 int ret; 534 u8 mac_align[ALIGN(ETH_ALEN, 8)]; 535 536 ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), 537 mac_align, sizeof(mac_align)); 538 if (ret) 539 return ret; 540 541 if (is_valid_ether_addr(mac_align)) 542 memcpy(mac, mac_align, ETH_ALEN); 543 else { 544 IWM_ERR(iwm, "Invalid EEPROM MAC\n"); 545 memcpy(mac, iwm->conf.mac_addr, ETH_ALEN); 546 get_random_bytes(&mac[3], 3); 547 } 548 549 return 0; 550} 551 552static int iwm_check_profile(struct iwm_priv *iwm) 553{ 554 if (!iwm->umac_profile_active) 555 return -EAGAIN; 556 557 if (iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && 558 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104 && 559 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_TKIP && 560 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_CCMP) { 561 IWM_ERR(iwm, "Wrong unicast cipher: 0x%x\n", 562 iwm->umac_profile->sec.ucast_cipher); 563 return -EAGAIN; 564 } 565 566 if (iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_40 && 567 iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_104 && 568 iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_TKIP && 569 iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_CCMP) { 570 IWM_ERR(iwm, "Wrong multicast cipher: 0x%x\n", 571 iwm->umac_profile->sec.mcast_cipher); 572 return -EAGAIN; 573 } 574 575 if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || 576 iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && 577 (iwm->umac_profile->sec.ucast_cipher != 578 iwm->umac_profile->sec.mcast_cipher)) { 579 IWM_ERR(iwm, "Unicast and multicast ciphers differ for WEP\n"); 580 } 581 582 return 0; 583} 584 585int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) 586{ 587 struct iwm_umac_tx_key_id tx_key_id; 588 int ret; 589 590 ret = iwm_check_profile(iwm); 591 if (ret < 0) 592 return ret; 593 594 /* UMAC only allows to set default key for WEP and auth type is 595 * NOT 802.1X or RSNA. */ 596 if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && 597 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) || 598 iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X || 599 iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK) 600 return 0; 601 602 tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; 603 tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - 604 sizeof(struct iwm_umac_wifi_if)); 605 606 tx_key_id.key_idx = key_idx; 607 608 return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); 609} 610 611int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) 612{ 613 int ret = 0; 614 u8 cmd[64], *sta_addr, *key_data, key_len; 615 s8 key_idx; 616 u16 cmd_size = 0; 617 struct iwm_umac_key_hdr *key_hdr = &key->hdr; 618 struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd; 619 struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd; 620 struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; 621 struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; 622 623 if (!remove) { 624 ret = iwm_check_profile(iwm); 625 if (ret < 0) 626 return ret; 627 } 628 629 sta_addr = key->hdr.mac; 630 key_data = key->key; 631 key_len = key->key_len; 632 key_idx = key->hdr.key_idx; 633 634 if (!remove) { 635 u8 auth_type = iwm->umac_profile->sec.auth_type; 636 637 IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); 638 IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); 639 IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", 640 key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); 641 642 IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n", 643 iwm->umac_profile->sec.mcast_cipher, 644 iwm->umac_profile->sec.ucast_cipher); 645 IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n", 646 iwm->umac_profile->sec.auth_type, 647 iwm->umac_profile->sec.flags); 648 649 switch (key->cipher) { 650 case WLAN_CIPHER_SUITE_WEP40: 651 wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; 652 wep40->hdr.buf_size = 653 cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - 654 sizeof(struct iwm_umac_wifi_if)); 655 656 memcpy(&wep40->key_hdr, key_hdr, 657 sizeof(struct iwm_umac_key_hdr)); 658 memcpy(wep40->key, key_data, key_len); 659 wep40->static_key = 660 !!((auth_type != UMAC_AUTH_TYPE_8021X) && 661 (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); 662 663 cmd_size = sizeof(struct iwm_umac_key_wep40); 664 break; 665 666 case WLAN_CIPHER_SUITE_WEP104: 667 wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; 668 wep104->hdr.buf_size = 669 cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - 670 sizeof(struct iwm_umac_wifi_if)); 671 672 memcpy(&wep104->key_hdr, key_hdr, 673 sizeof(struct iwm_umac_key_hdr)); 674 memcpy(wep104->key, key_data, key_len); 675 wep104->static_key = 676 !!((auth_type != UMAC_AUTH_TYPE_8021X) && 677 (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); 678 679 cmd_size = sizeof(struct iwm_umac_key_wep104); 680 break; 681 682 case WLAN_CIPHER_SUITE_CCMP: 683 key_hdr->key_idx++; 684 ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; 685 ccmp->hdr.buf_size = 686 cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) - 687 sizeof(struct iwm_umac_wifi_if)); 688 689 memcpy(&ccmp->key_hdr, key_hdr, 690 sizeof(struct iwm_umac_key_hdr)); 691 692 memcpy(ccmp->key, key_data, key_len); 693 694 if (key->seq_len) 695 memcpy(ccmp->iv_count, key->seq, key->seq_len); 696 697 cmd_size = sizeof(struct iwm_umac_key_ccmp); 698 break; 699 700 case WLAN_CIPHER_SUITE_TKIP: 701 key_hdr->key_idx++; 702 tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; 703 tkip->hdr.buf_size = 704 cpu_to_le16(sizeof(struct iwm_umac_key_tkip) - 705 sizeof(struct iwm_umac_wifi_if)); 706 707 memcpy(&tkip->key_hdr, key_hdr, 708 sizeof(struct iwm_umac_key_hdr)); 709 710 memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE); 711 memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE, 712 IWM_TKIP_MIC_SIZE); 713 memcpy(tkip->mic_rx_key, 714 key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, 715 IWM_TKIP_MIC_SIZE); 716 717 if (key->seq_len) 718 memcpy(ccmp->iv_count, key->seq, key->seq_len); 719 720 cmd_size = sizeof(struct iwm_umac_key_tkip); 721 break; 722 723 default: 724 return -ENOTSUPP; 725 } 726 727 if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) || 728 (key->cipher == WLAN_CIPHER_SUITE_CCMP)) 729 /* 730 * UGLY_UGLY_UGLY 731 * Copied HACK from the MWG driver. 732 * Without it, the key is set before the second 733 * EAPOL frame is sent, and the latter is thus 734 * encrypted. 735 */ 736 schedule_timeout_interruptible(usecs_to_jiffies(300)); 737 738 ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); 739 } else { 740 struct iwm_umac_key_remove key_remove; 741 742 IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx); 743 744 key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; 745 key_remove.hdr.buf_size = 746 cpu_to_le16(sizeof(struct iwm_umac_key_remove) - 747 sizeof(struct iwm_umac_wifi_if)); 748 memcpy(&key_remove.key_hdr, key_hdr, 749 sizeof(struct iwm_umac_key_hdr)); 750 751 ret = iwm_send_wifi_if_cmd(iwm, &key_remove, 752 sizeof(struct iwm_umac_key_remove), 753 1); 754 if (ret) 755 return ret; 756 757 iwm->keys[key_idx].key_len = 0; 758 } 759 760 return ret; 761} 762 763 764int iwm_send_mlme_profile(struct iwm_priv *iwm) 765{ 766 int ret; 767 struct iwm_umac_profile profile; 768 769 memcpy(&profile, iwm->umac_profile, sizeof(profile)); 770 771 profile.hdr.oid = UMAC_WIFI_IF_CMD_SET_PROFILE; 772 profile.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_profile) - 773 sizeof(struct iwm_umac_wifi_if)); 774 775 ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); 776 if (ret) { 777 IWM_ERR(iwm, "Send profile command failed\n"); 778 return ret; 779 } 780 781 set_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); 782 return 0; 783} 784 785int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm) 786{ 787 struct iwm_umac_invalidate_profile invalid; 788 789 invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; 790 invalid.hdr.buf_size = 791 cpu_to_le16(sizeof(struct iwm_umac_invalidate_profile) - 792 sizeof(struct iwm_umac_wifi_if)); 793 794 invalid.reason = WLAN_REASON_UNSPECIFIED; 795 796 return iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); 797} 798 799int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) 800{ 801 int ret; 802 803 ret = __iwm_invalidate_mlme_profile(iwm); 804 if (ret) 805 return ret; 806 807 ret = wait_event_interruptible_timeout(iwm->mlme_queue, 808 (iwm->umac_profile_active == 0), 5 * HZ); 809 810 return ret ? 0 : -EBUSY; 811} 812 813int iwm_tx_power_trigger(struct iwm_priv *iwm) 814{ 815 struct iwm_umac_pwr_trigger pwr_trigger; 816 817 pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER; 818 pwr_trigger.hdr.buf_size = 819 cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) - 820 sizeof(struct iwm_umac_wifi_if)); 821 822 823 return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1); 824} 825 826int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) 827{ 828 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 829 struct iwm_umac_cmd umac_cmd; 830 struct iwm_umac_cmd_stats_req stats_req; 831 832 stats_req.flags = cpu_to_le32(flags); 833 834 umac_cmd.id = UMAC_CMD_OPCODE_STATISTIC_REQUEST; 835 umac_cmd.resp = 0; 836 837 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stats_req, 838 sizeof(struct iwm_umac_cmd_stats_req)); 839} 840 841int iwm_send_umac_channel_list(struct iwm_priv *iwm) 842{ 843 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 844 struct iwm_umac_cmd umac_cmd; 845 struct iwm_umac_cmd_get_channel_list *ch_list; 846 int size = sizeof(struct iwm_umac_cmd_get_channel_list) + 847 sizeof(struct iwm_umac_channel_info) * 4; 848 int ret; 849 850 ch_list = kzalloc(size, GFP_KERNEL); 851 if (!ch_list) { 852 IWM_ERR(iwm, "Couldn't allocate channel list cmd\n"); 853 return -ENOMEM; 854 } 855 856 ch_list->ch[0].band = UMAC_BAND_2GHZ; 857 ch_list->ch[0].type = UMAC_CHANNEL_WIDTH_20MHZ; 858 ch_list->ch[0].flags = UMAC_CHANNEL_FLAG_VALID; 859 860 ch_list->ch[1].band = UMAC_BAND_5GHZ; 861 ch_list->ch[1].type = UMAC_CHANNEL_WIDTH_20MHZ; 862 ch_list->ch[1].flags = UMAC_CHANNEL_FLAG_VALID; 863 864 ch_list->ch[2].band = UMAC_BAND_2GHZ; 865 ch_list->ch[2].type = UMAC_CHANNEL_WIDTH_20MHZ; 866 ch_list->ch[2].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; 867 868 ch_list->ch[3].band = UMAC_BAND_5GHZ; 869 ch_list->ch[3].type = UMAC_CHANNEL_WIDTH_20MHZ; 870 ch_list->ch[3].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; 871 872 ch_list->count = cpu_to_le16(4); 873 874 umac_cmd.id = UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST; 875 umac_cmd.resp = 1; 876 877 ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ch_list, size); 878 879 kfree(ch_list); 880 881 return ret; 882} 883 884int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, 885 int ssid_num) 886{ 887 struct iwm_umac_cmd_scan_request req; 888 int i, ret; 889 890 memset(&req, 0, sizeof(struct iwm_umac_cmd_scan_request)); 891 892 req.hdr.oid = UMAC_WIFI_IF_CMD_SCAN_REQUEST; 893 req.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_cmd_scan_request) 894 - sizeof(struct iwm_umac_wifi_if)); 895 req.type = UMAC_WIFI_IF_SCAN_TYPE_USER; 896 req.timeout = 2; 897 req.seq_num = iwm->scan_id; 898 req.ssid_num = min(ssid_num, UMAC_WIFI_IF_PROBE_OPTION_MAX); 899 900 for (i = 0; i < req.ssid_num; i++) { 901 memcpy(req.ssids[i].ssid, ssids[i].ssid, ssids[i].ssid_len); 902 req.ssids[i].ssid_len = ssids[i].ssid_len; 903 } 904 905 ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); 906 if (ret) { 907 IWM_ERR(iwm, "Couldn't send scan request\n"); 908 return ret; 909 } 910 911 iwm->scan_id = iwm->scan_id++ % IWM_SCAN_ID_MAX; 912 913 return 0; 914} 915 916int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len) 917{ 918 struct cfg80211_ssid one_ssid; 919 920 if (test_and_set_bit(IWM_STATUS_SCANNING, &iwm->status)) 921 return 0; 922 923 one_ssid.ssid_len = min(ssid_len, IEEE80211_MAX_SSID_LEN); 924 memcpy(&one_ssid.ssid, ssid, one_ssid.ssid_len); 925 926 return iwm_scan_ssids(iwm, &one_ssid, 1); 927} 928 929int iwm_target_reset(struct iwm_priv *iwm) 930{ 931 struct iwm_udma_nonwifi_cmd target_cmd; 932 933 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_REBOOT; 934 target_cmd.addr = 0; 935 target_cmd.op1_sz = 0; 936 target_cmd.op2 = 0; 937 target_cmd.handle_by_hw = 0; 938 target_cmd.resp = 0; 939 target_cmd.eop = 1; 940 941 return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); 942} 943 944int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, 945 struct iwm_umac_notif_stop_resume_tx *ntf) 946{ 947 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 948 struct iwm_umac_cmd umac_cmd; 949 struct iwm_umac_cmd_stop_resume_tx stp_res_cmd; 950 struct iwm_sta_info *sta_info; 951 u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id); 952 int i; 953 954 sta_info = &iwm->sta_table[sta_id]; 955 if (!sta_info->valid) { 956 IWM_ERR(iwm, "Invalid STA: %d\n", sta_id); 957 return -EINVAL; 958 } 959 960 umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX; 961 umac_cmd.resp = 0; 962 963 stp_res_cmd.flags = ntf->flags; 964 stp_res_cmd.sta_id = ntf->sta_id; 965 stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk; 966 for (i = 0; i < IWM_UMAC_TID_NR; i++) 967 stp_res_cmd.last_seq_num[i] = 968 sta_info->tid_info[i].last_seq_num; 969 970 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd, 971 sizeof(struct iwm_umac_cmd_stop_resume_tx)); 972 973} 974 975int iwm_send_pmkid_update(struct iwm_priv *iwm, 976 struct cfg80211_pmksa *pmksa, u32 command) 977{ 978 struct iwm_umac_pmkid_update update; 979 int ret; 980 981 memset(&update, 0, sizeof(struct iwm_umac_pmkid_update)); 982 983 update.hdr.oid = UMAC_WIFI_IF_CMD_PMKID_UPDATE; 984 update.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_pmkid_update) - 985 sizeof(struct iwm_umac_wifi_if)); 986 987 update.command = cpu_to_le32(command); 988 if (pmksa->bssid) 989 memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); 990 if (pmksa->pmkid) 991 memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); 992 993 ret = iwm_send_wifi_if_cmd(iwm, &update, 994 sizeof(struct iwm_umac_pmkid_update), 0); 995 if (ret) { 996 IWM_ERR(iwm, "PMKID update command failed\n"); 997 return ret; 998 } 999 1000 return 0; 1001}