aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEran Harary <eran.harary@intel.com>2015-02-08 04:41:43 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-03-12 03:57:30 -0400
commit8ba2d7a1dd5defd7a9cbc400004cc112fc9ff3b5 (patch)
tree3462d611cfb7ce7d766d2daafeeeafdd819cd0df
parent5711cac489d06cc9c3cdcd513c810b7148beb49d (diff)
iwlwifi: mvm: take the MAC address from HW registers
For some configurations, the driver should get the MAC address from the hardware registers and not from the regular locations. Since the parsing of the MAC address is the same regardless of its source, continue the regular code path (parsing) after we read the registers. Signed-off-by: Eran Harary <eran.harary@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c61
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h150
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c73
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c79
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c2
9 files changed, 225 insertions, 167 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 5ea381861d5d..81c2f4875d30 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -244,6 +244,7 @@ enum iwl_ucode_tlv_flag {
244 * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. 244 * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
245 * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time 245 * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
246 * longer than the passive one, which is essential for fragmented scan. 246 * longer than the passive one, which is essential for fragmented scan.
247 * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source.
247 * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR 248 * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR
248 * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, 249 * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command,
249 * regardless of the band or the number of the probes. FW will calculate 250 * regardless of the band or the number of the probes. FW will calculate
@@ -261,6 +262,7 @@ enum iwl_ucode_tlv_api {
261 IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), 262 IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
262 IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), 263 IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7),
263 IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), 264 IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
265 IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9),
264 IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), 266 IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10),
265 IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), 267 IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13),
266 IWL_UCODE_TLV_API_SCD_CFG = BIT(15), 268 IWL_UCODE_TLV_API_SCD_CFG = BIT(15),
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index d9423eda6ad9..54e447b9978c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -542,7 +542,8 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
542 const struct iwl_cfg *cfg, 542 const struct iwl_cfg *cfg,
543 struct iwl_nvm_data *data, 543 struct iwl_nvm_data *data,
544 const __le16 *mac_override, 544 const __le16 *mac_override,
545 const __le16 *nvm_hw) 545 const __le16 *nvm_hw,
546 u32 mac_addr0, u32 mac_addr1)
546{ 547{
547 const u8 *hw_addr; 548 const u8 *hw_addr;
548 549
@@ -566,48 +567,17 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
566 } 567 }
567 568
568 if (nvm_hw) { 569 if (nvm_hw) {
569 /* read the MAC address from OTP */ 570 /* read the MAC address from HW resisters */
570 if (!dev_is_pci(dev) || (data->nvm_version < 0xE08)) { 571 hw_addr = (const u8 *)&mac_addr0;
571 /* read the mac address from the WFPM location */ 572 data->hw_addr[0] = hw_addr[3];
572 hw_addr = (const u8 *)(nvm_hw + 573 data->hw_addr[1] = hw_addr[2];
573 HW_ADDR0_WFPM_FAMILY_8000); 574 data->hw_addr[2] = hw_addr[1];
574 data->hw_addr[0] = hw_addr[3]; 575 data->hw_addr[3] = hw_addr[0];
575 data->hw_addr[1] = hw_addr[2]; 576
576 data->hw_addr[2] = hw_addr[1]; 577 hw_addr = (const u8 *)&mac_addr1;
577 data->hw_addr[3] = hw_addr[0]; 578 data->hw_addr[4] = hw_addr[1];
578 579 data->hw_addr[5] = hw_addr[0];
579 hw_addr = (const u8 *)(nvm_hw + 580
580 HW_ADDR1_WFPM_FAMILY_8000);
581 data->hw_addr[4] = hw_addr[1];
582 data->hw_addr[5] = hw_addr[0];
583 } else if ((data->nvm_version >= 0xE08) &&
584 (data->nvm_version < 0xE0B)) {
585 /* read "reverse order" from the PCIe location */
586 hw_addr = (const u8 *)(nvm_hw +
587 HW_ADDR0_PCIE_FAMILY_8000);
588 data->hw_addr[5] = hw_addr[2];
589 data->hw_addr[4] = hw_addr[1];
590 data->hw_addr[3] = hw_addr[0];
591
592 hw_addr = (const u8 *)(nvm_hw +
593 HW_ADDR1_PCIE_FAMILY_8000);
594 data->hw_addr[2] = hw_addr[3];
595 data->hw_addr[1] = hw_addr[2];
596 data->hw_addr[0] = hw_addr[1];
597 } else {
598 /* read from the PCIe location */
599 hw_addr = (const u8 *)(nvm_hw +
600 HW_ADDR0_PCIE_FAMILY_8000);
601 data->hw_addr[5] = hw_addr[0];
602 data->hw_addr[4] = hw_addr[1];
603 data->hw_addr[3] = hw_addr[2];
604
605 hw_addr = (const u8 *)(nvm_hw +
606 HW_ADDR1_PCIE_FAMILY_8000);
607 data->hw_addr[2] = hw_addr[1];
608 data->hw_addr[1] = hw_addr[2];
609 data->hw_addr[0] = hw_addr[3];
610 }
611 if (!is_valid_ether_addr(data->hw_addr)) 581 if (!is_valid_ether_addr(data->hw_addr))
612 IWL_ERR_DEV(dev, 582 IWL_ERR_DEV(dev,
613 "mac address from hw section is not valid\n"); 583 "mac address from hw section is not valid\n");
@@ -624,7 +594,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
624 const __le16 *nvm_calib, const __le16 *regulatory, 594 const __le16 *nvm_calib, const __le16 *regulatory,
625 const __le16 *mac_override, const __le16 *phy_sku, 595 const __le16 *mac_override, const __le16 *phy_sku,
626 u8 tx_chains, u8 rx_chains, 596 u8 tx_chains, u8 rx_chains,
627 bool lar_fw_supported, bool is_family_8000_a_step) 597 bool lar_fw_supported, bool is_family_8000_a_step,
598 u32 mac_addr0, u32 mac_addr1)
628{ 599{
629 struct iwl_nvm_data *data; 600 struct iwl_nvm_data *data;
630 u32 sku; 601 u32 sku;
@@ -692,7 +663,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
692 663
693 /* MAC address in family 8000 */ 664 /* MAC address in family 8000 */
694 iwl_set_hw_address_family_8000(dev, cfg, data, mac_override, 665 iwl_set_hw_address_family_8000(dev, cfg, data, mac_override,
695 nvm_hw); 666 nvm_hw, mac_addr0, mac_addr1);
696 667
697 iwl_init_sbands(dev, cfg, data, regulatory, 668 iwl_init_sbands(dev, cfg, data, regulatory,
698 tx_chains, rx_chains, 669 tx_chains, rx_chains,
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
index 18c3ff2c5593..c995d2cee3f6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
@@ -79,7 +79,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
79 const __le16 *nvm_calib, const __le16 *regulatory, 79 const __le16 *nvm_calib, const __le16 *regulatory,
80 const __le16 *mac_override, const __le16 *phy_sku, 80 const __le16 *mac_override, const __le16 *phy_sku,
81 u8 tx_chains, u8 rx_chains, 81 u8 tx_chains, u8 rx_chains,
82 bool lar_fw_supported, bool is_family_8000_a_step); 82 bool lar_fw_supported, bool is_family_8000_a_step,
83 u32 mac_addr0, u32 mac_addr1);
83 84
84/** 85/**
85 * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW 86 * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 6095088b88d9..383af2749d9a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -371,6 +371,14 @@ enum secure_load_status_reg {
371 371
372#define DBGC_IN_SAMPLE (0xa03c00) 372#define DBGC_IN_SAMPLE (0xa03c00)
373 373
374/* enable the ID buf for read */
375#define WFPM_PS_CTL_CLR 0xA0300C
376#define WFMP_MAC_ADDR_0 0xA03080
377#define WFMP_MAC_ADDR_1 0xA03084
378#define LMPM_PMG_EN 0xA01CEC
379#define RADIO_REG_SYS_MANUAL_DFT_0 0xAD4078
380#define RFIC_REG_RD 0xAD0470
381
374/* FW chicken bits */ 382/* FW chicken bits */
375#define LMPM_CHICK 0xA01FF8 383#define LMPM_CHICK 0xA01FF8
376enum { 384enum {
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index f514fae017d1..7e4936585544 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -1478,6 +1478,92 @@ struct iwl_sf_cfg_cmd {
1478 __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; 1478 __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
1479} __packed; /* SF_CFG_API_S_VER_2 */ 1479} __packed; /* SF_CFG_API_S_VER_2 */
1480 1480
1481/***********************************
1482 * Location Aware Regulatory (LAR) API - MCC updates
1483 ***********************************/
1484
1485/**
1486 * struct iwl_mcc_update_cmd - Request the device to update geographic
1487 * regulatory profile according to the given MCC (Mobile Country Code).
1488 * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
1489 * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
1490 * MCC in the cmd response will be the relevant MCC in the NVM.
1491 * @mcc: given mobile country code
1492 * @source_id: the source from where we got the MCC, see iwl_mcc_source
1493 * @reserved: reserved for alignment
1494 */
1495struct iwl_mcc_update_cmd {
1496 __le16 mcc;
1497 u8 source_id;
1498 u8 reserved;
1499} __packed; /* LAR_UPDATE_MCC_CMD_API_S */
1500
1501/**
1502 * iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
1503 * Contains the new channel control profile map, if changed, and the new MCC
1504 * (mobile country code).
1505 * The new MCC may be different than what was requested in MCC_UPDATE_CMD.
1506 * @status: 0 for success, 1 no change in channel profile, 2 invalid input.
1507 * @mcc: the new applied MCC
1508 * @cap: capabilities for all channels which matches the MCC
1509 * @source_id: the MCC source, see iwl_mcc_source
1510 * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
1511 * channels, depending on platform)
1512 * @channels: channel control data map, DWORD for each channel. Only the first
1513 * 16bits are used.
1514 */
1515struct iwl_mcc_update_resp {
1516 __le32 status;
1517 __le16 mcc;
1518 u8 cap;
1519 u8 source_id;
1520 __le32 n_channels;
1521 __le32 channels[0];
1522} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */
1523
1524/**
1525 * struct iwl_mcc_chub_notif - chub notifies of mcc change
1526 * (MCC_CHUB_UPDATE_CMD = 0xc9)
1527 * The Chub (Communication Hub, CommsHUB) is a HW component that connects to
1528 * the cellular and connectivity cores that gets updates of the mcc, and
1529 * notifies the ucode directly of any mcc change.
1530 * The ucode requests the driver to request the device to update geographic
1531 * regulatory profile according to the given MCC (Mobile Country Code).
1532 * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
1533 * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
1534 * MCC in the cmd response will be the relevant MCC in the NVM.
1535 * @mcc: given mobile country code
1536 * @source_id: identity of the change originator, see iwl_mcc_source
1537 * @reserved1: reserved for alignment
1538 */
1539struct iwl_mcc_chub_notif {
1540 u16 mcc;
1541 u8 source_id;
1542 u8 reserved1;
1543} __packed; /* LAR_MCC_NOTIFY_S */
1544
1545enum iwl_mcc_update_status {
1546 MCC_RESP_NEW_CHAN_PROFILE,
1547 MCC_RESP_SAME_CHAN_PROFILE,
1548 MCC_RESP_INVALID,
1549 MCC_RESP_NVM_DISABLED,
1550 MCC_RESP_ILLEGAL,
1551 MCC_RESP_LOW_PRIORITY,
1552};
1553
1554enum iwl_mcc_source {
1555 MCC_SOURCE_OLD_FW = 0,
1556 MCC_SOURCE_ME = 1,
1557 MCC_SOURCE_BIOS = 2,
1558 MCC_SOURCE_3G_LTE_HOST = 3,
1559 MCC_SOURCE_3G_LTE_DEVICE = 4,
1560 MCC_SOURCE_WIFI = 5,
1561 MCC_SOURCE_RESERVED = 6,
1562 MCC_SOURCE_DEFAULT = 7,
1563 MCC_SOURCE_UNINITIALIZED = 8,
1564 MCC_SOURCE_GET_CURRENT = 0x10
1565};
1566
1481/* DTS measurements */ 1567/* DTS measurements */
1482 1568
1483enum iwl_dts_measurement_flags { 1569enum iwl_dts_measurement_flags {
@@ -1679,68 +1765,4 @@ struct iwl_shared_mem_cfg {
1679 __le32 page_buff_size; 1765 __le32 page_buff_size;
1680} __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */ 1766} __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */
1681 1767
1682/***********************************
1683 * Location Aware Regulatory (LAR) API - MCC updates
1684 ***********************************/
1685
1686/**
1687 * struct iwl_mcc_update_cmd - Request the device to update geographic
1688 * regulatory profile according to the given MCC (Mobile Country Code).
1689 * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
1690 * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
1691 * MCC in the cmd response will be the relevant MCC in the NVM.
1692 * @mcc: given mobile country code
1693 * @reserved: reserved for alignment
1694 */
1695struct iwl_mcc_update_cmd {
1696 __le16 mcc;
1697 __le16 reserved;
1698} __packed; /* LAR_UPDATE_MCC_CMD_API_S */
1699
1700/**
1701 * iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
1702 * Contains the new channel control profile map, if changed, and the new MCC
1703 * (mobile country code).
1704 * The new MCC may be different than what was requested in MCC_UPDATE_CMD.
1705 * @status: 0 for success, 1 no change in channel profile, 2 invalid input.
1706 * @mcc: the new applied MCC
1707 * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
1708 * channels, depending on platform)
1709 * @channels: channel control data map, DWORD for each channel. Only the first
1710 * 16bits are used.
1711 */
1712struct iwl_mcc_update_resp {
1713 __le32 status;
1714 __le16 mcc;
1715 __le16 reserved;
1716 __le32 n_channels;
1717 __le32 channels[0];
1718} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */
1719
1720/**
1721 * struct iwl_mcc_chub_notif - chub notifies of mcc change
1722 * (MCC_CHUB_UPDATE_CMD = 0xc9)
1723 * The Chub (Communication Hub, CommsHUB) is a HW component that connects to
1724 * the cellular and connectivity cores that gets updates of the mcc, and
1725 * notifies the ucode directly of any mcc change.
1726 * The ucode requests the driver to request the device to update geographic
1727 * regulatory profile according to the given MCC (Mobile Country Code).
1728 * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
1729 * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
1730 * MCC in the cmd response will be the relevant MCC in the NVM.
1731 * @mcc: given mobile country code
1732 * @reserved: reserved for alignment
1733 */
1734struct iwl_mcc_chub_notif {
1735 u16 mcc;
1736 u16 reserved1;
1737} __packed; /* LAR_MCC_NOTIFY_S */
1738
1739enum iwl_mcc_update_status {
1740 MCC_RESP_NEW_CHAN_PROFILE,
1741 MCC_RESP_SAME_CHAN_PROFILE,
1742 MCC_RESP_INVALID,
1743 MCC_RESP_NVM_DISABLED,
1744};
1745
1746#endif /* __fw_api_h__ */ 1768#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 5dc3a9492d9a..303a7a0c6498 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -303,7 +303,8 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
303} 303}
304 304
305struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, 305struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
306 const char *alpha2) 306 const char *alpha2,
307 enum iwl_mcc_source src_id)
307{ 308{
308 struct ieee80211_regdomain *regd = NULL; 309 struct ieee80211_regdomain *regd = NULL;
309 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 310 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
@@ -312,39 +313,75 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
312 313
313 IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); 314 IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2);
314 315
315 mutex_lock(&mvm->mutex); 316 lockdep_assert_held(&mvm->mutex);
316
317 /* change "99" to "ZZ" for the FW */
318 if (alpha2[0] == '9' && alpha2[1] == '9')
319 alpha2 = "ZZ";
320 317
321 resp = iwl_mvm_update_mcc(mvm, alpha2); 318 resp = iwl_mvm_update_mcc(mvm, alpha2, src_id);
322 if (IS_ERR_OR_NULL(resp)) { 319 if (IS_ERR_OR_NULL(resp)) {
323 IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n", 320 IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",
324 PTR_RET(resp)); 321 PTR_RET(resp));
325 goto out_unlock; 322 goto out;
326 } 323 }
327 324
328 regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, 325 regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg,
329 __le32_to_cpu(resp->n_channels), 326 __le32_to_cpu(resp->n_channels),
330 resp->channels, 327 resp->channels,
331 __le16_to_cpu(resp->mcc)); 328 __le16_to_cpu(resp->mcc));
329 /* Store the return source id */
330 src_id = resp->source_id;
332 kfree(resp); 331 kfree(resp);
333 if (IS_ERR_OR_NULL(regd)) { 332 if (IS_ERR_OR_NULL(regd)) {
334 IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n", 333 IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",
335 PTR_RET(resp)); 334 PTR_RET(regd));
336 goto out_unlock; 335 goto out;
337 } 336 }
338 337
339 IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x)\n", 338 IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x) src=%d\n",
340 regd->alpha2, regd->alpha2[0], regd->alpha2[1]); 339 regd->alpha2, regd->alpha2[0], regd->alpha2[1], src_id);
341 mvm->lar_regdom_set = true; 340 mvm->lar_regdom_set = true;
341 mvm->mcc_src = src_id;
342 342
343out_unlock: 343out:
344 mutex_unlock(&mvm->mutex);
345 return regd; 344 return regd;
346} 345}
347 346
347struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm)
348{
349 return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ",
350 iwl_mvm_is_wifi_mcc_supported(mvm) ?
351 MCC_SOURCE_GET_CURRENT :
352 MCC_SOURCE_OLD_FW);
353}
354
355int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm)
356{
357 enum iwl_mcc_source used_src;
358 struct ieee80211_regdomain *regd;
359 const struct ieee80211_regdomain *r =
360 rtnl_dereference(mvm->hw->wiphy->regd);
361
362 if (!r)
363 return 0;
364
365 /* save the last source in case we overwrite it below */
366 used_src = mvm->mcc_src;
367 if (iwl_mvm_is_wifi_mcc_supported(mvm)) {
368 /* Notify the firmware we support wifi location updates */
369 regd = iwl_mvm_get_current_regdomain(mvm);
370 if (!IS_ERR_OR_NULL(regd))
371 kfree(regd);
372 }
373
374 /* Now set our last stored MCC and source */
375 regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src);
376 if (IS_ERR_OR_NULL(regd))
377 return -EIO;
378
379 regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
380 kfree(regd);
381
382 return 0;
383}
384
348int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) 385int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
349{ 386{
350 struct ieee80211_hw *hw = mvm->hw; 387 struct ieee80211_hw *hw = mvm->hw;
@@ -400,8 +437,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
400 BIT(NL80211_IFTYPE_ADHOC); 437 BIT(NL80211_IFTYPE_ADHOC);
401 438
402 hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 439 hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
403 hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | 440 hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR;
404 REGULATORY_DISABLE_BEACON_HINTS; 441 if (iwl_mvm_is_lar_supported(mvm))
442 hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
443 else
444 hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
445 REGULATORY_DISABLE_BEACON_HINTS;
405 446
406 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) 447 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD)
407 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 448 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 207c3a847ed4..5d5be372593a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -811,6 +811,7 @@ struct iwl_mvm {
811 u32 ap_last_beacon_gp2; 811 u32 ap_last_beacon_gp2;
812 812
813 bool lar_regdom_set; 813 bool lar_regdom_set;
814 enum iwl_mcc_source mcc_src;
814 815
815 u8 low_latency_agg_frame_limit; 816 u8 low_latency_agg_frame_limit;
816 817
@@ -931,6 +932,11 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
931 return tlv_lar; 932 return tlv_lar;
932} 933}
933 934
935static inline bool iwl_mvm_is_wifi_mcc_supported(struct iwl_mvm *mvm)
936{
937 return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WIFI_MCC_UPDATE;
938}
939
934static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) 940static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm)
935{ 941{
936 return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG; 942 return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG;
@@ -1412,13 +1418,17 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm);
1412 1418
1413/* Location Aware Regulatory */ 1419/* Location Aware Regulatory */
1414struct iwl_mcc_update_resp * 1420struct iwl_mcc_update_resp *
1415iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2); 1421iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
1422 enum iwl_mcc_source src_id);
1416int iwl_mvm_init_mcc(struct iwl_mvm *mvm); 1423int iwl_mvm_init_mcc(struct iwl_mvm *mvm);
1417int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, 1424int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
1418 struct iwl_rx_cmd_buffer *rxb, 1425 struct iwl_rx_cmd_buffer *rxb,
1419 struct iwl_device_cmd *cmd); 1426 struct iwl_device_cmd *cmd);
1420struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, 1427struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
1421 const char *alpha2); 1428 const char *alpha2,
1429 enum iwl_mcc_source src_id);
1430struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm);
1431int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm);
1422 1432
1423/* smart fifo */ 1433/* smart fifo */
1424int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 1434int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 5a16e0d79352..41189e5e98df 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -70,6 +70,7 @@
70#include "iwl-eeprom-parse.h" 70#include "iwl-eeprom-parse.h"
71#include "iwl-eeprom-read.h" 71#include "iwl-eeprom-read.h"
72#include "iwl-nvm-parse.h" 72#include "iwl-nvm-parse.h"
73#include "iwl-prph.h"
73 74
74/* Default NVM size to read */ 75/* Default NVM size to read */
75#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) 76#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
@@ -265,6 +266,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
265 struct iwl_nvm_section *sections = mvm->nvm_sections; 266 struct iwl_nvm_section *sections = mvm->nvm_sections;
266 const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; 267 const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku;
267 bool is_family_8000_a_step = false, lar_enabled; 268 bool is_family_8000_a_step = false, lar_enabled;
269 u32 mac_addr0, mac_addr1;
268 270
269 /* Checking for required sections */ 271 /* Checking for required sections */
270 if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { 272 if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
@@ -304,6 +306,10 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
304 if (WARN_ON(!mvm->cfg)) 306 if (WARN_ON(!mvm->cfg))
305 return NULL; 307 return NULL;
306 308
309 /* read the mac address from WFMP registers */
310 mac_addr0 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_0);
311 mac_addr1 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_1);
312
307 hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; 313 hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
308 sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; 314 sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
309 calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; 315 calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
@@ -319,7 +325,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
319 return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, 325 return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
320 regulatory, mac_override, phy_sku, 326 regulatory, mac_override, phy_sku,
321 mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, 327 mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant,
322 lar_enabled, is_family_8000_a_step); 328 lar_enabled, is_family_8000_a_step,
329 mac_addr0, mac_addr1);
323} 330}
324 331
325#define MAX_NVM_FILE_LEN 16384 332#define MAX_NVM_FILE_LEN 16384
@@ -590,10 +597,12 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
590} 597}
591 598
592struct iwl_mcc_update_resp * 599struct iwl_mcc_update_resp *
593iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2) 600iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
601 enum iwl_mcc_source src_id)
594{ 602{
595 struct iwl_mcc_update_cmd mcc_update_cmd = { 603 struct iwl_mcc_update_cmd mcc_update_cmd = {
596 .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), 604 .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]),
605 .source_id = (u8)src_id,
597 }; 606 };
598 struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL; 607 struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL;
599 struct iwl_rx_packet *pkt; 608 struct iwl_rx_packet *pkt;
@@ -613,8 +622,8 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2)
613 622
614 cmd.len[0] = sizeof(struct iwl_mcc_update_cmd); 623 cmd.len[0] = sizeof(struct iwl_mcc_update_cmd);
615 624
616 IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c'\n", 625 IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n",
617 alpha2[0], alpha2[1]); 626 alpha2[0], alpha2[1], src_id);
618 627
619 ret = iwl_mvm_send_cmd(mvm, &cmd); 628 ret = iwl_mvm_send_cmd(mvm, &cmd);
620 if (ret) 629 if (ret)
@@ -632,18 +641,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2)
632 mcc_resp = (void *)pkt->data; 641 mcc_resp = (void *)pkt->data;
633 status = le32_to_cpu(mcc_resp->status); 642 status = le32_to_cpu(mcc_resp->status);
634 643
635 if (status == MCC_RESP_INVALID) {
636 IWL_ERR(mvm,
637 "FW ERROR: MCC update with invalid parameter '%c%c'\n",
638 alpha2[0], alpha2[1]);
639 ret = -EINVAL;
640 goto exit;
641 } else if (status == MCC_RESP_NVM_DISABLED) {
642 ret = 0;
643 /* resp_cp will be NULL */
644 goto exit;
645 }
646
647 mcc = le16_to_cpu(mcc_resp->mcc); 644 mcc = le16_to_cpu(mcc_resp->mcc);
648 645
649 /* W/A for a FW/NVM issue - returns 0x00 for the world domain */ 646 /* W/A for a FW/NVM issue - returns 0x00 for the world domain */
@@ -677,6 +674,8 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
677{ 674{
678 bool tlv_lar; 675 bool tlv_lar;
679 bool nvm_lar; 676 bool nvm_lar;
677 int retval;
678 struct ieee80211_regdomain *regd;
680 679
681 if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) { 680 if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
682 tlv_lar = mvm->fw->ucode_capa.capa[0] & 681 tlv_lar = mvm->fw->ucode_capa.capa[0] &
@@ -698,32 +697,24 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
698 */ 697 */
699 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { 698 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
700 /* This should only be called during vif up and hold RTNL */ 699 /* This should only be called during vif up and hold RTNL */
701 const struct ieee80211_regdomain *r = 700 return iwl_mvm_init_fw_regd(mvm);
702 rtnl_dereference(mvm->hw->wiphy->regd);
703
704 if (r) {
705 struct iwl_mcc_update_resp *resp;
706
707 resp = iwl_mvm_update_mcc(mvm, r->alpha2);
708 if (IS_ERR_OR_NULL(resp))
709 return -EIO;
710
711 kfree(resp);
712 }
713
714 return 0;
715 } 701 }
716 702
717 /* 703 /*
718 * Driver regulatory hint for initial update - use the special 704 * Driver regulatory hint for initial update, this also informs the
719 * unknown-country "99" code. This will also clear the "custom reg" 705 * firmware we support wifi location updates.
720 * flag and allow regdomain changes. It will happen after init since
721 * RTNL is required.
722 * Disallow scans that might crash the FW while the LAR regdomain 706 * Disallow scans that might crash the FW while the LAR regdomain
723 * is not set. 707 * is not set.
724 */ 708 */
725 mvm->lar_regdom_set = false; 709 mvm->lar_regdom_set = false;
726 return 0; 710
711 regd = iwl_mvm_get_current_regdomain(mvm);
712 if (IS_ERR_OR_NULL(regd))
713 return -EIO;
714
715 retval = regulatory_set_wiphy_regd_sync_rtnl(mvm->hw->wiphy, regd);
716 kfree(regd);
717 return retval;
727} 718}
728 719
729int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, 720int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
@@ -732,17 +723,29 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
732{ 723{
733 struct iwl_rx_packet *pkt = rxb_addr(rxb); 724 struct iwl_rx_packet *pkt = rxb_addr(rxb);
734 struct iwl_mcc_chub_notif *notif = (void *)pkt->data; 725 struct iwl_mcc_chub_notif *notif = (void *)pkt->data;
726 enum iwl_mcc_source src;
735 char mcc[3]; 727 char mcc[3];
728 struct ieee80211_regdomain *regd;
729
730 lockdep_assert_held(&mvm->mutex);
736 731
737 if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) 732 if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
738 return -EOPNOTSUPP; 733 return 0;
739 734
740 mcc[0] = notif->mcc >> 8; 735 mcc[0] = notif->mcc >> 8;
741 mcc[1] = notif->mcc & 0xff; 736 mcc[1] = notif->mcc & 0xff;
742 mcc[2] = '\0'; 737 mcc[2] = '\0';
738 src = notif->source_id;
743 739
744 IWL_DEBUG_LAR(mvm, 740 IWL_DEBUG_LAR(mvm,
745 "RX: received chub update mcc command (mcc 0x%x '%s')\n", 741 "RX: received chub update mcc cmd (mcc '%s' src %d)\n",
746 notif->mcc, mcc); 742 mcc, src);
743 regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src);
744 if (IS_ERR_OR_NULL(regd))
745 return 0;
746
747 regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
748 kfree(regd);
749
747 return 0; 750 return 0;
748} 751}
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 1072f45720d6..c1de23cc07fd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -234,7 +234,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
234 iwl_mvm_rx_ant_coupling_notif, true), 234 iwl_mvm_rx_ant_coupling_notif, true),
235 235
236 RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), 236 RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
237 RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, false), 237 RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true),
238 238
239 RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), 239 RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false),
240 240