aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/nvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/nvm.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c290
1 files changed, 286 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 5383429d96c1..123e0a16aea8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -63,12 +63,16 @@
63 * 63 *
64 *****************************************************************************/ 64 *****************************************************************************/
65#include <linux/firmware.h> 65#include <linux/firmware.h>
66#include <linux/rtnetlink.h>
67#include <linux/pci.h>
68#include <linux/acpi.h>
66#include "iwl-trans.h" 69#include "iwl-trans.h"
67#include "iwl-csr.h" 70#include "iwl-csr.h"
68#include "mvm.h" 71#include "mvm.h"
69#include "iwl-eeprom-parse.h" 72#include "iwl-eeprom-parse.h"
70#include "iwl-eeprom-read.h" 73#include "iwl-eeprom-read.h"
71#include "iwl-nvm-parse.h" 74#include "iwl-nvm-parse.h"
75#include "iwl-prph.h"
72 76
73/* Default NVM size to read */ 77/* Default NVM size to read */
74#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) 78#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
@@ -262,7 +266,9 @@ static struct iwl_nvm_data *
262iwl_parse_nvm_sections(struct iwl_mvm *mvm) 266iwl_parse_nvm_sections(struct iwl_mvm *mvm)
263{ 267{
264 struct iwl_nvm_section *sections = mvm->nvm_sections; 268 struct iwl_nvm_section *sections = mvm->nvm_sections;
265 const __le16 *hw, *sw, *calib, *regulatory, *mac_override; 269 const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku;
270 bool is_family_8000_a_step = false, lar_enabled;
271 u32 mac_addr0, mac_addr1;
266 272
267 /* Checking for required sections */ 273 /* Checking for required sections */
268 if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { 274 if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
@@ -286,22 +292,43 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
286 "Can't parse mac_address, empty sections\n"); 292 "Can't parse mac_address, empty sections\n");
287 return NULL; 293 return NULL;
288 } 294 }
295
296 if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
297 is_family_8000_a_step = true;
298
299 /* PHY_SKU section is mandatory in B0 */
300 if (!is_family_8000_a_step &&
301 !mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) {
302 IWL_ERR(mvm,
303 "Can't parse phy_sku in B0, empty sections\n");
304 return NULL;
305 }
289 } 306 }
290 307
291 if (WARN_ON(!mvm->cfg)) 308 if (WARN_ON(!mvm->cfg))
292 return NULL; 309 return NULL;
293 310
311 /* read the mac address from WFMP registers */
312 mac_addr0 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_0);
313 mac_addr1 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_1);
314
294 hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; 315 hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
295 sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; 316 sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
296 calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; 317 calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
297 regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; 318 regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data;
298 mac_override = 319 mac_override =
299 (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data; 320 (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data;
321 phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data;
322
323 lar_enabled = !iwlwifi_mod_params.lar_disable &&
324 (mvm->fw->ucode_capa.capa[0] &
325 IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
300 326
301 return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, 327 return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
302 regulatory, mac_override, 328 regulatory, mac_override, phy_sku,
303 mvm->fw->valid_tx_ant, 329 mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant,
304 mvm->fw->valid_rx_ant); 330 lar_enabled, is_family_8000_a_step,
331 mac_addr0, mac_addr1);
305} 332}
306 333
307#define MAX_NVM_FILE_LEN 16384 334#define MAX_NVM_FILE_LEN 16384
@@ -570,3 +597,258 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
570 597
571 return 0; 598 return 0;
572} 599}
600
601struct iwl_mcc_update_resp *
602iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
603 enum iwl_mcc_source src_id)
604{
605 struct iwl_mcc_update_cmd mcc_update_cmd = {
606 .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]),
607 .source_id = (u8)src_id,
608 };
609 struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL;
610 struct iwl_rx_packet *pkt;
611 struct iwl_host_cmd cmd = {
612 .id = MCC_UPDATE_CMD,
613 .flags = CMD_WANT_SKB,
614 .data = { &mcc_update_cmd },
615 };
616
617 int ret;
618 u32 status;
619 int resp_len, n_channels;
620 u16 mcc;
621
622 if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
623 return ERR_PTR(-EOPNOTSUPP);
624
625 cmd.len[0] = sizeof(struct iwl_mcc_update_cmd);
626
627 IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n",
628 alpha2[0], alpha2[1], src_id);
629
630 ret = iwl_mvm_send_cmd(mvm, &cmd);
631 if (ret)
632 return ERR_PTR(ret);
633
634 pkt = cmd.resp_pkt;
635 if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
636 IWL_ERR(mvm, "Bad return from MCC_UPDATE_COMMAND (0x%08X)\n",
637 pkt->hdr.flags);
638 ret = -EIO;
639 goto exit;
640 }
641
642 /* Extract MCC response */
643 mcc_resp = (void *)pkt->data;
644 status = le32_to_cpu(mcc_resp->status);
645
646 mcc = le16_to_cpu(mcc_resp->mcc);
647
648 /* W/A for a FW/NVM issue - returns 0x00 for the world domain */
649 if (mcc == 0) {
650 mcc = 0x3030; /* "00" - world */
651 mcc_resp->mcc = cpu_to_le16(mcc);
652 }
653
654 n_channels = __le32_to_cpu(mcc_resp->n_channels);
655 IWL_DEBUG_LAR(mvm,
656 "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n",
657 status, mcc, mcc >> 8, mcc & 0xff,
658 !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels);
659
660 resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32);
661 resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
662 if (!resp_cp) {
663 ret = -ENOMEM;
664 goto exit;
665 }
666
667 ret = 0;
668exit:
669 iwl_free_resp(&cmd);
670 if (ret)
671 return ERR_PTR(ret);
672 return resp_cp;
673}
674
675#ifdef CONFIG_ACPI
676#define WRD_METHOD "WRDD"
677#define WRDD_WIFI (0x07)
678#define WRDD_WIGIG (0x10)
679
680static u32 iwl_mvm_wrdd_get_mcc(struct iwl_mvm *mvm, union acpi_object *wrdd)
681{
682 union acpi_object *mcc_pkg, *domain_type, *mcc_value;
683 u32 i;
684
685 if (wrdd->type != ACPI_TYPE_PACKAGE ||
686 wrdd->package.count < 2 ||
687 wrdd->package.elements[0].type != ACPI_TYPE_INTEGER ||
688 wrdd->package.elements[0].integer.value != 0) {
689 IWL_DEBUG_LAR(mvm, "Unsupported wrdd structure\n");
690 return 0;
691 }
692
693 for (i = 1 ; i < wrdd->package.count ; ++i) {
694 mcc_pkg = &wrdd->package.elements[i];
695
696 if (mcc_pkg->type != ACPI_TYPE_PACKAGE ||
697 mcc_pkg->package.count < 2 ||
698 mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
699 mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
700 mcc_pkg = NULL;
701 continue;
702 }
703
704 domain_type = &mcc_pkg->package.elements[0];
705 if (domain_type->integer.value == WRDD_WIFI)
706 break;
707
708 mcc_pkg = NULL;
709 }
710
711 if (mcc_pkg) {
712 mcc_value = &mcc_pkg->package.elements[1];
713 return mcc_value->integer.value;
714 }
715
716 return 0;
717}
718
719static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc)
720{
721 acpi_handle root_handle;
722 acpi_handle handle;
723 struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
724 acpi_status status;
725 u32 mcc_val;
726 struct pci_dev *pdev = to_pci_dev(mvm->dev);
727
728 root_handle = ACPI_HANDLE(&pdev->dev);
729 if (!root_handle) {
730 IWL_DEBUG_LAR(mvm,
731 "Could not retrieve root port ACPI handle\n");
732 return -ENOENT;
733 }
734
735 /* Get the method's handle */
736 status = acpi_get_handle(root_handle, (acpi_string)WRD_METHOD, &handle);
737 if (ACPI_FAILURE(status)) {
738 IWL_DEBUG_LAR(mvm, "WRD method not found\n");
739 return -ENOENT;
740 }
741
742 /* Call WRDD with no arguments */
743 status = acpi_evaluate_object(handle, NULL, NULL, &wrdd);
744 if (ACPI_FAILURE(status)) {
745 IWL_DEBUG_LAR(mvm, "WRDC invocation failed (0x%x)\n", status);
746 return -ENOENT;
747 }
748
749 mcc_val = iwl_mvm_wrdd_get_mcc(mvm, wrdd.pointer);
750 kfree(wrdd.pointer);
751 if (!mcc_val)
752 return -ENOENT;
753
754 mcc[0] = (mcc_val >> 8) & 0xff;
755 mcc[1] = mcc_val & 0xff;
756 mcc[2] = '\0';
757 return 0;
758}
759#else /* CONFIG_ACPI */
760static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc)
761{
762 return -ENOENT;
763}
764#endif
765
766int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
767{
768 bool tlv_lar;
769 bool nvm_lar;
770 int retval;
771 struct ieee80211_regdomain *regd;
772 char mcc[3];
773
774 if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
775 tlv_lar = mvm->fw->ucode_capa.capa[0] &
776 IWL_UCODE_TLV_CAPA_LAR_SUPPORT;
777 nvm_lar = mvm->nvm_data->lar_enabled;
778 if (tlv_lar != nvm_lar)
779 IWL_INFO(mvm,
780 "Conflict between TLV & NVM regarding enabling LAR (TLV = %s NVM =%s)\n",
781 tlv_lar ? "enabled" : "disabled",
782 nvm_lar ? "enabled" : "disabled");
783 }
784
785 if (!iwl_mvm_is_lar_supported(mvm))
786 return 0;
787
788 /*
789 * During HW restart, only replay the last set MCC to FW. Otherwise,
790 * queue an update to cfg80211 to retrieve the default alpha2 from FW.
791 */
792 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
793 /* This should only be called during vif up and hold RTNL */
794 return iwl_mvm_init_fw_regd(mvm);
795 }
796
797 /*
798 * Driver regulatory hint for initial update, this also informs the
799 * firmware we support wifi location updates.
800 * Disallow scans that might crash the FW while the LAR regdomain
801 * is not set.
802 */
803 mvm->lar_regdom_set = false;
804
805 regd = iwl_mvm_get_current_regdomain(mvm, NULL);
806 if (IS_ERR_OR_NULL(regd))
807 return -EIO;
808
809 if (iwl_mvm_is_wifi_mcc_supported(mvm) &&
810 !iwl_mvm_get_bios_mcc(mvm, mcc)) {
811 kfree(regd);
812 regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc,
813 MCC_SOURCE_BIOS, NULL);
814 if (IS_ERR_OR_NULL(regd))
815 return -EIO;
816 }
817
818 retval = regulatory_set_wiphy_regd_sync_rtnl(mvm->hw->wiphy, regd);
819 kfree(regd);
820 return retval;
821}
822
823int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
824 struct iwl_rx_cmd_buffer *rxb,
825 struct iwl_device_cmd *cmd)
826{
827 struct iwl_rx_packet *pkt = rxb_addr(rxb);
828 struct iwl_mcc_chub_notif *notif = (void *)pkt->data;
829 enum iwl_mcc_source src;
830 char mcc[3];
831 struct ieee80211_regdomain *regd;
832
833 lockdep_assert_held(&mvm->mutex);
834
835 if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
836 return 0;
837
838 mcc[0] = notif->mcc >> 8;
839 mcc[1] = notif->mcc & 0xff;
840 mcc[2] = '\0';
841 src = notif->source_id;
842
843 IWL_DEBUG_LAR(mvm,
844 "RX: received chub update mcc cmd (mcc '%s' src %d)\n",
845 mcc, src);
846 regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL);
847 if (IS_ERR_OR_NULL(regd))
848 return 0;
849
850 regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
851 kfree(regd);
852
853 return 0;
854}