diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2020-06-11 08:18:25 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2020-06-11 08:18:25 +0000 |
commit | 611bfd674abf3102fe58eb69bf63b22e384adc51 (patch) | |
tree | bfc9a4eb32f3724f5fc3ab7e004a01e194634593 | |
parent | 1ddb095354c5abc7ecf8c5b2822cca659bd4f3fc (diff) |
Add initial support for regulatory domain updates in iwx(4).
iwx(4) devices have a hardware component (the "communications hub")
that can detect which country it is running in. The firmware will
then inform the driver about the auto-detected regulatory domain.
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.
Tested by jcs@, sven falempin, and myself.
-rw-r--r-- | sys/dev/pci/if_iwx.c | 71 | ||||
-rw-r--r-- | sys/dev/pci/if_iwxreg.h | 86 |
2 files changed, 143 insertions, 14 deletions
diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c index 4673e5fef10..25e086f8d77 100644 --- a/sys/dev/pci/if_iwx.c +++ b/sys/dev/pci/if_iwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwx.c,v 1.22 2020/06/11 08:17:32 stsp Exp $ */ +/* $OpenBSD: if_iwx.c,v 1.23 2020/06/11 08:18:24 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh <info@genua.de> @@ -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 *channel_profile_v3, 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 char *alpha2) .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 char *alpha2) 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 *data, struct mbuf_list *ml) 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); diff --git a/sys/dev/pci/if_iwxreg.h b/sys/dev/pci/if_iwxreg.h index f8e2b22fa8b..978b1f91a6e 100644 --- a/sys/dev/pci/if_iwxreg.h +++ b/sys/dev/pci/if_iwxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwxreg.h,v 1.7 2020/06/11 08:17:32 stsp Exp $ */ +/* $OpenBSD: if_iwxreg.h,v 1.8 2020/06/11 08:18:24 stsp Exp $ */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, @@ -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_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_2 */ +} __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 |