| .. | .. |
|---|
| 19 | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 20 | 20 | * General Public License for more details. |
|---|
| 21 | 21 | * |
|---|
| 22 | | - * You should have received a copy of the GNU General Public License |
|---|
| 23 | | - * along with this program; if not, write to the Free Software |
|---|
| 24 | | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, |
|---|
| 25 | | - * USA |
|---|
| 26 | | - * |
|---|
| 27 | 22 | * The full GNU General Public License is included in this distribution |
|---|
| 28 | 23 | * in the file called COPYING. |
|---|
| 29 | 24 | * |
|---|
| .. | .. |
|---|
| 183 | 178 | } else { |
|---|
| 184 | 179 | IWL_DEBUG_EEPROM(mvm->trans->dev, |
|---|
| 185 | 180 | "NVM access command failed with status %d (device: %s)\n", |
|---|
| 186 | | - ret, mvm->cfg->name); |
|---|
| 187 | | - ret = -EIO; |
|---|
| 181 | + ret, mvm->trans->name); |
|---|
| 182 | + ret = -ENODATA; |
|---|
| 188 | 183 | } |
|---|
| 189 | 184 | goto exit; |
|---|
| 190 | 185 | } |
|---|
| .. | .. |
|---|
| 254 | 249 | while (ret == length) { |
|---|
| 255 | 250 | /* Check no memory assumptions fail and cause an overflow */ |
|---|
| 256 | 251 | if ((size_read + offset + length) > |
|---|
| 257 | | - mvm->cfg->base_params->eeprom_size) { |
|---|
| 252 | + mvm->trans->trans_cfg->base_params->eeprom_size) { |
|---|
| 258 | 253 | IWL_ERR(mvm, "EEPROM size is too small for NVM\n"); |
|---|
| 259 | 254 | return -ENOBUFS; |
|---|
| 260 | 255 | } |
|---|
| .. | .. |
|---|
| 282 | 277 | struct iwl_nvm_section *sections = mvm->nvm_sections; |
|---|
| 283 | 278 | const __be16 *hw; |
|---|
| 284 | 279 | const __le16 *sw, *calib, *regulatory, *mac_override, *phy_sku; |
|---|
| 285 | | - bool lar_enabled; |
|---|
| 286 | 280 | int regulatory_type; |
|---|
| 287 | 281 | |
|---|
| 288 | 282 | /* Checking for required sections */ |
|---|
| .. | .. |
|---|
| 333 | 327 | (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY_SDP].data : |
|---|
| 334 | 328 | (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; |
|---|
| 335 | 329 | |
|---|
| 336 | | - lar_enabled = !iwlwifi_mod_params.lar_disable && |
|---|
| 337 | | - fw_has_capa(&mvm->fw->ucode_capa, |
|---|
| 338 | | - IWL_UCODE_TLV_CAPA_LAR_SUPPORT); |
|---|
| 339 | | - |
|---|
| 340 | | - return iwl_parse_nvm_data(mvm->trans, mvm->cfg, hw, sw, calib, |
|---|
| 330 | + return iwl_parse_nvm_data(mvm->trans, mvm->cfg, mvm->fw, hw, sw, calib, |
|---|
| 341 | 331 | regulatory, mac_override, phy_sku, |
|---|
| 342 | | - mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, |
|---|
| 343 | | - lar_enabled); |
|---|
| 332 | + mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant); |
|---|
| 344 | 333 | } |
|---|
| 345 | 334 | |
|---|
| 346 | 335 | /* Loads the NVM data stored in mvm->nvm_sections into the NIC */ |
|---|
| .. | .. |
|---|
| 378 | 367 | /* Read From FW NVM */ |
|---|
| 379 | 368 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); |
|---|
| 380 | 369 | |
|---|
| 381 | | - nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, |
|---|
| 370 | + nvm_buffer = kmalloc(mvm->trans->trans_cfg->base_params->eeprom_size, |
|---|
| 382 | 371 | GFP_KERNEL); |
|---|
| 383 | 372 | if (!nvm_buffer) |
|---|
| 384 | 373 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 386 | 375 | /* we override the constness for initial read */ |
|---|
| 387 | 376 | ret = iwl_nvm_read_section(mvm, section, nvm_buffer, |
|---|
| 388 | 377 | size_read); |
|---|
| 389 | | - if (ret < 0) |
|---|
| 378 | + if (ret == -ENODATA) { |
|---|
| 379 | + ret = 0; |
|---|
| 390 | 380 | continue; |
|---|
| 381 | + } |
|---|
| 382 | + if (ret < 0) |
|---|
| 383 | + break; |
|---|
| 391 | 384 | size_read += ret; |
|---|
| 392 | 385 | temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); |
|---|
| 393 | 386 | if (!temp) { |
|---|
| .. | .. |
|---|
| 417 | 410 | case NVM_SECTION_TYPE_PHY_SKU: |
|---|
| 418 | 411 | mvm->nvm_phy_sku_blob.data = temp; |
|---|
| 419 | 412 | mvm->nvm_phy_sku_blob.size = ret; |
|---|
| 413 | + break; |
|---|
| 414 | + case NVM_SECTION_TYPE_REGULATORY_SDP: |
|---|
| 415 | + case NVM_SECTION_TYPE_REGULATORY: |
|---|
| 416 | + mvm->nvm_reg_blob.data = temp; |
|---|
| 417 | + mvm->nvm_reg_blob.size = ret; |
|---|
| 420 | 418 | break; |
|---|
| 421 | 419 | default: |
|---|
| 422 | 420 | if (section == mvm->cfg->nvm_hw_section_num) { |
|---|
| .. | .. |
|---|
| 460 | 458 | IWL_DEBUG_EEPROM(mvm->trans->dev, "nvm version = %x\n", |
|---|
| 461 | 459 | mvm->nvm_data->nvm_version); |
|---|
| 462 | 460 | |
|---|
| 463 | | - return 0; |
|---|
| 461 | + return ret < 0 ? ret : 0; |
|---|
| 464 | 462 | } |
|---|
| 465 | 463 | |
|---|
| 466 | 464 | struct iwl_mcc_update_resp * |
|---|
| .. | .. |
|---|
| 483 | 481 | u32 status; |
|---|
| 484 | 482 | int resp_len, n_channels; |
|---|
| 485 | 483 | u16 mcc; |
|---|
| 486 | | - bool resp_v2 = fw_has_capa(&mvm->fw->ucode_capa, |
|---|
| 487 | | - IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2); |
|---|
| 488 | 484 | |
|---|
| 489 | 485 | if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) |
|---|
| 490 | 486 | return ERR_PTR(-EOPNOTSUPP); |
|---|
| 491 | 487 | |
|---|
| 492 | 488 | cmd.len[0] = sizeof(struct iwl_mcc_update_cmd); |
|---|
| 493 | | - if (!resp_v2) |
|---|
| 494 | | - cmd.len[0] = sizeof(struct iwl_mcc_update_cmd_v1); |
|---|
| 495 | 489 | |
|---|
| 496 | 490 | IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n", |
|---|
| 497 | 491 | alpha2[0], alpha2[1], src_id); |
|---|
| .. | .. |
|---|
| 503 | 497 | pkt = cmd.resp_pkt; |
|---|
| 504 | 498 | |
|---|
| 505 | 499 | /* Extract MCC response */ |
|---|
| 506 | | - if (resp_v2) { |
|---|
| 500 | + if (fw_has_capa(&mvm->fw->ucode_capa, |
|---|
| 501 | + IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { |
|---|
| 507 | 502 | struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data; |
|---|
| 508 | 503 | |
|---|
| 509 | 504 | n_channels = __le32_to_cpu(mcc_resp->n_channels); |
|---|
| 505 | + if (iwl_rx_packet_payload_len(pkt) != |
|---|
| 506 | + struct_size(mcc_resp, channels, n_channels)) { |
|---|
| 507 | + resp_cp = ERR_PTR(-EINVAL); |
|---|
| 508 | + goto exit; |
|---|
| 509 | + } |
|---|
| 510 | 510 | resp_len = sizeof(struct iwl_mcc_update_resp) + |
|---|
| 511 | 511 | n_channels * sizeof(__le32); |
|---|
| 512 | 512 | resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 515 | 515 | goto exit; |
|---|
| 516 | 516 | } |
|---|
| 517 | 517 | } else { |
|---|
| 518 | | - struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data; |
|---|
| 518 | + struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data; |
|---|
| 519 | 519 | |
|---|
| 520 | | - n_channels = __le32_to_cpu(mcc_resp_v1->n_channels); |
|---|
| 520 | + n_channels = __le32_to_cpu(mcc_resp_v3->n_channels); |
|---|
| 521 | + if (iwl_rx_packet_payload_len(pkt) != |
|---|
| 522 | + struct_size(mcc_resp_v3, channels, n_channels)) { |
|---|
| 523 | + resp_cp = ERR_PTR(-EINVAL); |
|---|
| 524 | + goto exit; |
|---|
| 525 | + } |
|---|
| 521 | 526 | resp_len = sizeof(struct iwl_mcc_update_resp) + |
|---|
| 522 | 527 | n_channels * sizeof(__le32); |
|---|
| 523 | 528 | resp_cp = kzalloc(resp_len, GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 526 | 531 | goto exit; |
|---|
| 527 | 532 | } |
|---|
| 528 | 533 | |
|---|
| 529 | | - resp_cp->status = mcc_resp_v1->status; |
|---|
| 530 | | - resp_cp->mcc = mcc_resp_v1->mcc; |
|---|
| 531 | | - resp_cp->cap = mcc_resp_v1->cap; |
|---|
| 532 | | - resp_cp->source_id = mcc_resp_v1->source_id; |
|---|
| 533 | | - resp_cp->n_channels = mcc_resp_v1->n_channels; |
|---|
| 534 | | - memcpy(resp_cp->channels, mcc_resp_v1->channels, |
|---|
| 534 | + resp_cp->status = mcc_resp_v3->status; |
|---|
| 535 | + resp_cp->mcc = mcc_resp_v3->mcc; |
|---|
| 536 | + resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap); |
|---|
| 537 | + resp_cp->source_id = mcc_resp_v3->source_id; |
|---|
| 538 | + resp_cp->time = mcc_resp_v3->time; |
|---|
| 539 | + resp_cp->geo_info = mcc_resp_v3->geo_info; |
|---|
| 540 | + resp_cp->n_channels = mcc_resp_v3->n_channels; |
|---|
| 541 | + memcpy(resp_cp->channels, mcc_resp_v3->channels, |
|---|
| 535 | 542 | n_channels * sizeof(__le32)); |
|---|
| 536 | 543 | } |
|---|
| 537 | 544 | |
|---|
| .. | .. |
|---|
| 618 | 625 | enum iwl_mcc_source src; |
|---|
| 619 | 626 | char mcc[3]; |
|---|
| 620 | 627 | struct ieee80211_regdomain *regd; |
|---|
| 628 | + int wgds_tbl_idx; |
|---|
| 621 | 629 | |
|---|
| 622 | 630 | lockdep_assert_held(&mvm->mutex); |
|---|
| 623 | 631 | |
|---|
| .. | .. |
|---|
| 641 | 649 | if (IS_ERR_OR_NULL(regd)) |
|---|
| 642 | 650 | return; |
|---|
| 643 | 651 | |
|---|
| 652 | + wgds_tbl_idx = iwl_mvm_get_sar_geo_profile(mvm); |
|---|
| 653 | + if (wgds_tbl_idx < 0) |
|---|
| 654 | + IWL_DEBUG_INFO(mvm, "SAR WGDS is disabled (%d)\n", |
|---|
| 655 | + wgds_tbl_idx); |
|---|
| 656 | + else |
|---|
| 657 | + IWL_DEBUG_INFO(mvm, "SAR WGDS: geo profile %d is configured\n", |
|---|
| 658 | + wgds_tbl_idx); |
|---|
| 659 | + |
|---|
| 644 | 660 | regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); |
|---|
| 645 | 661 | kfree(regd); |
|---|
| 646 | 662 | } |
|---|