1 /* 2 * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 18 19 #include <linux/module.h> 20 #include <linux/firmware.h> 21 #include <linux/platform_device.h> 22 #include <linux/of_address.h> 23 #include <linux/of_device.h> 24 #include "wcn36xx.h" 25 26 unsigned int wcn36xx_dbg_mask; 27 module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644); 28 MODULE_PARM_DESC(debug_mask, "Debugging mask"); 29 30 #define CHAN2G(_freq, _idx) { \ 31 .band = NL80211_BAND_2GHZ, \ 32 .center_freq = (_freq), \ 33 .hw_value = (_idx), \ 34 .max_power = 25, \ 35 } 36 37 #define CHAN5G(_freq, _idx) { \ 38 .band = NL80211_BAND_5GHZ, \ 39 .center_freq = (_freq), \ 40 .hw_value = (_idx), \ 41 .max_power = 25, \ 42 } 43 44 /* The wcn firmware expects channel values to matching 45 * their mnemonic values. So use these for .hw_value. */ 46 static struct ieee80211_channel wcn_2ghz_channels[] = { 47 CHAN2G(2412, 1), /* Channel 1 */ 48 CHAN2G(2417, 2), /* Channel 2 */ 49 CHAN2G(2422, 3), /* Channel 3 */ 50 CHAN2G(2427, 4), /* Channel 4 */ 51 CHAN2G(2432, 5), /* Channel 5 */ 52 CHAN2G(2437, 6), /* Channel 6 */ 53 CHAN2G(2442, 7), /* Channel 7 */ 54 CHAN2G(2447, 8), /* Channel 8 */ 55 CHAN2G(2452, 9), /* Channel 9 */ 56 CHAN2G(2457, 10), /* Channel 10 */ 57 CHAN2G(2462, 11), /* Channel 11 */ 58 CHAN2G(2467, 12), /* Channel 12 */ 59 CHAN2G(2472, 13), /* Channel 13 */ 60 CHAN2G(2484, 14) /* Channel 14 */ 61 62 }; 63 64 static struct ieee80211_channel wcn_5ghz_channels[] = { 65 CHAN5G(5180, 36), 66 CHAN5G(5200, 40), 67 CHAN5G(5220, 44), 68 CHAN5G(5240, 48), 69 CHAN5G(5260, 52), 70 CHAN5G(5280, 56), 71 CHAN5G(5300, 60), 72 CHAN5G(5320, 64), 73 CHAN5G(5500, 100), 74 CHAN5G(5520, 104), 75 CHAN5G(5540, 108), 76 CHAN5G(5560, 112), 77 CHAN5G(5580, 116), 78 CHAN5G(5600, 120), 79 CHAN5G(5620, 124), 80 CHAN5G(5640, 128), 81 CHAN5G(5660, 132), 82 CHAN5G(5700, 140), 83 CHAN5G(5745, 149), 84 CHAN5G(5765, 153), 85 CHAN5G(5785, 157), 86 CHAN5G(5805, 161), 87 CHAN5G(5825, 165) 88 }; 89 90 #define RATE(_bitrate, _hw_rate, _flags) { \ 91 .bitrate = (_bitrate), \ 92 .flags = (_flags), \ 93 .hw_value = (_hw_rate), \ 94 .hw_value_short = (_hw_rate) \ 95 } 96 97 static struct ieee80211_rate wcn_2ghz_rates[] = { 98 RATE(10, HW_RATE_INDEX_1MBPS, 0), 99 RATE(20, HW_RATE_INDEX_2MBPS, IEEE80211_RATE_SHORT_PREAMBLE), 100 RATE(55, HW_RATE_INDEX_5_5MBPS, IEEE80211_RATE_SHORT_PREAMBLE), 101 RATE(110, HW_RATE_INDEX_11MBPS, IEEE80211_RATE_SHORT_PREAMBLE), 102 RATE(60, HW_RATE_INDEX_6MBPS, 0), 103 RATE(90, HW_RATE_INDEX_9MBPS, 0), 104 RATE(120, HW_RATE_INDEX_12MBPS, 0), 105 RATE(180, HW_RATE_INDEX_18MBPS, 0), 106 RATE(240, HW_RATE_INDEX_24MBPS, 0), 107 RATE(360, HW_RATE_INDEX_36MBPS, 0), 108 RATE(480, HW_RATE_INDEX_48MBPS, 0), 109 RATE(540, HW_RATE_INDEX_54MBPS, 0) 110 }; 111 112 static struct ieee80211_rate wcn_5ghz_rates[] = { 113 RATE(60, HW_RATE_INDEX_6MBPS, 0), 114 RATE(90, HW_RATE_INDEX_9MBPS, 0), 115 RATE(120, HW_RATE_INDEX_12MBPS, 0), 116 RATE(180, HW_RATE_INDEX_18MBPS, 0), 117 RATE(240, HW_RATE_INDEX_24MBPS, 0), 118 RATE(360, HW_RATE_INDEX_36MBPS, 0), 119 RATE(480, HW_RATE_INDEX_48MBPS, 0), 120 RATE(540, HW_RATE_INDEX_54MBPS, 0) 121 }; 122 123 static struct ieee80211_supported_band wcn_band_2ghz = { 124 .channels = wcn_2ghz_channels, 125 .n_channels = ARRAY_SIZE(wcn_2ghz_channels), 126 .bitrates = wcn_2ghz_rates, 127 .n_bitrates = ARRAY_SIZE(wcn_2ghz_rates), 128 .ht_cap = { 129 .cap = IEEE80211_HT_CAP_GRN_FLD | 130 IEEE80211_HT_CAP_SGI_20 | 131 IEEE80211_HT_CAP_DSSSCCK40 | 132 IEEE80211_HT_CAP_LSIG_TXOP_PROT, 133 .ht_supported = true, 134 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, 135 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, 136 .mcs = { 137 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 138 .rx_highest = cpu_to_le16(72), 139 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, 140 } 141 } 142 }; 143 144 static struct ieee80211_supported_band wcn_band_5ghz = { 145 .channels = wcn_5ghz_channels, 146 .n_channels = ARRAY_SIZE(wcn_5ghz_channels), 147 .bitrates = wcn_5ghz_rates, 148 .n_bitrates = ARRAY_SIZE(wcn_5ghz_rates), 149 .ht_cap = { 150 .cap = IEEE80211_HT_CAP_GRN_FLD | 151 IEEE80211_HT_CAP_SGI_20 | 152 IEEE80211_HT_CAP_DSSSCCK40 | 153 IEEE80211_HT_CAP_LSIG_TXOP_PROT | 154 IEEE80211_HT_CAP_SGI_40 | 155 IEEE80211_HT_CAP_SUP_WIDTH_20_40, 156 .ht_supported = true, 157 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, 158 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, 159 .mcs = { 160 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 161 .rx_highest = cpu_to_le16(72), 162 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, 163 } 164 } 165 }; 166 167 #ifdef CONFIG_PM 168 169 static const struct wiphy_wowlan_support wowlan_support = { 170 .flags = WIPHY_WOWLAN_ANY 171 }; 172 173 #endif 174 175 static inline u8 get_sta_index(struct ieee80211_vif *vif, 176 struct wcn36xx_sta *sta_priv) 177 { 178 return NL80211_IFTYPE_STATION == vif->type ? 179 sta_priv->bss_sta_index : 180 sta_priv->sta_index; 181 } 182 183 static const char * const wcn36xx_caps_names[] = { 184 "MCC", /* 0 */ 185 "P2P", /* 1 */ 186 "DOT11AC", /* 2 */ 187 "SLM_SESSIONIZATION", /* 3 */ 188 "DOT11AC_OPMODE", /* 4 */ 189 "SAP32STA", /* 5 */ 190 "TDLS", /* 6 */ 191 "P2P_GO_NOA_DECOUPLE_INIT_SCAN",/* 7 */ 192 "WLANACTIVE_OFFLOAD", /* 8 */ 193 "BEACON_OFFLOAD", /* 9 */ 194 "SCAN_OFFLOAD", /* 10 */ 195 "ROAM_OFFLOAD", /* 11 */ 196 "BCN_MISS_OFFLOAD", /* 12 */ 197 "STA_POWERSAVE", /* 13 */ 198 "STA_ADVANCED_PWRSAVE", /* 14 */ 199 "AP_UAPSD", /* 15 */ 200 "AP_DFS", /* 16 */ 201 "BLOCKACK", /* 17 */ 202 "PHY_ERR", /* 18 */ 203 "BCN_FILTER", /* 19 */ 204 "RTT", /* 20 */ 205 "RATECTRL", /* 21 */ 206 "WOW", /* 22 */ 207 "WLAN_ROAM_SCAN_OFFLOAD", /* 23 */ 208 "SPECULATIVE_PS_POLL", /* 24 */ 209 "SCAN_SCH", /* 25 */ 210 "IBSS_HEARTBEAT_OFFLOAD", /* 26 */ 211 "WLAN_SCAN_OFFLOAD", /* 27 */ 212 "WLAN_PERIODIC_TX_PTRN", /* 28 */ 213 "ADVANCE_TDLS", /* 29 */ 214 "BATCH_SCAN", /* 30 */ 215 "FW_IN_TX_PATH", /* 31 */ 216 "EXTENDED_NSOFFLOAD_SLOT", /* 32 */ 217 "CH_SWITCH_V1", /* 33 */ 218 "HT40_OBSS_SCAN", /* 34 */ 219 "UPDATE_CHANNEL_LIST", /* 35 */ 220 "WLAN_MCADDR_FLT", /* 36 */ 221 "WLAN_CH144", /* 37 */ 222 "NAN", /* 38 */ 223 "TDLS_SCAN_COEXISTENCE", /* 39 */ 224 "LINK_LAYER_STATS_MEAS", /* 40 */ 225 "MU_MIMO", /* 41 */ 226 "EXTENDED_SCAN", /* 42 */ 227 "DYNAMIC_WMM_PS", /* 43 */ 228 "MAC_SPOOFED_SCAN", /* 44 */ 229 "BMU_ERROR_GENERIC_RECOVERY", /* 45 */ 230 "DISA", /* 46 */ 231 "FW_STATS", /* 47 */ 232 "WPS_PRBRSP_TMPL", /* 48 */ 233 "BCN_IE_FLT_DELTA", /* 49 */ 234 "TDLS_OFF_CHANNEL", /* 51 */ 235 "RTT3", /* 52 */ 236 "MGMT_FRAME_LOGGING", /* 53 */ 237 "ENHANCED_TXBD_COMPLETION", /* 54 */ 238 "LOGGING_ENHANCEMENT", /* 55 */ 239 "EXT_SCAN_ENHANCED", /* 56 */ 240 "MEMORY_DUMP_SUPPORTED", /* 57 */ 241 "PER_PKT_STATS_SUPPORTED", /* 58 */ 242 "EXT_LL_STAT", /* 60 */ 243 "WIFI_CONFIG", /* 61 */ 244 "ANTENNA_DIVERSITY_SELECTION", /* 62 */ 245 }; 246 247 static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x) 248 { 249 if (x >= ARRAY_SIZE(wcn36xx_caps_names)) 250 return "UNKNOWN"; 251 return wcn36xx_caps_names[x]; 252 } 253 254 static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) 255 { 256 int i; 257 258 for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { 259 if (get_feat_caps(wcn->fw_feat_caps, i)) 260 wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i)); 261 } 262 } 263 264 static int wcn36xx_start(struct ieee80211_hw *hw) 265 { 266 struct wcn36xx *wcn = hw->priv; 267 int ret; 268 269 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac start\n"); 270 271 /* SMD initialization */ 272 ret = wcn36xx_smd_open(wcn); 273 if (ret) { 274 wcn36xx_err("Failed to open smd channel: %d\n", ret); 275 goto out_err; 276 } 277 278 /* Allocate memory pools for Mgmt BD headers and Data BD headers */ 279 ret = wcn36xx_dxe_allocate_mem_pools(wcn); 280 if (ret) { 281 wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret); 282 goto out_smd_close; 283 } 284 285 ret = wcn36xx_dxe_alloc_ctl_blks(wcn); 286 if (ret) { 287 wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret); 288 goto out_free_dxe_pool; 289 } 290 291 wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL); 292 if (!wcn->hal_buf) { 293 wcn36xx_err("Failed to allocate smd buf\n"); 294 ret = -ENOMEM; 295 goto out_free_dxe_ctl; 296 } 297 298 ret = wcn36xx_smd_load_nv(wcn); 299 if (ret) { 300 wcn36xx_err("Failed to push NV to chip\n"); 301 goto out_free_smd_buf; 302 } 303 304 ret = wcn36xx_smd_start(wcn); 305 if (ret) { 306 wcn36xx_err("Failed to start chip\n"); 307 goto out_free_smd_buf; 308 } 309 310 if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { 311 ret = wcn36xx_smd_feature_caps_exchange(wcn); 312 if (ret) 313 wcn36xx_warn("Exchange feature caps failed\n"); 314 else 315 wcn36xx_feat_caps_info(wcn); 316 } 317 318 /* DMA channel initialization */ 319 ret = wcn36xx_dxe_init(wcn); 320 if (ret) { 321 wcn36xx_err("DXE init failed\n"); 322 goto out_smd_stop; 323 } 324 325 wcn36xx_debugfs_init(wcn); 326 327 INIT_LIST_HEAD(&wcn->vif_list); 328 spin_lock_init(&wcn->dxe_lock); 329 330 return 0; 331 332 out_smd_stop: 333 wcn36xx_smd_stop(wcn); 334 out_free_smd_buf: 335 kfree(wcn->hal_buf); 336 out_free_dxe_pool: 337 wcn36xx_dxe_free_mem_pools(wcn); 338 out_free_dxe_ctl: 339 wcn36xx_dxe_free_ctl_blks(wcn); 340 out_smd_close: 341 wcn36xx_smd_close(wcn); 342 out_err: 343 return ret; 344 } 345 346 static void wcn36xx_stop(struct ieee80211_hw *hw) 347 { 348 struct wcn36xx *wcn = hw->priv; 349 350 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n"); 351 352 wcn36xx_debugfs_exit(wcn); 353 wcn36xx_smd_stop(wcn); 354 wcn36xx_dxe_deinit(wcn); 355 wcn36xx_smd_close(wcn); 356 357 wcn36xx_dxe_free_mem_pools(wcn); 358 wcn36xx_dxe_free_ctl_blks(wcn); 359 360 kfree(wcn->hal_buf); 361 } 362 363 static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) 364 { 365 struct wcn36xx *wcn = hw->priv; 366 struct ieee80211_vif *vif = NULL; 367 struct wcn36xx_vif *tmp; 368 369 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed); 370 371 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 372 int ch = WCN36XX_HW_CHANNEL(wcn); 373 wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n", 374 ch); 375 list_for_each_entry(tmp, &wcn->vif_list, list) { 376 vif = wcn36xx_priv_to_vif(tmp); 377 wcn36xx_smd_switch_channel(wcn, vif, ch); 378 } 379 } 380 381 return 0; 382 } 383 384 static void wcn36xx_configure_filter(struct ieee80211_hw *hw, 385 unsigned int changed, 386 unsigned int *total, u64 multicast) 387 { 388 struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp; 389 struct wcn36xx *wcn = hw->priv; 390 struct wcn36xx_vif *tmp; 391 struct ieee80211_vif *vif = NULL; 392 393 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n"); 394 395 *total &= FIF_ALLMULTI; 396 397 fp = (void *)(unsigned long)multicast; 398 list_for_each_entry(tmp, &wcn->vif_list, list) { 399 vif = wcn36xx_priv_to_vif(tmp); 400 401 /* FW handles MC filtering only when connected as STA */ 402 if (*total & FIF_ALLMULTI) 403 wcn36xx_smd_set_mc_list(wcn, vif, NULL); 404 else if (NL80211_IFTYPE_STATION == vif->type && tmp->sta_assoc) 405 wcn36xx_smd_set_mc_list(wcn, vif, fp); 406 } 407 kfree(fp); 408 } 409 410 static u64 wcn36xx_prepare_multicast(struct ieee80211_hw *hw, 411 struct netdev_hw_addr_list *mc_list) 412 { 413 struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp; 414 struct netdev_hw_addr *ha; 415 416 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac prepare multicast list\n"); 417 fp = kzalloc(sizeof(*fp), GFP_ATOMIC); 418 if (!fp) { 419 wcn36xx_err("Out of memory setting filters.\n"); 420 return 0; 421 } 422 423 fp->mc_addr_count = 0; 424 /* update multicast filtering parameters */ 425 if (netdev_hw_addr_list_count(mc_list) <= 426 WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS) { 427 netdev_hw_addr_list_for_each(ha, mc_list) { 428 memcpy(fp->mc_addr[fp->mc_addr_count], 429 ha->addr, ETH_ALEN); 430 fp->mc_addr_count++; 431 } 432 } 433 434 return (u64)(unsigned long)fp; 435 } 436 437 static void wcn36xx_tx(struct ieee80211_hw *hw, 438 struct ieee80211_tx_control *control, 439 struct sk_buff *skb) 440 { 441 struct wcn36xx *wcn = hw->priv; 442 struct wcn36xx_sta *sta_priv = NULL; 443 444 if (control->sta) 445 sta_priv = wcn36xx_sta_to_priv(control->sta); 446 447 if (wcn36xx_start_tx(wcn, sta_priv, skb)) 448 ieee80211_free_txskb(wcn->hw, skb); 449 } 450 451 static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 452 struct ieee80211_vif *vif, 453 struct ieee80211_sta *sta, 454 struct ieee80211_key_conf *key_conf) 455 { 456 struct wcn36xx *wcn = hw->priv; 457 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); 458 struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); 459 int ret = 0; 460 u8 key[WLAN_MAX_KEY_LEN]; 461 462 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 set key\n"); 463 wcn36xx_dbg(WCN36XX_DBG_MAC, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n", 464 cmd, key_conf->cipher, key_conf->keyidx, 465 key_conf->keylen, key_conf->flags); 466 wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "KEY: ", 467 key_conf->key, 468 key_conf->keylen); 469 470 switch (key_conf->cipher) { 471 case WLAN_CIPHER_SUITE_WEP40: 472 vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40; 473 break; 474 case WLAN_CIPHER_SUITE_WEP104: 475 vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40; 476 break; 477 case WLAN_CIPHER_SUITE_CCMP: 478 vif_priv->encrypt_type = WCN36XX_HAL_ED_CCMP; 479 break; 480 case WLAN_CIPHER_SUITE_TKIP: 481 vif_priv->encrypt_type = WCN36XX_HAL_ED_TKIP; 482 break; 483 default: 484 wcn36xx_err("Unsupported key type 0x%x\n", 485 key_conf->cipher); 486 ret = -EOPNOTSUPP; 487 goto out; 488 } 489 490 switch (cmd) { 491 case SET_KEY: 492 if (WCN36XX_HAL_ED_TKIP == vif_priv->encrypt_type) { 493 /* 494 * Supplicant is sending key in the wrong order: 495 * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b) 496 * but HW expects it to be in the order as described in 497 * IEEE 802.11 spec (see chapter 11.7) like this: 498 * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b) 499 */ 500 memcpy(key, key_conf->key, 16); 501 memcpy(key + 16, key_conf->key + 24, 8); 502 memcpy(key + 24, key_conf->key + 16, 8); 503 } else { 504 memcpy(key, key_conf->key, key_conf->keylen); 505 } 506 507 if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) { 508 sta_priv->is_data_encrypted = true; 509 /* Reconfigure bss with encrypt_type */ 510 if (NL80211_IFTYPE_STATION == vif->type) 511 wcn36xx_smd_config_bss(wcn, 512 vif, 513 sta, 514 sta->addr, 515 true); 516 517 wcn36xx_smd_set_stakey(wcn, 518 vif_priv->encrypt_type, 519 key_conf->keyidx, 520 key_conf->keylen, 521 key, 522 get_sta_index(vif, sta_priv)); 523 } else { 524 wcn36xx_smd_set_bsskey(wcn, 525 vif_priv->encrypt_type, 526 key_conf->keyidx, 527 key_conf->keylen, 528 key); 529 if ((WLAN_CIPHER_SUITE_WEP40 == key_conf->cipher) || 530 (WLAN_CIPHER_SUITE_WEP104 == key_conf->cipher)) { 531 sta_priv->is_data_encrypted = true; 532 wcn36xx_smd_set_stakey(wcn, 533 vif_priv->encrypt_type, 534 key_conf->keyidx, 535 key_conf->keylen, 536 key, 537 get_sta_index(vif, sta_priv)); 538 } 539 } 540 break; 541 case DISABLE_KEY: 542 if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) { 543 vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE; 544 wcn36xx_smd_remove_bsskey(wcn, 545 vif_priv->encrypt_type, 546 key_conf->keyidx); 547 } else { 548 sta_priv->is_data_encrypted = false; 549 /* do not remove key if disassociated */ 550 if (sta_priv->aid) 551 wcn36xx_smd_remove_stakey(wcn, 552 vif_priv->encrypt_type, 553 key_conf->keyidx, 554 get_sta_index(vif, sta_priv)); 555 } 556 break; 557 default: 558 wcn36xx_err("Unsupported key cmd 0x%x\n", cmd); 559 ret = -EOPNOTSUPP; 560 goto out; 561 } 562 563 out: 564 return ret; 565 } 566 567 static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, 568 struct ieee80211_vif *vif, 569 const u8 *mac_addr) 570 { 571 struct wcn36xx *wcn = hw->priv; 572 573 wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN); 574 wcn36xx_smd_start_scan(wcn); 575 } 576 577 static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw, 578 struct ieee80211_vif *vif) 579 { 580 struct wcn36xx *wcn = hw->priv; 581 582 wcn36xx_smd_end_scan(wcn); 583 wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN); 584 } 585 586 static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, 587 enum nl80211_band band) 588 { 589 int i, size; 590 u16 *rates_table; 591 struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); 592 u32 rates = sta->supp_rates[band]; 593 594 memset(&sta_priv->supported_rates, 0, 595 sizeof(sta_priv->supported_rates)); 596 sta_priv->supported_rates.op_rate_mode = STA_11n; 597 598 size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates); 599 rates_table = sta_priv->supported_rates.dsss_rates; 600 if (band == NL80211_BAND_2GHZ) { 601 for (i = 0; i < size; i++) { 602 if (rates & 0x01) { 603 rates_table[i] = wcn_2ghz_rates[i].hw_value; 604 rates = rates >> 1; 605 } 606 } 607 } 608 609 size = ARRAY_SIZE(sta_priv->supported_rates.ofdm_rates); 610 rates_table = sta_priv->supported_rates.ofdm_rates; 611 for (i = 0; i < size; i++) { 612 if (rates & 0x01) { 613 rates_table[i] = wcn_5ghz_rates[i].hw_value; 614 rates = rates >> 1; 615 } 616 } 617 618 if (sta->ht_cap.ht_supported) { 619 BUILD_BUG_ON(sizeof(sta->ht_cap.mcs.rx_mask) > 620 sizeof(sta_priv->supported_rates.supported_mcs_set)); 621 memcpy(sta_priv->supported_rates.supported_mcs_set, 622 sta->ht_cap.mcs.rx_mask, 623 sizeof(sta->ht_cap.mcs.rx_mask)); 624 } 625 } 626 void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates) 627 { 628 u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = { 629 HW_RATE_INDEX_6MBPS, 630 HW_RATE_INDEX_9MBPS, 631 HW_RATE_INDEX_12MBPS, 632 HW_RATE_INDEX_18MBPS, 633 HW_RATE_INDEX_24MBPS, 634 HW_RATE_INDEX_36MBPS, 635 HW_RATE_INDEX_48MBPS, 636 HW_RATE_INDEX_54MBPS 637 }; 638 u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES] = { 639 HW_RATE_INDEX_1MBPS, 640 HW_RATE_INDEX_2MBPS, 641 HW_RATE_INDEX_5_5MBPS, 642 HW_RATE_INDEX_11MBPS 643 }; 644 645 rates->op_rate_mode = STA_11n; 646 memcpy(rates->dsss_rates, dsss_rates, 647 sizeof(*dsss_rates) * WCN36XX_HAL_NUM_DSSS_RATES); 648 memcpy(rates->ofdm_rates, ofdm_rates, 649 sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES); 650 rates->supported_mcs_set[0] = 0xFF; 651 } 652 static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, 653 struct ieee80211_vif *vif, 654 struct ieee80211_bss_conf *bss_conf, 655 u32 changed) 656 { 657 struct wcn36xx *wcn = hw->priv; 658 struct sk_buff *skb = NULL; 659 u16 tim_off, tim_len; 660 enum wcn36xx_hal_link_state link_state; 661 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); 662 663 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n", 664 vif, changed); 665 666 if (changed & BSS_CHANGED_BEACON_INFO) { 667 wcn36xx_dbg(WCN36XX_DBG_MAC, 668 "mac bss changed dtim period %d\n", 669 bss_conf->dtim_period); 670 671 vif_priv->dtim_period = bss_conf->dtim_period; 672 } 673 674 if (changed & BSS_CHANGED_PS) { 675 wcn36xx_dbg(WCN36XX_DBG_MAC, 676 "mac bss PS set %d\n", 677 bss_conf->ps); 678 if (bss_conf->ps) { 679 wcn36xx_pmc_enter_bmps_state(wcn, vif); 680 } else { 681 wcn36xx_pmc_exit_bmps_state(wcn, vif); 682 } 683 } 684 685 if (changed & BSS_CHANGED_BSSID) { 686 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed_bssid %pM\n", 687 bss_conf->bssid); 688 689 if (!is_zero_ether_addr(bss_conf->bssid)) { 690 vif_priv->is_joining = true; 691 vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX; 692 wcn36xx_smd_join(wcn, bss_conf->bssid, 693 vif->addr, WCN36XX_HW_CHANNEL(wcn)); 694 wcn36xx_smd_config_bss(wcn, vif, NULL, 695 bss_conf->bssid, false); 696 } else { 697 vif_priv->is_joining = false; 698 wcn36xx_smd_delete_bss(wcn, vif); 699 vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE; 700 } 701 } 702 703 if (changed & BSS_CHANGED_SSID) { 704 wcn36xx_dbg(WCN36XX_DBG_MAC, 705 "mac bss changed ssid\n"); 706 wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ", 707 bss_conf->ssid, bss_conf->ssid_len); 708 709 vif_priv->ssid.length = bss_conf->ssid_len; 710 memcpy(&vif_priv->ssid.ssid, 711 bss_conf->ssid, 712 bss_conf->ssid_len); 713 } 714 715 if (changed & BSS_CHANGED_ASSOC) { 716 vif_priv->is_joining = false; 717 if (bss_conf->assoc) { 718 struct ieee80211_sta *sta; 719 struct wcn36xx_sta *sta_priv; 720 721 wcn36xx_dbg(WCN36XX_DBG_MAC, 722 "mac assoc bss %pM vif %pM AID=%d\n", 723 bss_conf->bssid, 724 vif->addr, 725 bss_conf->aid); 726 727 vif_priv->sta_assoc = true; 728 rcu_read_lock(); 729 sta = ieee80211_find_sta(vif, bss_conf->bssid); 730 if (!sta) { 731 wcn36xx_err("sta %pM is not found\n", 732 bss_conf->bssid); 733 rcu_read_unlock(); 734 goto out; 735 } 736 sta_priv = wcn36xx_sta_to_priv(sta); 737 738 wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn)); 739 740 wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, 741 vif->addr, 742 WCN36XX_HAL_LINK_POSTASSOC_STATE); 743 wcn36xx_smd_config_bss(wcn, vif, sta, 744 bss_conf->bssid, 745 true); 746 sta_priv->aid = bss_conf->aid; 747 /* 748 * config_sta must be called from because this is the 749 * place where AID is available. 750 */ 751 wcn36xx_smd_config_sta(wcn, vif, sta); 752 rcu_read_unlock(); 753 } else { 754 wcn36xx_dbg(WCN36XX_DBG_MAC, 755 "disassociated bss %pM vif %pM AID=%d\n", 756 bss_conf->bssid, 757 vif->addr, 758 bss_conf->aid); 759 vif_priv->sta_assoc = false; 760 wcn36xx_smd_set_link_st(wcn, 761 bss_conf->bssid, 762 vif->addr, 763 WCN36XX_HAL_LINK_IDLE_STATE); 764 } 765 } 766 767 if (changed & BSS_CHANGED_AP_PROBE_RESP) { 768 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ap probe resp\n"); 769 skb = ieee80211_proberesp_get(hw, vif); 770 if (!skb) { 771 wcn36xx_err("failed to alloc probereq skb\n"); 772 goto out; 773 } 774 775 wcn36xx_smd_update_proberesp_tmpl(wcn, vif, skb); 776 dev_kfree_skb(skb); 777 } 778 779 if (changed & BSS_CHANGED_BEACON_ENABLED || 780 changed & BSS_CHANGED_BEACON) { 781 wcn36xx_dbg(WCN36XX_DBG_MAC, 782 "mac bss changed beacon enabled %d\n", 783 bss_conf->enable_beacon); 784 785 if (bss_conf->enable_beacon) { 786 vif_priv->dtim_period = bss_conf->dtim_period; 787 vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX; 788 wcn36xx_smd_config_bss(wcn, vif, NULL, 789 vif->addr, false); 790 skb = ieee80211_beacon_get_tim(hw, vif, &tim_off, 791 &tim_len); 792 if (!skb) { 793 wcn36xx_err("failed to alloc beacon skb\n"); 794 goto out; 795 } 796 wcn36xx_smd_send_beacon(wcn, vif, skb, tim_off, 0); 797 dev_kfree_skb(skb); 798 799 if (vif->type == NL80211_IFTYPE_ADHOC || 800 vif->type == NL80211_IFTYPE_MESH_POINT) 801 link_state = WCN36XX_HAL_LINK_IBSS_STATE; 802 else 803 link_state = WCN36XX_HAL_LINK_AP_STATE; 804 805 wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr, 806 link_state); 807 } else { 808 wcn36xx_smd_delete_bss(wcn, vif); 809 wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr, 810 WCN36XX_HAL_LINK_IDLE_STATE); 811 } 812 } 813 out: 814 return; 815 } 816 817 /* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */ 818 static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 819 { 820 struct wcn36xx *wcn = hw->priv; 821 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value); 822 823 wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_RTS_THRESHOLD, value); 824 return 0; 825 } 826 827 static void wcn36xx_remove_interface(struct ieee80211_hw *hw, 828 struct ieee80211_vif *vif) 829 { 830 struct wcn36xx *wcn = hw->priv; 831 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); 832 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif); 833 834 list_del(&vif_priv->list); 835 wcn36xx_smd_delete_sta_self(wcn, vif->addr); 836 } 837 838 static int wcn36xx_add_interface(struct ieee80211_hw *hw, 839 struct ieee80211_vif *vif) 840 { 841 struct wcn36xx *wcn = hw->priv; 842 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); 843 844 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n", 845 vif, vif->type); 846 847 if (!(NL80211_IFTYPE_STATION == vif->type || 848 NL80211_IFTYPE_AP == vif->type || 849 NL80211_IFTYPE_ADHOC == vif->type || 850 NL80211_IFTYPE_MESH_POINT == vif->type)) { 851 wcn36xx_warn("Unsupported interface type requested: %d\n", 852 vif->type); 853 return -EOPNOTSUPP; 854 } 855 856 list_add(&vif_priv->list, &wcn->vif_list); 857 wcn36xx_smd_add_sta_self(wcn, vif); 858 859 return 0; 860 } 861 862 static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 863 struct ieee80211_sta *sta) 864 { 865 struct wcn36xx *wcn = hw->priv; 866 struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); 867 struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); 868 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n", 869 vif, sta->addr); 870 871 spin_lock_init(&sta_priv->ampdu_lock); 872 sta_priv->vif = vif_priv; 873 /* 874 * For STA mode HW will be configured on BSS_CHANGED_ASSOC because 875 * at this stage AID is not available yet. 876 */ 877 if (NL80211_IFTYPE_STATION != vif->type) { 878 wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn)); 879 sta_priv->aid = sta->aid; 880 wcn36xx_smd_config_sta(wcn, vif, sta); 881 } 882 return 0; 883 } 884 885 static int wcn36xx_sta_remove(struct ieee80211_hw *hw, 886 struct ieee80211_vif *vif, 887 struct ieee80211_sta *sta) 888 { 889 struct wcn36xx *wcn = hw->priv; 890 struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta); 891 892 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n", 893 vif, sta->addr, sta_priv->sta_index); 894 895 wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index); 896 sta_priv->vif = NULL; 897 return 0; 898 } 899 900 #ifdef CONFIG_PM 901 902 static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) 903 { 904 struct wcn36xx *wcn = hw->priv; 905 906 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n"); 907 908 flush_workqueue(wcn->hal_ind_wq); 909 wcn36xx_smd_set_power_params(wcn, true); 910 return 0; 911 } 912 913 static int wcn36xx_resume(struct ieee80211_hw *hw) 914 { 915 struct wcn36xx *wcn = hw->priv; 916 917 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n"); 918 919 flush_workqueue(wcn->hal_ind_wq); 920 wcn36xx_smd_set_power_params(wcn, false); 921 return 0; 922 } 923 924 #endif 925 926 static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, 927 struct ieee80211_vif *vif, 928 struct ieee80211_ampdu_params *params) 929 { 930 struct wcn36xx *wcn = hw->priv; 931 struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(params->sta); 932 struct ieee80211_sta *sta = params->sta; 933 enum ieee80211_ampdu_mlme_action action = params->action; 934 u16 tid = params->tid; 935 u16 *ssn = ¶ms->ssn; 936 937 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", 938 action, tid); 939 940 switch (action) { 941 case IEEE80211_AMPDU_RX_START: 942 sta_priv->tid = tid; 943 wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, 944 get_sta_index(vif, sta_priv)); 945 wcn36xx_smd_add_ba(wcn); 946 wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); 947 break; 948 case IEEE80211_AMPDU_RX_STOP: 949 wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); 950 break; 951 case IEEE80211_AMPDU_TX_START: 952 spin_lock_bh(&sta_priv->ampdu_lock); 953 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; 954 spin_unlock_bh(&sta_priv->ampdu_lock); 955 956 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); 957 break; 958 case IEEE80211_AMPDU_TX_OPERATIONAL: 959 spin_lock_bh(&sta_priv->ampdu_lock); 960 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL; 961 spin_unlock_bh(&sta_priv->ampdu_lock); 962 963 wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, 964 get_sta_index(vif, sta_priv)); 965 break; 966 case IEEE80211_AMPDU_TX_STOP_FLUSH: 967 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 968 case IEEE80211_AMPDU_TX_STOP_CONT: 969 spin_lock_bh(&sta_priv->ampdu_lock); 970 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE; 971 spin_unlock_bh(&sta_priv->ampdu_lock); 972 973 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 974 break; 975 default: 976 wcn36xx_err("Unknown AMPDU action\n"); 977 } 978 979 return 0; 980 } 981 982 static const struct ieee80211_ops wcn36xx_ops = { 983 .start = wcn36xx_start, 984 .stop = wcn36xx_stop, 985 .add_interface = wcn36xx_add_interface, 986 .remove_interface = wcn36xx_remove_interface, 987 #ifdef CONFIG_PM 988 .suspend = wcn36xx_suspend, 989 .resume = wcn36xx_resume, 990 #endif 991 .config = wcn36xx_config, 992 .prepare_multicast = wcn36xx_prepare_multicast, 993 .configure_filter = wcn36xx_configure_filter, 994 .tx = wcn36xx_tx, 995 .set_key = wcn36xx_set_key, 996 .sw_scan_start = wcn36xx_sw_scan_start, 997 .sw_scan_complete = wcn36xx_sw_scan_complete, 998 .bss_info_changed = wcn36xx_bss_info_changed, 999 .set_rts_threshold = wcn36xx_set_rts_threshold, 1000 .sta_add = wcn36xx_sta_add, 1001 .sta_remove = wcn36xx_sta_remove, 1002 .ampdu_action = wcn36xx_ampdu_action, 1003 }; 1004 1005 static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) 1006 { 1007 int ret = 0; 1008 1009 static const u32 cipher_suites[] = { 1010 WLAN_CIPHER_SUITE_WEP40, 1011 WLAN_CIPHER_SUITE_WEP104, 1012 WLAN_CIPHER_SUITE_TKIP, 1013 WLAN_CIPHER_SUITE_CCMP, 1014 }; 1015 1016 ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY); 1017 ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION); 1018 ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR); 1019 ieee80211_hw_set(wcn->hw, SUPPORTS_PS); 1020 ieee80211_hw_set(wcn->hw, SIGNAL_DBM); 1021 ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL); 1022 1023 wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 1024 BIT(NL80211_IFTYPE_AP) | 1025 BIT(NL80211_IFTYPE_ADHOC) | 1026 BIT(NL80211_IFTYPE_MESH_POINT); 1027 1028 wcn->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wcn_band_2ghz; 1029 wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz; 1030 1031 wcn->hw->wiphy->cipher_suites = cipher_suites; 1032 wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); 1033 1034 wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; 1035 1036 #ifdef CONFIG_PM 1037 wcn->hw->wiphy->wowlan = &wowlan_support; 1038 #endif 1039 1040 wcn->hw->max_listen_interval = 200; 1041 1042 wcn->hw->queues = 4; 1043 1044 SET_IEEE80211_DEV(wcn->hw, wcn->dev); 1045 1046 wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta); 1047 wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif); 1048 1049 return ret; 1050 } 1051 1052 static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, 1053 struct platform_device *pdev) 1054 { 1055 struct device_node *mmio_node; 1056 struct resource *res; 1057 int index; 1058 int ret; 1059 1060 /* Set TX IRQ */ 1061 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 1062 "wcnss_wlantx_irq"); 1063 if (!res) { 1064 wcn36xx_err("failed to get tx_irq\n"); 1065 return -ENOENT; 1066 } 1067 wcn->tx_irq = res->start; 1068 1069 /* Set RX IRQ */ 1070 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 1071 "wcnss_wlanrx_irq"); 1072 if (!res) { 1073 wcn36xx_err("failed to get rx_irq\n"); 1074 return -ENOENT; 1075 } 1076 wcn->rx_irq = res->start; 1077 1078 mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0); 1079 if (!mmio_node) { 1080 wcn36xx_err("failed to acquire qcom,mmio reference\n"); 1081 return -EINVAL; 1082 } 1083 1084 wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto"); 1085 1086 /* Map the CCU memory */ 1087 index = of_property_match_string(mmio_node, "reg-names", "ccu"); 1088 wcn->ccu_base = of_iomap(mmio_node, index); 1089 if (!wcn->ccu_base) { 1090 wcn36xx_err("failed to map ccu memory\n"); 1091 ret = -ENOMEM; 1092 goto put_mmio_node; 1093 } 1094 1095 /* Map the DXE memory */ 1096 index = of_property_match_string(mmio_node, "reg-names", "dxe"); 1097 wcn->dxe_base = of_iomap(mmio_node, index); 1098 if (!wcn->dxe_base) { 1099 wcn36xx_err("failed to map dxe memory\n"); 1100 ret = -ENOMEM; 1101 goto unmap_ccu; 1102 } 1103 1104 of_node_put(mmio_node); 1105 return 0; 1106 1107 unmap_ccu: 1108 iounmap(wcn->ccu_base); 1109 put_mmio_node: 1110 of_node_put(mmio_node); 1111 return ret; 1112 } 1113 1114 static int wcn36xx_probe(struct platform_device *pdev) 1115 { 1116 struct ieee80211_hw *hw; 1117 struct wcn36xx *wcn; 1118 int ret; 1119 u8 addr[ETH_ALEN]; 1120 1121 wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n"); 1122 1123 hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops); 1124 if (!hw) { 1125 wcn36xx_err("failed to alloc hw\n"); 1126 ret = -ENOMEM; 1127 goto out_err; 1128 } 1129 platform_set_drvdata(pdev, hw); 1130 wcn = hw->priv; 1131 wcn->hw = hw; 1132 wcn->dev = &pdev->dev; 1133 wcn->ctrl_ops = pdev->dev.platform_data; 1134 1135 mutex_init(&wcn->hal_mutex); 1136 1137 if (!wcn->ctrl_ops->get_hw_mac(addr)) { 1138 wcn36xx_info("mac address: %pM\n", addr); 1139 SET_IEEE80211_PERM_ADDR(wcn->hw, addr); 1140 } 1141 1142 ret = wcn36xx_platform_get_resources(wcn, pdev); 1143 if (ret) 1144 goto out_wq; 1145 1146 wcn36xx_init_ieee80211(wcn); 1147 ret = ieee80211_register_hw(wcn->hw); 1148 if (ret) 1149 goto out_unmap; 1150 1151 return 0; 1152 1153 out_unmap: 1154 iounmap(wcn->ccu_base); 1155 iounmap(wcn->dxe_base); 1156 out_wq: 1157 ieee80211_free_hw(hw); 1158 out_err: 1159 return ret; 1160 } 1161 static int wcn36xx_remove(struct platform_device *pdev) 1162 { 1163 struct ieee80211_hw *hw = platform_get_drvdata(pdev); 1164 struct wcn36xx *wcn = hw->priv; 1165 wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n"); 1166 1167 release_firmware(wcn->nv); 1168 mutex_destroy(&wcn->hal_mutex); 1169 1170 ieee80211_unregister_hw(hw); 1171 iounmap(wcn->dxe_base); 1172 iounmap(wcn->ccu_base); 1173 ieee80211_free_hw(hw); 1174 1175 return 0; 1176 } 1177 static const struct platform_device_id wcn36xx_platform_id_table[] = { 1178 { 1179 .name = "wcn36xx", 1180 .driver_data = 0 1181 }, 1182 {} 1183 }; 1184 MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table); 1185 1186 static struct platform_driver wcn36xx_driver = { 1187 .probe = wcn36xx_probe, 1188 .remove = wcn36xx_remove, 1189 .driver = { 1190 .name = "wcn36xx", 1191 }, 1192 .id_table = wcn36xx_platform_id_table, 1193 }; 1194 1195 static int __init wcn36xx_init(void) 1196 { 1197 platform_driver_register(&wcn36xx_driver); 1198 return 0; 1199 } 1200 module_init(wcn36xx_init); 1201 1202 static void __exit wcn36xx_exit(void) 1203 { 1204 platform_driver_unregister(&wcn36xx_driver); 1205 } 1206 module_exit(wcn36xx_exit); 1207 1208 MODULE_LICENSE("Dual BSD/GPL"); 1209 MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com"); 1210 MODULE_FIRMWARE(WLAN_NV_FILE); 1211