(This patch depends on the iwx NVM parser patch which I just sent
out previously. This patch won't apply otherwise.)

iwx(4) devices have a hardware component that can detect which country
it is running in. The firmware will then inform the driver about the
auto-detected regulatory domain.

Currently we don't see this notification due to a bug in our driver.
I have a fix for that other bug which I will send out separately.
If we do not handle the regulatory domain notification, this other
fix would result in messages like:
iwx0: unhandled firmware response 0xc9/0x20000008 rx ring 64[35]

For now, just print a message which shows the detected regulatory domain
if 'ifconfig iwx0 debug' is enabled. It is up to the driver whether it
wants to react to regulatory domain updates.

ok?

diff e883cbeb57aae26539e3cf9c73701c2e0d44bb50 
3387c0fc20f29323f58bb3abae4a685d2cca4969
blob - f99f211301ac2da8cc350549e9fc029852c971fb
blob + eaad5ad73abbd1d25eb5895de88cf48e731abfcc
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -392,6 +392,7 @@ int iwx_rm_sta_cmd(struct iwx_softc *, struct iwx_node
 int    iwx_fill_probe_req(struct iwx_softc *, struct iwx_scan_probe_req *);
 int    iwx_config_umac_scan(struct iwx_softc *);
 int    iwx_umac_scan(struct iwx_softc *, int);
+void   iwx_mcc_update(struct iwx_softc *, struct iwx_mcc_chub_notif *);
 uint8_t        iwx_ridx2rate(struct ieee80211_rateset *, int);
 int    iwx_rval2ridx(int);
 void   iwx_ack_rates(struct iwx_softc *, struct iwx_node *, int *, int *);
@@ -2709,12 +2710,15 @@ iwx_init_channel_map(struct iwx_softc *sc, uint16_t *c
                if (is_5ghz && !data->sku_cap_band_52GHz_enable)
                        ch_flags &= ~IWX_NVM_CHANNEL_VALID;
 
-               if (!(ch_flags & IWX_NVM_CHANNEL_VALID))
-                       continue;
-
                hw_value = nvm_channels[ch_idx];
                channel = &ic->ic_channels[hw_value];
 
+               if (!(ch_flags & IWX_NVM_CHANNEL_VALID)) {
+                       channel->ic_freq = 0;
+                       channel->ic_flags = 0;
+                       continue;
+               }
+
                if (!is_5ghz) {
                        flags = IEEE80211_CHAN_2GHZ;
                        channel->ic_flags
@@ -5245,6 +5249,24 @@ iwx_umac_scan(struct iwx_softc *sc, int bgscan)
        return err;
 }
 
+void
+iwx_mcc_update(struct iwx_softc *sc, struct iwx_mcc_chub_notif *notif)
+{
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = IC2IFP(ic);
+       char alpha2[3];
+
+       snprintf(alpha2, sizeof(alpha2), "%c%c",
+           (le16toh(notif->mcc) & 0xff00) >> 8, le16toh(notif->mcc) & 0xff);
+
+       if (ifp->if_flags & IFF_DEBUG) {
+               printf("%s: firmware has detected regulatory domain '%s' "
+                   "(0x%x)\n", DEVNAME(sc), alpha2, le16toh(notif->mcc));
+       }
+
+       /* TODO: Schedule a task to send MCC_UPDATE_CMD? */
+}
+
 uint8_t
 iwx_ridx2rate(struct ieee80211_rateset *rs, int ridx)
 {
@@ -6454,6 +6476,9 @@ iwx_send_update_mcc_cmd(struct iwx_softc *sc, const ch
                .flags = IWX_CMD_WANT_RESP,
                .data = { &mcc_cmd },
        };
+       struct iwx_rx_packet *pkt;
+       struct iwx_mcc_update_resp *resp;
+       size_t resp_len;
        int err;
 
        memset(&mcc_cmd, 0, sizeof(mcc_cmd));
@@ -6465,16 +6490,41 @@ iwx_send_update_mcc_cmd(struct iwx_softc *sc, const ch
                mcc_cmd.source_id = IWX_MCC_SOURCE_OLD_FW;
 
        hcmd.len[0] = sizeof(struct iwx_mcc_update_cmd);
-       hcmd.resp_pkt_len = sizeof(struct iwx_rx_packet) +
-           sizeof(struct iwx_mcc_update_resp);
+       hcmd.resp_pkt_len = IWX_CMD_RESP_MAX;
 
        err = iwx_send_cmd(sc, &hcmd);
        if (err)
                return err;
 
+       pkt = hcmd.resp_pkt;
+       if (!pkt || (pkt->hdr.flags & IWX_CMD_FAILED_MSK)) {
+               err = EIO;
+               goto out;
+       }
+
+       resp_len = iwx_rx_packet_payload_len(pkt);
+       if (resp_len < sizeof(*resp)) {
+               err = EIO;
+               goto out;
+       }
+
+       resp = (void *)pkt->data;
+       if (resp_len != sizeof(*resp) +
+           resp->n_channels * sizeof(resp->channels[0])) {
+               err = EIO;
+               goto out;
+       }
+
+       DPRINTF(("MCC status=0x%x mcc=0x%x cap=0x%x time=0x%x geo_info=0x%x 
source_id=0x%d n_channels=%u\n",
+           resp->status, resp->mcc, resp->cap, resp->time, resp->geo_info, 
resp->source_id, resp->n_channels));
+
+       /* Update channel map for net80211 and our scan configuration. */
+       iwx_init_channel_map(sc, NULL, resp->channels, resp->n_channels);
+
+out:
        iwx_free_resp(sc, &hcmd);
 
-       return 0;
+       return err;
 }
 
 int
@@ -7365,6 +7415,13 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
                        break;
                }
 
+               case IWX_MCC_CHUB_UPDATE_CMD: {
+                       struct iwx_mcc_chub_notif *notif;
+                       SYNC_RESP_STRUCT(notif, pkt);
+                       iwx_mcc_update(sc, notif);
+                       break;
+               }
+       
                case IWX_REPLY_ERROR: {
                        struct iwx_error_resp *resp;
                        SYNC_RESP_STRUCT(resp, pkt);
blob - 78db5d5caaa0372acb855950e4b50c6c6016ecb1
blob + d6c823fe64ce7509e69c5b4ec20fdfa8681cfb2d
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -1525,6 +1525,7 @@ struct iwx_tx_queue_cfg_rsp {
 
 /* Location Aware Regulatory */
 #define IWX_MCC_UPDATE_CMD     0xc8
+#define IWX_MCC_CHUB_UPDATE_CMD        0xc9
 
 /* BT Coex */
 #define IWX_BT_COEX_PRIO_TABLE 0xcc
@@ -6180,7 +6181,7 @@ struct iwx_bt_coex_cmd {
  * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
  * MCC in the cmd response will be the relevant MCC in the NVM.
  * @mcc: given mobile country code
- * @source_id: the source from where we got the MCC, see iwx_mcc_source
+ * @source_id: the source from where we got the MCC, see IWX_MCC_SOURCE_*
  * @reserved: reserved for alignment
  * @key: integrity key for MCC API OEM testing
  * @reserved2: reserved
@@ -6194,14 +6195,14 @@ struct iwx_mcc_update_cmd {
 } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */
 
 /**
- * iwx_mcc_update_resp - response to MCC_UPDATE_CMD.
+ * iwx_mcc_update_resp_v3 - response to MCC_UPDATE_CMD.
  * Contains the new channel control profile map, if changed, and the new MCC
  * (mobile country code).
  * The new MCC may be different than what was requested in MCC_UPDATE_CMD.
  * @status: see &enum iwx_mcc_update_status
  * @mcc: the new applied MCC
  * @cap: capabilities for all channels which matches the MCC
- * @source_id: the MCC source, see iwx_mcc_source
+ * @source_id: the MCC source, see IWX_MCC_SOURCE_*
  * @time: time elapsed from the MCC test start (in 30 seconds TU)
  * @reserved: reserved.
  * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
@@ -6209,16 +6210,87 @@ struct iwx_mcc_update_cmd {
  * @channels: channel control data map, DWORD for each channel. Only the first
  *     16bits are used.
  */
-struct iwx_mcc_update_resp {
+struct iwx_mcc_update_resp_v3 {
        uint32_t status;
        uint16_t mcc;
        uint8_t cap;
        uint8_t source_id;
        uint16_t time;
-       uint16_t reserved;
+       uint16_t geo_info;
        uint32_t n_channels;
        uint32_t channels[0];
-} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */
+} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */
+
+/**
+ * geographic information.
+ * @GEO_NO_INFO: no special info for this geo profile.
+ * @GEO_WMM_ETSI_5GHZ_INFO: this geo profile limits the WMM params
+ *     for the 5 GHz band.
+ */
+#define IWX_GEO_NO_INFO                        0
+#define IWX_GEO_WMM_ETSI_5GHZ_INFO (1 << 0)
+
+/**
+ * struct iwx_mcc_update_resp - response to MCC_UPDATE_CMD.
+ * Contains the new channel control profile map, if changed, and the new MCC
+ * (mobile country code).
+ * The new MCC may be different than what was requested in MCC_UPDATE_CMD.
+ * @status: see &enum iwl_mcc_update_status
+ * @mcc: the new applied MCC
+ * @cap: capabilities for all channels which matches the MCC
+ * @time: time elapsed from the MCC test start (in units of 30 seconds)
+ * @geo_info: geographic specific profile information
+ *     see IWX_GEO_*
+ * @source_id: the MCC source, see IWX_MCC_SOURCE_*
+ * @reserved: for four bytes alignment.
+ * @n_channels: number of channels in @channels_data.
+ * @channels: channel control data map, DWORD for each channel. Only the first
+ *     16bits are used.
+ */
+struct iwx_mcc_update_resp {
+       uint32_t status;
+       uint16_t mcc;
+       uint16_t cap;
+       uint16_t time;
+       uint16_t geo_info;
+       uint8_t source_id;
+       uint8_t reserved[3];
+       uint32_t n_channels;
+       uint32_t channels[0];
+} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */
+
+/**
+ * struct iwx_mcc_chub_notif - chub notifies of mcc change
+ * (MCC_CHUB_UPDATE_CMD = 0xc9)
+ * The Chub (Communication Hub, CommsHUB) is a HW component that connects to
+ * the cellular and connectivity cores that gets updates of the mcc, and
+ * notifies the ucode directly of any mcc change.
+ * The ucode requests the driver to request the device to update geographic
+ * regulatory  profile according to the given MCC (Mobile Country Code).
+ * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
+ * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
+ * MCC in the cmd response will be the relevant MCC in the NVM.
+ * @mcc: given mobile country code
+ * @source_id: identity of the change originator, see IWX_MCC_SOURCE_*
+ * @reserved1: reserved for alignment
+ */
+struct iwx_mcc_chub_notif {
+       uint16_t mcc;
+       uint8_t source_id;
+       uint8_t reserved1;
+} __packed; /* LAR_MCC_NOTIFY_S */
+
+enum iwx_mcc_update_status {
+       IWX_MCC_RESP_NEW_CHAN_PROFILE,
+       IWX_MCC_RESP_SAME_CHAN_PROFILE,
+       IWX_MCC_RESP_INVALID,
+       IWX_MCC_RESP_NVM_DISABLED,
+       IWX_MCC_RESP_ILLEGAL,
+       IWX_MCC_RESP_LOW_PRIORITY,
+       IWX_MCC_RESP_TEST_MODE_ACTIVE,
+       IWX_MCC_RESP_TEST_MODE_NOT_ACTIVE,
+       IWX_MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE,
+};
 
 #define IWX_MCC_SOURCE_OLD_FW                  0
 #define IWX_MCC_SOURCE_ME                      1

Reply via email to