summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2024-11-08 09:12:47 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2024-11-08 09:12:47 +0000
commit1ef4445c7bc0ab808a7082b106b0c58db5458d01 (patch)
tree6805e7acacef58888e4657d5b2b9d6f8c53f4aaa
parent80a557e14f0fc4aac1a920de028e43fb4b6259dd (diff)
Add support for MA devices.
ok stsp@
-rw-r--r--sys/dev/pci/if_iwx.c509
-rw-r--r--sys/dev/pci/if_iwxreg.h485
-rw-r--r--sys/dev/pci/if_iwxvar.h36
3 files changed, 999 insertions, 31 deletions
diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c
index f3c693a838c..6ff1a13167a 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.187 2024/06/26 01:40:49 jsg Exp $ */
+/* $OpenBSD: if_iwx.c,v 1.188 2024/11/08 09:12:46 kettenis Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -409,7 +409,9 @@ int iwx_power_update_device(struct iwx_softc *);
int iwx_enable_beacon_filter(struct iwx_softc *, struct iwx_node *);
int iwx_disable_beacon_filter(struct iwx_softc *);
int iwx_add_sta_cmd(struct iwx_softc *, struct iwx_node *, int);
+int iwx_mld_add_sta_cmd(struct iwx_softc *, struct iwx_node *, int);
int iwx_rm_sta_cmd(struct iwx_softc *, struct iwx_node *);
+int iwx_mld_rm_sta_cmd(struct iwx_softc *, struct iwx_node *);
int iwx_rm_sta(struct iwx_softc *, struct iwx_node *);
int iwx_fill_probe_req(struct iwx_softc *, struct iwx_scan_probe_req *);
int iwx_config_umac_scan_reduced(struct iwx_softc *);
@@ -430,6 +432,8 @@ void iwx_mac_ctxt_cmd_common(struct iwx_softc *, struct iwx_node *,
void iwx_mac_ctxt_cmd_fill_sta(struct iwx_softc *, struct iwx_node *,
struct iwx_mac_data_sta *, int);
int iwx_mac_ctxt_cmd(struct iwx_softc *, struct iwx_node *, uint32_t, int);
+int iwx_mld_mac_ctxt_cmd(struct iwx_softc *, struct iwx_node *, uint32_t,
+ int);
int iwx_clear_statistics(struct iwx_softc *);
void iwx_add_task(struct iwx_softc *, struct taskq *, struct task *);
void iwx_del_task(struct iwx_softc *, struct taskq *, struct task *);
@@ -2717,6 +2721,8 @@ iwx_stop_device(struct iwx_softc *sc)
iwx_ctxt_info_free_paging(sc);
iwx_dma_contig_free(&sc->pnvm_dma);
+ for (i = 0; i < sc->pnvm_segs; i++)
+ iwx_dma_contig_free(&sc->pnvm_seg_dma[i]);
}
void
@@ -4034,16 +4040,83 @@ iwx_start_fw(struct iwx_softc *sc)
}
int
+iwx_pnvm_setup_fragmented(struct iwx_softc *sc, uint8_t **pnvm_data,
+ size_t *pnvm_size, int pnvm_segs)
+{
+ struct iwx_pnvm_info_dram *pnvm_info;
+ int i, err;
+
+ err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->pnvm_dma,
+ sizeof(struct iwx_pnvm_info_dram), 0);
+ if (err)
+ return err;
+ pnvm_info = (struct iwx_pnvm_info_dram *)sc->pnvm_dma.vaddr;
+
+ for (i = 0; i < pnvm_segs; i++) {
+ err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->pnvm_seg_dma[i],
+ pnvm_size[i], 0);
+ if (err)
+ goto fail;
+ memcpy(sc->pnvm_seg_dma[i].vaddr, pnvm_data[i], pnvm_size[i]);
+ pnvm_info->pnvm_img[i] = htole64(sc->pnvm_seg_dma[i].paddr);
+ sc->pnvm_size += pnvm_size[i];
+ sc->pnvm_segs++;
+ }
+
+ return 0;
+
+fail:
+ for (i = 0; i < pnvm_segs; i++)
+ iwx_dma_contig_free(&sc->pnvm_seg_dma[i]);
+ sc->pnvm_size = 0;
+ sc->pnvm_segs = 0;
+ iwx_dma_contig_free(&sc->pnvm_dma);
+
+ return err;
+}
+
+int
+iwx_pnvm_setup(struct iwx_softc *sc, uint8_t **pnvm_data,
+ size_t *pnvm_size, int pnvm_segs)
+{
+ uint8_t *data;
+ size_t size = 0;
+ int i, err;
+
+ if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG))
+ return iwx_pnvm_setup_fragmented(sc, pnvm_data, pnvm_size, pnvm_segs);
+
+ for (i = 0; i < pnvm_segs; i++)
+ size += pnvm_size[i];
+
+ err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->pnvm_dma, size, 0);
+ if (err)
+ return err;
+
+ data = sc->pnvm_dma.vaddr;
+ for (i = 0; i < pnvm_segs; i++) {
+ memcpy(data, pnvm_data[i], pnvm_size[i]);
+ data += pnvm_size[i];
+ }
+ sc->pnvm_size = size;
+
+ return 0;
+}
+
+int
iwx_pnvm_handle_section(struct iwx_softc *sc, const uint8_t *data,
size_t len)
{
const struct iwx_ucode_tlv *tlv;
uint32_t sha1 = 0;
uint16_t mac_type = 0, rf_id = 0;
- uint8_t *pnvm_data = NULL, *tmp;
+ uint8_t *pnvm_data[IWX_MAX_DRAM_ENTRY];
+ size_t pnvm_size[IWX_MAX_DRAM_ENTRY];
+ int pnvm_segs = 0;
int hw_match = 0;
uint32_t size = 0;
int err;
+ int i;
while (len >= sizeof(*tlv)) {
uint32_t tlv_len, tlv_type;
@@ -4096,16 +4169,19 @@ iwx_pnvm_handle_section(struct iwx_softc *sc, const uint8_t *data,
if (le32_to_cpup((const uint32_t *)data) == 0xddddeeee)
break;
- tmp = malloc(size + data_len, M_DEVBUF,
+ if (pnvm_segs >= nitems(pnvm_data)) {
+ err = ERANGE;
+ goto out;
+ }
+
+ pnvm_data[pnvm_segs] = malloc(data_len, M_DEVBUF,
M_WAITOK | M_CANFAIL | M_ZERO);
- if (tmp == NULL) {
+ if (pnvm_data[pnvm_segs] == NULL) {
err = ENOMEM;
goto out;
}
- memcpy(tmp, pnvm_data, size);
- memcpy(tmp + size, section->data, data_len);
- free(pnvm_data, M_DEVBUF, size);
- pnvm_data = tmp;
+ memcpy(pnvm_data[pnvm_segs], section->data, data_len);
+ pnvm_size[pnvm_segs++] = data_len;
size += data_len;
break;
}
@@ -4127,18 +4203,19 @@ done:
goto out;
}
- err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->pnvm_dma, size, 0);
+ err = iwx_pnvm_setup(sc, pnvm_data, pnvm_size, pnvm_segs);
if (err) {
printf("%s: could not allocate DMA memory for PNVM\n",
DEVNAME(sc));
err = ENOMEM;
goto out;
}
- memcpy(sc->pnvm_dma.vaddr, pnvm_data, size);
+
iwx_ctxt_info_gen3_set_pnvm(sc);
sc->sc_pnvm_ver = sha1;
out:
- free(pnvm_data, M_DEVBUF, size);
+ for (i = 0; i < pnvm_segs; i++)
+ free(pnvm_data[i], M_DEVBUF, pnvm_size[i]);
return err;
}
@@ -4186,15 +4263,19 @@ iwx_ctxt_info_gen3_set_pnvm(struct iwx_softc *sc)
{
struct iwx_prph_scratch *prph_scratch;
struct iwx_prph_scratch_ctrl_cfg *prph_sc_ctrl;
+ int i;
prph_scratch = sc->prph_scratch_dma.vaddr;
prph_sc_ctrl = &prph_scratch->ctrl_cfg;
prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = htole64(sc->pnvm_dma.paddr);
- prph_sc_ctrl->pnvm_cfg.pnvm_size = htole32(sc->pnvm_dma.size);
+ prph_sc_ctrl->pnvm_cfg.pnvm_size = htole32(sc->pnvm_size);
- bus_dmamap_sync(sc->sc_dmat, sc->pnvm_dma.map, 0, sc->pnvm_dma.size,
- BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->sc_dmat, sc->pnvm_dma.map, 0,
+ sc->pnvm_dma.size, BUS_DMASYNC_PREWRITE);
+ for (i = 0; i < sc->pnvm_segs; i++)
+ bus_dmamap_sync(sc->sc_dmat, sc->pnvm_seg_dma[i].map, 0,
+ sc->pnvm_seg_dma[i].size, BUS_DMASYNC_PREWRITE);
}
/*
@@ -4392,6 +4473,16 @@ iwx_run_init_mvm_ucode(struct iwx_softc *sc, int readnvm)
sc->sc_nvm.hw_addr);
}
+
+ /*
+ * Only enable the MLD API on MA devices for now as the API 77
+ * firmware on some of the older firmware devices also claims
+ * support, but doesn't actually work.
+ */
+ if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_MLD_API_SUPPORT) &&
+ IWX_CSR_HW_REV_TYPE(sc->sc_hw_rev) == IWX_CFG_MAC_TYPE_MA)
+ sc->sc_use_mld_api = 1;
+
return 0;
}
@@ -5508,6 +5599,10 @@ iwx_binding_cmd(struct iwx_softc *sc, struct iwx_node *in, uint32_t action)
int i, err, active = (sc->sc_flags & IWX_FLAG_BINDING_ACTIVE);
uint32_t status;
+ /* No need to bind with MLD firmware. */
+ if (sc->sc_use_mld_api)
+ return 0;
+
if (action == IWX_FW_CTXT_ACTION_ADD && active)
panic("binding already added");
if (action == IWX_FW_CTXT_ACTION_REMOVE && !active)
@@ -6428,6 +6523,10 @@ iwx_drain_sta(struct iwx_softc *sc, struct iwx_node* in, int drain)
int err;
uint32_t status;
+ /* No need to drain with MLD firmware. */
+ if (sc->sc_use_mld_api)
+ return 0;
+
memset(&cmd, 0, sizeof(cmd));
cmd.mac_id_n_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id,
in->in_color));
@@ -6619,6 +6718,9 @@ iwx_add_sta_cmd(struct iwx_softc *sc, struct iwx_node *in, int update)
if (!update && (sc->sc_flags & IWX_FLAG_STA_ACTIVE))
panic("STA already added");
+ if (sc->sc_use_mld_api)
+ return iwx_mld_add_sta_cmd(sc, in, update);
+
memset(&add_sta_cmd, 0, sizeof(add_sta_cmd));
if (ic->ic_opmode == IEEE80211_M_MONITOR) {
@@ -6724,6 +6826,170 @@ iwx_add_sta_cmd(struct iwx_softc *sc, struct iwx_node *in, int update)
return err;
}
+void
+iwx_mld_modify_link_fill(struct iwx_softc *sc, struct iwx_node *in,
+ struct iwx_link_config_cmd *cmd, int changes, int active)
+{
+#define IWX_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni = &in->in_ni;
+ int cck_ack_rates, ofdm_ack_rates;
+ int i;
+
+ cmd->link_id = htole32(0);
+ cmd->mac_id = htole32(in->in_id);
+ KASSERT(in->in_phyctxt);
+ cmd->phy_id = htole32(in->in_phyctxt->id);
+ IEEE80211_ADDR_COPY(cmd->local_link_addr, ic->ic_myaddr);
+ cmd->active = htole32(active);
+
+ iwx_ack_rates(sc, in, &cck_ack_rates, &ofdm_ack_rates);
+ cmd->cck_rates = htole32(cck_ack_rates);
+ cmd->ofdm_rates = htole32(ofdm_ack_rates);
+ cmd->cck_short_preamble
+ = htole32((ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? 1 : 0);
+ cmd->short_slot
+ = htole32((ic->ic_flags & IEEE80211_F_SHSLOT) ? 1 : 0);
+
+ for (i = 0; i < EDCA_NUM_AC; i++) {
+ struct ieee80211_edca_ac_params *ac = &ic->ic_edca_ac[i];
+ int txf = iwx_ac_to_tx_fifo[i];
+
+ cmd->ac[txf].cw_min = htole16(IWX_EXP2(ac->ac_ecwmin));
+ cmd->ac[txf].cw_max = htole16(IWX_EXP2(ac->ac_ecwmax));
+ cmd->ac[txf].aifsn = ac->ac_aifsn;
+ cmd->ac[txf].fifos_mask = (1 << txf);
+ cmd->ac[txf].edca_txop = htole16(ac->ac_txoplimit * 32);
+ }
+ if (ni->ni_flags & IEEE80211_NODE_QOS)
+ cmd->qos_flags |= htole32(IWX_MAC_QOS_FLG_UPDATE_EDCA);
+
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ enum ieee80211_htprot htprot =
+ (ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
+ switch (htprot) {
+ case IEEE80211_HTPROT_NONE:
+ break;
+ case IEEE80211_HTPROT_NONMEMBER:
+ case IEEE80211_HTPROT_NONHT_MIXED:
+ cmd->protection_flags |=
+ htole32(IWX_LINK_PROT_FLG_HT_PROT |
+ IWX_LINK_PROT_FLG_FAT_PROT);
+ break;
+ case IEEE80211_HTPROT_20MHZ:
+ if (in->in_phyctxt &&
+ (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA ||
+ in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB)) {
+ cmd->protection_flags |=
+ htole32(IWX_LINK_PROT_FLG_HT_PROT |
+ IWX_LINK_PROT_FLG_FAT_PROT);
+ }
+ break;
+ default:
+ break;
+ }
+
+ cmd->qos_flags |= htole32(IWX_MAC_QOS_FLG_TGN);
+ }
+ if (ic->ic_flags & IEEE80211_F_USEPROT)
+ cmd->protection_flags |= htole32(IWX_LINK_PROT_FLG_TGG_PROTECT);
+
+ cmd->bi = htole32(ni->ni_intval);
+ cmd->dtim_interval = htole32(ni->ni_intval * ni->ni_dtimperiod);
+
+ cmd->modify_mask = htole32(changes);
+ cmd->flags = 0;
+ cmd->flags_mask = 0;
+ cmd->spec_link_id = 0;
+ cmd->listen_lmac = 0;
+ cmd->action = IWX_FW_CTXT_ACTION_MODIFY;
+#undef IWX_EXP2
+}
+
+int
+iwx_mld_add_sta_cmd(struct iwx_softc *sc, struct iwx_node *in, int update)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct iwx_link_config_cmd link_cmd;
+ struct iwx_mvm_sta_cfg_cmd sta_cmd;
+ uint32_t aggsize;
+ const uint32_t max_aggsize = (IWX_STA_FLG_MAX_AGG_SIZE_64K >>
+ IWX_STA_FLG_MAX_AGG_SIZE_SHIFT);
+ int err, changes;
+
+ if (!update) {
+ memset(&link_cmd, 0, sizeof(link_cmd));
+ link_cmd.link_id = htole32(0);
+ link_cmd.mac_id = htole32(in->in_id);
+ link_cmd.spec_link_id = 0;
+ if (in->in_phyctxt)
+ link_cmd.phy_id = htole32(in->in_phyctxt->id);
+ else
+ link_cmd.phy_id = htole32(IWX_FW_CTXT_INVALID);
+ IEEE80211_ADDR_COPY(link_cmd.local_link_addr, ic->ic_myaddr);
+ link_cmd.listen_lmac = 0;
+ link_cmd.action = IWX_FW_CTXT_ACTION_ADD;
+
+ err = iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_LINK_CONFIG_CMD),
+ 0, sizeof(link_cmd), &link_cmd);
+ if (err)
+ return err;
+ }
+
+ changes = IWX_LINK_CONTEXT_MODIFY_ACTIVE;
+ changes |= IWX_LINK_CONTEXT_MODIFY_RATES_INFO;
+ if (update) {
+ changes |= IWX_LINK_CONTEXT_MODIFY_PROTECT_FLAGS;
+ changes |= IWX_LINK_CONTEXT_MODIFY_QOS_PARAMS;
+ changes |= IWX_LINK_CONTEXT_MODIFY_BEACON_TIMING;
+ }
+
+ memset(&link_cmd, 0, sizeof(link_cmd));
+ iwx_mld_modify_link_fill(sc, in, &link_cmd, changes, 1);
+ err = iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_LINK_CONFIG_CMD),
+ 0, sizeof(link_cmd), &link_cmd);
+ if (err)
+ return err;
+
+ memset(&sta_cmd, 0, sizeof(sta_cmd));
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ sta_cmd.sta_id = htole32(IWX_MONITOR_STA_ID);
+ sta_cmd.station_type = htole32(IWX_STA_GENERAL_PURPOSE);
+ } else {
+ sta_cmd.sta_id = htole32(IWX_STATION_ID);
+ sta_cmd.station_type = htole32(IWX_STA_LINK);
+ }
+ sta_cmd.link_id = htole32(0);
+ IEEE80211_ADDR_COPY(sta_cmd.peer_mld_address, in->in_macaddr);
+ IEEE80211_ADDR_COPY(sta_cmd.peer_link_address, in->in_macaddr);
+ sta_cmd.assoc_id = htole32(in->in_ni.ni_associd);
+
+ if (in->in_ni.ni_flags & IEEE80211_NODE_HT) {
+ if (iwx_mimo_enabled(sc))
+ sta_cmd.mimo = htole32(1);
+
+ if (in->in_ni.ni_flags & IEEE80211_NODE_VHT) {
+ aggsize = (in->in_ni.ni_vhtcaps &
+ IEEE80211_VHTCAP_MAX_AMPDU_LEN_MASK) >>
+ IEEE80211_VHTCAP_MAX_AMPDU_LEN_SHIFT;
+ } else {
+ aggsize = (in->in_ni.ni_ampdu_param &
+ IEEE80211_AMPDU_PARAM_LE);
+ }
+ if (aggsize > max_aggsize)
+ aggsize = max_aggsize;
+
+ sta_cmd.tx_ampdu_spacing = htole32(0);
+ sta_cmd.tx_ampdu_max_size = aggsize;
+ }
+
+ return iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_STA_CONFIG_CMD),
+ 0, sizeof(sta_cmd), &sta_cmd);
+}
+
int
iwx_rm_sta_cmd(struct iwx_softc *sc, struct iwx_node *in)
{
@@ -6734,6 +7000,9 @@ iwx_rm_sta_cmd(struct iwx_softc *sc, struct iwx_node *in)
if ((sc->sc_flags & IWX_FLAG_STA_ACTIVE) == 0)
panic("sta already removed");
+ if (sc->sc_use_mld_api)
+ return iwx_mld_rm_sta_cmd(sc, in);
+
memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
if (ic->ic_opmode == IEEE80211_M_MONITOR)
rm_sta_cmd.sta_id = IWX_MONITOR_STA_ID;
@@ -6813,6 +7082,41 @@ iwx_rm_sta(struct iwx_softc *sc, struct iwx_node *in)
return 0;
}
+int
+iwx_mld_rm_sta_cmd(struct iwx_softc *sc, struct iwx_node *in)
+{
+ struct iwx_mvm_remove_sta_cmd sta_cmd;
+ struct iwx_link_config_cmd link_cmd;
+ int err;
+
+ memset(&sta_cmd, 0, sizeof(sta_cmd));
+ sta_cmd.sta_id = htole32(IWX_STATION_ID);
+
+ err = iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_STA_REMOVE_CMD),
+ 0, sizeof(sta_cmd), &sta_cmd);
+ if (err)
+ return err;
+
+ memset(&link_cmd, 0, sizeof(link_cmd));
+ iwx_mld_modify_link_fill(sc, in, &link_cmd,
+ IWX_LINK_CONTEXT_MODIFY_ACTIVE, 0);
+ err = iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_LINK_CONFIG_CMD),
+ 0, sizeof(link_cmd), &link_cmd);
+ if (err)
+ return err;
+
+ memset(&link_cmd, 0, sizeof(link_cmd));
+ link_cmd.link_id = htole32(0);
+ link_cmd.spec_link_id = 0;
+ link_cmd.action = IWX_FW_CTXT_ACTION_REMOVE;
+
+ return iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_LINK_CONFIG_CMD),
+ 0, sizeof(link_cmd), &link_cmd);
+}
+
uint8_t
iwx_umac_scan_fill_channels(struct iwx_softc *sc,
struct iwx_scan_channel_cfg_umac *chan, size_t chan_nitems,
@@ -7424,6 +7728,9 @@ iwx_mac_ctxt_cmd(struct iwx_softc *sc, struct iwx_node *in, uint32_t action,
if (action == IWX_FW_CTXT_ACTION_REMOVE && !active)
panic("MAC already removed");
+ if (sc->sc_use_mld_api)
+ return iwx_mld_mac_ctxt_cmd(sc, in, action, assoc);
+
memset(&cmd, 0, sizeof(cmd));
iwx_mac_ctxt_cmd_common(sc, in, &cmd, action);
@@ -7452,6 +7759,53 @@ iwx_mac_ctxt_cmd(struct iwx_softc *sc, struct iwx_node *in, uint32_t action,
}
int
+iwx_mld_mac_ctxt_cmd(struct iwx_softc *sc, struct iwx_node *in,
+ uint32_t action, int assoc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni = &in->in_ni;
+ struct iwx_mac_config_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.id_and_color = htole32(in->in_id);
+ cmd.action = htole32(action);
+
+ if (action == IWX_FW_CTXT_ACTION_REMOVE) {
+ return iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_MAC_CONFIG_CMD),
+ 0, sizeof(cmd), &cmd);
+ }
+
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ cmd.mac_type = htole32(IWX_FW_MAC_TYPE_LISTENER);
+ else if (ic->ic_opmode == IEEE80211_M_STA)
+ cmd.mac_type = htole32(IWX_FW_MAC_TYPE_BSS_STA);
+ else
+ panic("unsupported operating mode %d", ic->ic_opmode);
+ IEEE80211_ADDR_COPY(cmd.local_mld_addr, ic->ic_myaddr);
+ cmd.client.assoc_id = htole32(ni->ni_associd);
+
+ cmd.filter_flags = htole32(IWX_MAC_CFG_FILTER_ACCEPT_GRP);
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ cmd.filter_flags |= htole32(IWX_MAC_CFG_FILTER_PROMISC |
+ IWX_MAC_FILTER_IN_CONTROL_AND_MGMT |
+ IWX_MAC_CFG_FILTER_ACCEPT_BEACON |
+ IWX_MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
+ IWX_MAC_CFG_FILTER_ACCEPT_GRP);
+ } else if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod) {
+ /*
+ * Allow beacons to pass through as long as we are not
+ * associated or we do not have dtim period information.
+ */
+ cmd.filter_flags |= htole32(IWX_MAC_CFG_FILTER_ACCEPT_BEACON);
+ }
+
+ return iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_MAC_CONFIG_CMD),
+ 0, sizeof(cmd), &cmd);
+}
+
+int
iwx_clear_statistics(struct iwx_softc *sc)
{
struct iwx_statistics_cmd scmd = {
@@ -8433,24 +8787,47 @@ iwx_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
}
int
-iwx_add_sta_key(struct iwx_softc *sc, int sta_id, struct ieee80211_node *ni,
- struct ieee80211_key *k)
+iwx_mld_add_sta_key_cmd(struct iwx_softc *sc, int sta_id,
+ struct ieee80211_node *ni, struct ieee80211_key *k)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct iwx_sec_key_cmd cmd;
+ uint32_t flags = IWX_SEC_KEY_FLAG_CIPHER_CCMP;
+ int err;
+
+ if (k->k_flags & IEEE80211_KEY_GROUP)
+ flags |= IWX_SEC_KEY_FLAG_MCAST_KEY;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.u.add.sta_mask = htole32(1 << sta_id);
+ cmd.u.add.key_id = htole32(k->k_id);
+ cmd.u.add.key_flags = htole32(flags);
+ cmd.u.add.tx_seq = htole64(k->k_tsc);
+ memcpy(cmd.u.add.key, k->k_key, k->k_len);
+ cmd.action = IWX_FW_CTXT_ACTION_ADD;
+
+ err = iwx_send_cmd_pdu(sc,
+ IWX_WIDE_ID(IWX_DATA_PATH_GROUP, IWX_SEC_KEY_CMD),
+ 0, sizeof(cmd), &cmd);
+ if (err) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_AUTH_LEAVE);
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ return err;
+ }
+
+ return 0;
+}
+
+int
+iwx_add_sta_key_cmd(struct iwx_softc *sc, int sta_id,
+ struct ieee80211_node *ni, struct ieee80211_key *k)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct iwx_node *in = (void *)ni;
struct iwx_add_sta_key_cmd cmd;
uint32_t status;
- const int want_keymask = (IWX_NODE_FLAG_HAVE_PAIRWISE_KEY |
- IWX_NODE_FLAG_HAVE_GROUP_KEY);
int err;
- /*
- * Keys are stored in 'ni' so 'k' is valid if 'ni' is valid.
- * Currently we only implement station mode where 'ni' is always
- * ic->ic_bss so there is no need to validate arguments beyond this:
- */
- KASSERT(ni == ic->ic_bss);
-
memset(&cmd, 0, sizeof(cmd));
cmd.common.key_flags = htole16(IWX_STA_KEY_FLG_CCM |
@@ -8482,6 +8859,36 @@ iwx_add_sta_key(struct iwx_softc *sc, int sta_id, struct ieee80211_node *ni,
return err;
}
+ return 0;
+}
+
+int
+iwx_add_sta_key(struct iwx_softc *sc, int sta_id, struct ieee80211_node *ni,
+ struct ieee80211_key *k)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct iwx_node *in = (void *)ni;
+ const int want_keymask = (IWX_NODE_FLAG_HAVE_PAIRWISE_KEY |
+ IWX_NODE_FLAG_HAVE_GROUP_KEY);
+ uint8_t sec_key_ver;
+ int err;
+
+ /*
+ * Keys are stored in 'ni' so 'k' is valid if 'ni' is valid.
+ * Currently we only implement station mode where 'ni' is always
+ * ic->ic_bss so there is no need to validate arguments beyond this:
+ */
+ KASSERT(ni == ic->ic_bss);
+
+ sec_key_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+ IWX_SEC_KEY_CMD);
+ if (sec_key_ver != 0 && sec_key_ver != IWX_FW_CMD_VER_UNKNOWN)
+ err = iwx_mld_add_sta_key_cmd(sc, sta_id, ni, k);
+ else
+ err = iwx_add_sta_key_cmd(sc, sta_id, ni, k);
+ if (err)
+ return err;
+
if (k->k_flags & IEEE80211_KEY_GROUP)
in->in_flags |= IWX_NODE_FLAG_HAVE_GROUP_KEY;
else
@@ -9926,8 +10333,18 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *data, struct mbuf_list *ml)
IWX_SCD_QUEUE_CONFIG_CMD):
case IWX_WIDE_ID(IWX_DATA_PATH_GROUP,
IWX_RX_BAID_ALLOCATION_CONFIG_CMD):
+ case IWX_WIDE_ID(IWX_DATA_PATH_GROUP,
+ IWX_SEC_KEY_CMD):
case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
IWX_SESSION_PROTECTION_CMD):
+ case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
+ IWX_MAC_CONFIG_CMD):
+ case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
+ IWX_LINK_CONFIG_CMD):
+ case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
+ IWX_STA_CONFIG_CMD):
+ case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
+ IWX_STA_REMOVE_CMD):
case IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP,
IWX_NVM_GET_INFO):
case IWX_ADD_STA_KEY:
@@ -10399,7 +10816,7 @@ static const struct pci_matchid iwx_devices[] = {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_11,},
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_12,},
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_13,},
- /* _14 is an MA device, not yet supported */
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_14,},
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_15,},
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_16,},
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_17,},
@@ -10528,6 +10945,10 @@ static const struct iwx_dev_info iwx_dev_info_table[] = {
IWX_DEV_INFO(0x7f70, 0x1671, iwx_2ax_cfg_so_gf_a0), /* killer_1675s */
IWX_DEV_INFO(0x7f70, 0x1672, iwx_2ax_cfg_so_gf_a0), /* killer_1675i */
+ /* MA with GF2 */
+ IWX_DEV_INFO(0x7e40, 0x1671, iwx_cfg_ma_b0_gf_a0), /* killer_1675s */
+ IWX_DEV_INFO(0x7e40, 0x1672, iwx_cfg_ma_b0_gf_a0), /* killer_1675i */
+
/* Qu with Jf, C step */
_IWX_DEV_INFO(IWX_CFG_ANY, IWX_CFG_ANY,
IWX_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP,
@@ -10772,6 +11193,28 @@ static const struct iwx_dev_info iwx_dev_info_table[] = {
IWX_CFG_RF_TYPE_JF1, IWX_CFG_RF_ID_JF1_DIV,
IWX_CFG_NO_160, IWX_CFG_CORES_BT, IWX_CFG_NO_CDB,
IWX_CFG_ANY, iwx_2ax_cfg_so_jf_b0), /* 9462 */
+
+ /* Ma */
+ _IWX_DEV_INFO(IWX_CFG_ANY, IWX_CFG_ANY,
+ IWX_CFG_MAC_TYPE_MA, IWX_CFG_ANY,
+ IWX_CFG_RF_TYPE_HR2, IWX_CFG_ANY,
+ IWX_CFG_ANY, IWX_CFG_ANY, IWX_CFG_NO_CDB,
+ IWX_CFG_ANY, iwx_cfg_ma_b0_hr_b0), /* ax201 */
+ _IWX_DEV_INFO(IWX_CFG_ANY, IWX_CFG_ANY,
+ IWX_CFG_MAC_TYPE_MA, IWX_CFG_ANY,
+ IWX_CFG_RF_TYPE_GF, IWX_CFG_ANY,
+ IWX_CFG_ANY, IWX_CFG_ANY, IWX_CFG_NO_CDB,
+ IWX_CFG_ANY, iwx_cfg_ma_b0_gf_a0), /* ax211 */
+ _IWX_DEV_INFO(IWX_CFG_ANY, IWX_CFG_ANY,
+ IWX_CFG_MAC_TYPE_MA, IWX_CFG_ANY,
+ IWX_CFG_RF_TYPE_GF, IWX_CFG_ANY,
+ IWX_CFG_ANY, IWX_CFG_ANY, IWX_CFG_CDB,
+ IWX_CFG_ANY, iwx_cfg_ma_b0_gf4_a0), /* ax211 */
+ _IWX_DEV_INFO(IWX_CFG_ANY, IWX_CFG_ANY,
+ IWX_CFG_MAC_TYPE_MA, IWX_CFG_ANY,
+ IWX_CFG_RF_TYPE_FM, IWX_CFG_ANY,
+ IWX_CFG_ANY, IWX_CFG_ANY, IWX_CFG_NO_CDB,
+ IWX_CFG_ANY, iwx_cfg_ma_a0_fm_a0), /* ax231 */
};
int
@@ -11098,7 +11541,6 @@ iwx_attach(struct device *parent, struct device *self, void *aux)
case PCI_PRODUCT_INTEL_WL_22500_10:
case PCI_PRODUCT_INTEL_WL_22500_11:
case PCI_PRODUCT_INTEL_WL_22500_13:
- /* _14 is an MA device, not yet supported */
case PCI_PRODUCT_INTEL_WL_22500_15:
case PCI_PRODUCT_INTEL_WL_22500_16:
sc->sc_fwname = IWX_SO_A_GF_A_FW;
@@ -11124,6 +11566,17 @@ iwx_attach(struct device *parent, struct device *self, void *aux)
sc->sc_uhb_supported = 0;
sc->sc_imr_enabled = 1;
break;
+ case PCI_PRODUCT_INTEL_WL_22500_14:
+ sc->sc_fwname = IWX_MA_B_GF_A_FW;
+ sc->sc_pnvm_name = IWX_MA_B_GF_A_PNVM;
+ sc->sc_device_family = IWX_DEVICE_FAMILY_AX210;
+ sc->sc_integrated = 1;
+ sc->sc_ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_NONE;
+ sc->sc_low_latency_xtal = 0;
+ sc->sc_xtal_latency = 0;
+ sc->sc_tx_with_siso_diversity = 0;
+ sc->sc_uhb_supported = 1;
+ break;
default:
printf("%s: unknown adapter type\n", DEVNAME(sc));
return;
diff --git a/sys/dev/pci/if_iwxreg.h b/sys/dev/pci/if_iwxreg.h
index 7dc3cc9399c..dfc3a5c4804 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.54 2024/10/23 02:16:40 jsg Exp $ */
+/* $OpenBSD: if_iwxreg.h,v 1.55 2024/11/08 09:12:46 kettenis Exp $ */
/*-
* Based on BSD-licensed source modules in the Linux iwlwifi driver,
@@ -141,6 +141,10 @@ struct iwx_context_info_dram {
uint64_t virtual_img[IWX_MAX_DRAM_ENTRY];
} __packed;
+struct iwx_pnvm_info_dram {
+ uint64_t pnvm_img[IWX_MAX_DRAM_ENTRY];
+} __packed;
+
/*
* struct iwx_context_info_rbd_cfg - RBDs configuration
* @free_rbd_addr: default queue free RB CB base address
@@ -1363,6 +1367,7 @@ enum msix_ivar_for_cause {
#define IWX_UCODE_TLV_CAPA_LAR_MULTI_MCC 29
#define IWX_UCODE_TLV_CAPA_BT_COEX_RRC 30
#define IWX_UCODE_TLV_CAPA_GSCAN_SUPPORT 31
+#define IWX_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG 32
#define IWX_UCODE_TLV_CAPA_NAN_SUPPORT 34
#define IWX_UCODE_TLV_CAPA_UMAC_UPLOAD 35
#define IWM_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT 37
@@ -1414,6 +1419,7 @@ enum msix_ivar_for_cause {
#define IWX_UCODE_TLV_CAPA_MLME_OFFLOAD 96
#define IWX_UCODE_TLV_CAPA_BIGTK_SUPPORT 100
#define IWX_UCODE_TLV_CAPA_RFIM_SUPPORT 102
+#define IWX_UCODE_TLV_CAPA_MLD_API_SUPPORT 110
#define IWX_NUM_UCODE_TLV_CAPA 128
@@ -2001,6 +2007,10 @@ struct iwx_tx_queue_cfg_rsp {
/* MAC_CONF group subcommand IDs */
#define IWX_SESSION_PROTECTION_CMD 0x05
+#define IWX_MAC_CONFIG_CMD 0x08
+#define IWX_LINK_CONFIG_CMD 0x09
+#define IWX_STA_CONFIG_CMD 0x0a
+#define IWX_STA_REMOVE_CMD 0x0c
#define IWX_SESSION_PROTECTION_NOTIF 0xfb
/* DATA_PATH group subcommand IDs */
@@ -2009,6 +2019,7 @@ struct iwx_tx_queue_cfg_rsp {
#define IWX_TLC_MNG_CONFIG_CMD 0x0f
#define IWX_RX_BAID_ALLOCATION_CONFIG_CMD 0x16
#define IWX_SCD_QUEUE_CONFIG_CMD 0x17
+#define IWX_SEC_KEY_CMD 0x18
#define IWX_RX_NO_DATA_NOTIF 0xf5
#define IWX_THERMAL_DUAL_CHAIN_REQUEST 0xf6
#define IWX_TLC_MNG_UPDATE_NOTIF 0xf7
@@ -4508,6 +4519,404 @@ struct iwx_mac_ctx_cmd {
};
} __packed; /* IWX_MAC_CONTEXT_CMD_API_S_VER_1 */
+/**
+ * struct iwx_mac_client_data - configuration data for client MAC context
+ *
+ * @is_assoc: 1 for associated state, 0 otherwise
+ * @esr_transition_timeout: the timeout required by the AP for the eSR transition.
+ * Available only from version 2 of the command.
+ * This values comes from the EMLSR transition delay in the EML Capabilities
+ * subfield.
+ * @medium_sync_delay: the value as it appeasr in P802.11be_D2.2 Figure 9-1002j.
+ * @assoc_id: unique ID assigned by the AP during association
+ * @reserved1: alignment
+ * @data_policy: see &enum iwx_mac_data_policy
+ * @reserved2: alignment
+ * @ctwin: client traffic window in TU (period after TBTT when GO is present).
+ * 0 indicates that there is no CT window.
+ */
+struct iwx_mac_client_data {
+ uint8_t is_assoc;
+ uint8_t esr_transition_timeout;
+ uint16_t medium_sync_delay;
+
+ uint16_t assoc_id;
+ uint16_t reserved1;
+ uint16_t data_policy;
+ uint16_t reserved2;
+ uint32_t ctwin;
+} __packed; /* MAC_CONTEXT_CONFIG_CLIENT_DATA_API_S_VER_2 */
+
+/**
+ * struct iwx_mac_p2p_dev_data - configuration data for P2P device MAC context
+ *
+ * @is_disc_extended: if set to true, P2P Device discoverability is enabled on
+ * other channels as well. This should be to true only in case that the
+ * device is discoverable and there is an active GO. Note that setting this
+ * field when not needed, will increase the number of interrupts and have
+ * effect on the platform power, as this setting opens the Rx filters on
+ * all macs.
+ */
+struct iwx_mac_p2p_dev_data {
+ uint32_t is_disc_extended;
+} __packed; /* MAC_CONTEXT_CONFIG_P2P_DEV_DATA_API_S_VER_1 */
+
+/**
+ * enum iwx_mac_config_filter_flags - MAC context configuration filter flags
+ *
+ * @IWX_MAC_CFG_FILTER_PROMISC: accept all data frames
+ * @IWX_MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT: pass all management and
+ * control frames to the host
+ * @IWX_MAC_CFG_FILTER_ACCEPT_GRP: accept multicast frames
+ * @IWX_MAC_CFG_FILTER_ACCEPT_BEACON: accept beacon frames
+ * @IWX_MAC_CFG_FILTER_ACCEPT_BCAST_PROBE_RESP: accept broadcast probe response
+ * @IWX_MAC_CFG_FILTER_ACCEPT_PROBE_REQ: accept probe requests
+ */
+enum iwx_mac_config_filter_flags {
+ IWX_MAC_CFG_FILTER_PROMISC = (1 << 0),
+ IWX_MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT = (1 << 1),
+ IWX_MAC_CFG_FILTER_ACCEPT_GRP = (1 << 2),
+ IWX_MAC_CFG_FILTER_ACCEPT_BEACON = (1 << 3),
+ IWX_MAC_CFG_FILTER_ACCEPT_BCAST_PROBE_RESP = (1 << 4),
+ IWX_MAC_CFG_FILTER_ACCEPT_PROBE_REQ = (1 << 5),
+}; /* MAC_FILTER_FLAGS_MASK_E_VER_1 */
+
+/**
+ * struct iwx_mac_config_cmd - command structure to configure MAC contexts in
+ * MLD API
+ * ( MAC_CONTEXT_CONFIG_CMD = 0x8 )
+ *
+ * @id_and_color: ID and color of the MAC
+ * @action: action to perform, see &enum iwx_ctxt_action
+ * @mac_type: one of &enum iwx_mac_types
+ * @local_mld_addr: mld address
+ * @reserved_for_local_mld_addr: reserved
+ * @filter_flags: combination of &enum iwx_mac_config_filter_flags
+ * @he_support: does this MAC support HE
+ * @he_ap_support: HE AP enabled, "pseudo HE", no trigger frame handling
+ * @eht_support: does this MAC support EHT. Requires he_support
+ * @nic_not_ack_enabled: mark that the NIC doesn't support receiving
+ * ACK-enabled AGG, (i.e. both BACK and non-BACK frames in single AGG).
+ * If the NIC is not ACK_ENABLED it may use the EOF-bit in first non-0
+ * len delim to determine if AGG or single.
+ */
+struct iwx_mac_config_cmd {
+ /* COMMON_INDEX_HDR_API_S_VER_1 */
+ uint32_t id_and_color;
+ uint32_t action;
+ /* MAC_CONTEXT_TYPE_API_E */
+ uint32_t mac_type;
+ uint8_t local_mld_addr[6];
+ uint16_t reserved_for_local_mld_addr;
+ uint32_t filter_flags;
+ uint16_t he_support;
+ uint16_t he_ap_support;
+ uint32_t eht_support;
+ uint32_t nic_not_ack_enabled;
+ /* MAC_CONTEXT_CONFIG_SPECIFIC_DATA_API_U_VER_2 */
+ union {
+ struct iwx_mac_client_data client;
+ struct iwx_mac_p2p_dev_data p2p_dev;
+ };
+} __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_2 */
+
+/**
+ * struct iwx_he_backoff_conf - used for backoff configuration
+ * Per each trigger-based AC, (set by MU EDCA Parameter set info-element)
+ * used for backoff configuration of TXF5..TXF8 trigger based.
+ * The MU-TIMER is reloaded w/ MU_TIME each time a frame from the AC is sent via
+ * trigger-based TX.
+ * @cwmin: CW min
+ * @cwmax: CW max
+ * @aifsn: AIFSN
+ * AIFSN=0, means that no backoff from the specified TRIG-BASED AC is
+ * allowed till the MU-TIMER is 0
+ * @mu_time: MU time in 8TU units
+ */
+struct iwx_he_backoff_conf {
+ uint16_t cwmin;
+ uint16_t cwmax;
+ uint16_t aifsn;
+ uint16_t mu_time;
+} __packed; /* AC_QOS_DOT11AX_API_S */
+
+/**
+ * enum iwx_link_ctx_modify_flags - indicate to the fw what fields are being
+ * modified in &iwx_link_ctx_cfg_cmd
+ *
+ * @IWX_LINK_CONTEXT_MODIFY_ACTIVE: covers iwx_link_ctx_cfg_cmd::active
+ * @IWX_LINK_CONTEXT_MODIFY_RATES_INFO: covers iwx_link_ctx_cfg_cmd::cck_rates,
+ * iwx_link_ctx_cfg_cmd::ofdm_rates,
+ * iwx_link_ctx_cfg_cmd::cck_short_preamble,
+ * iwx_link_ctx_cfg_cmd::short_slot
+ * @IWX_LINK_CONTEXT_MODIFY_PROTECT_FLAGS: covers
+ * iwx_link_ctx_cfg_cmd::protection_flags
+ * @IWX_LINK_CONTEXT_MODIFY_QOS_PARAMS: covers iwx_link_ctx_cfg_cmd::qos_flags,
+ * iwx_link_ctx_cfg_cmd::ac,
+ * @IWX_LINK_CONTEXT_MODIFY_BEACON_TIMING: covers iwx_link_ctx_cfg_cmd::bi,
+ * iwx_link_ctx_cfg_cmd::dtim_interval,
+ * iwx_link_ctx_cfg_cmd::dtim_time,
+ * iwx_link_ctx_cfg_cmd::dtim_tsf,
+ * iwx_link_ctx_cfg_cmd::assoc_beacon_arrive_time.
+ * This flag can be set only once after assoc.
+ * @IWX_LINK_CONTEXT_MODIFY_HE_PARAMS: covers
+ * iwx_link_ctx_cfg_cmd::htc_trig_based_pkt_ext
+ * iwx_link_ctx_cfg_cmd::rand_alloc_ecwmin,
+ * iwx_link_ctx_cfg_cmd::rand_alloc_ecwmax,
+ * iwx_link_ctx_cfg_cmd::trig_based_txf,
+ * iwx_link_ctx_cfg_cmd::bss_color,
+ * iwx_link_ctx_cfg_cmd::ndp_fdbk_buff_th_exp,
+ * iwx_link_ctx_cfg_cmd::ref_bssid_addr
+ * iwx_link_ctx_cfg_cmd::bssid_index,
+ * iwx_link_ctx_cfg_cmd::frame_time_rts_th.
+ * This flag can be set any time.
+ * @IWX_LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE: covers
+ * iwx_link_ctx_cfg_cmd::bss_color_disable
+ * @IWX_LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwx_link_ctx_cfg_cmd::puncture_mask.
+ * This flag can be set only if the MAC that this link relates to has
+ * eht_support set to true.
+ * @IWX_LINK_CONTEXT_MODIFY_ALL: set all above flags
+ */
+enum iwx_link_ctx_modify_flags {
+ IWX_LINK_CONTEXT_MODIFY_ACTIVE = (1 << 0),
+ IWX_LINK_CONTEXT_MODIFY_RATES_INFO = (1 << 1),
+ IWX_LINK_CONTEXT_MODIFY_PROTECT_FLAGS = (1 << 2),
+ IWX_LINK_CONTEXT_MODIFY_QOS_PARAMS = (1 << 3),
+ IWX_LINK_CONTEXT_MODIFY_BEACON_TIMING = (1 << 4),
+ IWX_LINK_CONTEXT_MODIFY_HE_PARAMS = (1 << 5),
+ IWX_LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE = (1 << 6),
+ IWX_LINK_CONTEXT_MODIFY_EHT_PARAMS = (1 << 7),
+ IWX_LINK_CONTEXT_MODIFY_ALL = 0xff,
+}; /* LINK_CONTEXT_MODIFY_MASK_E_VER_1 */
+
+/**
+ * enum iwx_link_ctx_protection_flags - link protection flags
+ * @IWX_LINK_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames,
+ * this will require CCK RTS/CTS2self.
+ * RTS/CTS will protect full burst time.
+ * @IWX_LINK_PROT_FLG_HT_PROT: enable HT protection
+ * @IWX_LINK_PROT_FLG_FAT_PROT: protect 40 MHz transmissions
+ * @IWX_LINK_PROT_FLG_SELF_CTS_EN: allow CTS2self
+ */
+enum iwx_link_ctx_protection_flags {
+ IWX_LINK_PROT_FLG_TGG_PROTECT = (1 << 0),
+ IWX_LINK_PROT_FLG_HT_PROT = (1 << 1),
+ IWX_LINK_PROT_FLG_FAT_PROT = (1 << 2),
+ IWX_LINK_PROT_FLG_SELF_CTS_EN = (1 << 3),
+}; /* LINK_PROTECT_FLAGS_E_VER_1 */
+
+/**
+ * struct iwx_link_config_cmd - command structure to configure the LINK context
+ * in MLD API
+ * ( LINK_CONFIG_CMD =0x9 )
+ *
+ * @action: action to perform, see &enum iwx_ctxt_action
+ * @link_id: the id of the link that this cmd configures
+ * @mac_id: interface ID. Relevant only if action is FW_CTXT_ACTION_ADD
+ * @phy_id: PHY index. Can be changed only if the link was inactive
+ * (and stays inactive). If the link is active (or becomes active),
+ * this field is ignored.
+ * @local_link_addr: the links MAC address. Can be changed only if the link was
+ * inactive (and stays inactive). If the link is active
+ * (or becomes active), this field is ignored.
+ * @reserved_for_local_link_addr: reserved
+ * @modify_mask: from &enum iwx_link_ctx_modify_flags, selects what to change.
+ * Relevant only if action is FW_CTXT_ACTION_MODIFY
+ * @active: indicates whether the link is active or not
+ * @listen_lmac: indicates whether the link should be allocated on the Listen
+ * Lmac or on the Main Lmac. Cannot be changed on an active Link.
+ * Relevant only for eSR.
+ * @cck_rates: basic rates available for CCK
+ * @ofdm_rates: basic rates available for OFDM
+ * @cck_short_preamble: 1 for enabling short preamble, 0 otherwise
+ * @short_slot: 1 for enabling short slots, 0 otherwise
+ * @protection_flags: combination of &enum iwx_link_ctx_protection_flags
+ * @qos_flags: from &enum iwx_mac_qos_flags
+ * @ac: one iwx_mac_qos configuration for each AC
+ * @htc_trig_based_pkt_ext: default PE in 4us units
+ * @rand_alloc_ecwmin: random CWmin = 2**ECWmin-1
+ * @rand_alloc_ecwmax: random CWmax = 2**ECWmax-1
+ * @ndp_fdbk_buff_th_exp: set exponent for the NDP feedback buffered threshold
+ * @trig_based_txf: MU EDCA Parameter set for the trigger based traffic queues
+ * @bi: beacon interval in TU, applicable only when associated
+ * @dtim_interval: DTIM interval in TU.
+ * Relevant only for GO, otherwise this is offloaded.
+ * @puncture_mask: puncture mask for EHT
+ * @frame_time_rts_th: HE duration RTS threshold, in units of 32us
+ * @flags: a combination from &enum iwx_link_ctx_flags
+ * @flags_mask: what of %flags have changed. Also &enum iwx_link_ctx_flags
+ * Below fields are for multi-bssid:
+ * @ref_bssid_addr: reference BSSID used by the AP
+ * @reserved_for_ref_bssid_addr: reserved
+ * @bssid_index: index of the associated VAP
+ * @bss_color: 11ax AP ID that is used in the HE SIG-A to mark inter BSS frame
+ * @spec_link_id: link_id as the AP knows it
+ * @reserved: alignment
+ * @ibss_bssid_addr: bssid for ibss
+ * @reserved_for_ibss_bssid_addr: reserved
+ * @reserved1: reserved for future use
+ */
+struct iwx_link_config_cmd {
+ uint32_t action;
+ uint32_t link_id;
+ uint32_t mac_id;
+ uint32_t phy_id;
+ uint8_t local_link_addr[6];
+ uint16_t reserved_for_local_link_addr;
+ uint32_t modify_mask;
+ uint32_t active;
+ uint32_t listen_lmac;
+ uint32_t cck_rates;
+ uint32_t ofdm_rates;
+ uint32_t cck_short_preamble;
+ uint32_t short_slot;
+ uint32_t protection_flags;
+ /* MAC_QOS_PARAM_API_S_VER_1 */
+ uint32_t qos_flags;
+ struct iwx_ac_qos ac[IWX_AC_NUM + 1];
+ uint8_t htc_trig_based_pkt_ext;
+ uint8_t rand_alloc_ecwmin;
+ uint8_t rand_alloc_ecwmax;
+ uint8_t ndp_fdbk_buff_th_exp;
+ struct iwx_he_backoff_conf trig_based_txf[IWX_AC_NUM];
+ uint32_t bi;
+ uint32_t dtim_interval;
+ uint16_t puncture_mask;
+ uint16_t frame_time_rts_th;
+ uint32_t flags;
+ uint32_t flags_mask;
+ /* The below fields are for multi-bssid */
+ uint8_t ref_bssid_addr[6];
+ uint16_t reserved_for_ref_bssid_addr;
+ uint8_t bssid_index;
+ uint8_t bss_color;
+ uint8_t spec_link_id;
+ uint8_t reserved;
+ uint8_t ibss_bssid_addr[6];
+ uint16_t reserved_for_ibss_bssid_addr;
+ uint32_t reserved1[8];
+} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 */
+
+#define MAX_HE_SUPP_NSS 2
+#define MAX_CHANNEL_BW_INDX_API_D_VER_2 4
+#define MAX_CHANNEL_BW_INDX_API_D_VER_3 5
+
+/**
+ * struct iwx_he_pkt_ext_v1 - QAM thresholds
+ * The required PPE is set via HE Capabilities IE, per Nss x BW x MCS
+ * The IE is organized in the following way:
+ * Support for Nss x BW (or RU) matrix:
+ * (0=SISO, 1=MIMO2) x (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz)
+ * Each entry contains 2 QAM thresholds for 8us and 16us:
+ * 0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6=RES, 7=NONE
+ * i.e. QAM_th1 < QAM_th2 such if TX uses QAM_tx:
+ * QAM_tx < QAM_th1 --> PPE=0us
+ * QAM_th1 <= QAM_tx < QAM_th2 --> PPE=8us
+ * QAM_th2 <= QAM_tx --> PPE=16us
+ * @pkt_ext_qam_th: QAM thresholds
+ * For each Nss/Bw define 2 QAM thrsholds (0..5)
+ * For rates below the low_th, no need for PPE
+ * For rates between low_th and high_th, need 8us PPE
+ * For rates equal or higher then the high_th, need 16us PPE
+ * Nss (0-siso, 1-mimo2) x BW (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz) x
+ * (0-low_th, 1-high_th)
+ */
+struct iwx_he_pkt_ext_v1 {
+ uint8_t pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_2][2];
+} __packed; /* PKT_EXT_DOT11AX_API_S_VER_1 */
+
+/**
+ * struct iwx_he_pkt_ext_v2 - QAM thresholds
+ * The required PPE is set via HE Capabilities IE, per Nss x BW x MCS
+ * The IE is organized in the following way:
+ * Support for Nss x BW (or RU) matrix:
+ * (0=SISO, 1=MIMO2) x (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz)
+ * Each entry contains 2 QAM thresholds for 8us and 16us:
+ * 0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6=RES, 7=NONE
+ * i.e. QAM_th1 < QAM_th2 such if TX uses QAM_tx:
+ * QAM_tx < QAM_th1 --> PPE=0us
+ * QAM_th1 <= QAM_tx < QAM_th2 --> PPE=8us
+ * QAM_th2 <= QAM_tx --> PPE=16us
+ * @pkt_ext_qam_th: QAM thresholds
+ * For each Nss/Bw define 2 QAM thrsholds (0..5)
+ * For rates below the low_th, no need for PPE
+ * For rates between low_th and high_th, need 8us PPE
+ * For rates equal or higher then the high_th, need 16us PPE
+ * Nss (0-siso, 1-mimo2) x
+ * BW (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz, 4-320MHz) x
+ * (0-low_th, 1-high_th)
+ */
+struct iwx_he_pkt_ext_v2 {
+ uint8_t pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_3][2];
+} __packed; /* PKT_EXT_DOT11AX_API_S_VER_2 */
+
+/**
+ * struct iwx_mvm_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's
+ * station table
+ * ( STA_CONFIG_CMD = 0xA )
+ *
+ * @sta_id: index of station in uCode's station table
+ * @link_id: the id of the link that is used to communicate with this sta
+ * @peer_mld_address: the peers mld address
+ * @reserved_for_peer_mld_address: reserved
+ * @peer_link_address: the address of the link that is used to communicate
+ * with this sta
+ * @reserved_for_peer_link_address: reserved
+ * @station_type: type of this station. See &enum iwx_fw_sta_type
+ * @assoc_id: for GO only
+ * @beamform_flags: beam forming controls
+ * @mfp: indicates whether the STA uses management frame protection or not.
+ * @mimo: indicates whether the sta uses mimo or not
+ * @mimo_protection: indicates whether the sta uses mimo protection or not
+ * @ack_enabled: indicates that the AP supports receiving ACK-
+ * enabled AGG, i.e. both BACK and non-BACK frames in a single AGG
+ * @trig_rnd_alloc: indicates that trigger based random allocation
+ * is enabled according to UORA element existence
+ * @tx_ampdu_spacing: minimum A-MPDU spacing:
+ * 4 - 2us density, 5 - 4us density, 6 - 8us density, 7 - 16us density
+ * @tx_ampdu_max_size: maximum A-MPDU length: 0 - 8K, 1 - 16K, 2 - 32K,
+ * 3 - 64K, 4 - 128K, 5 - 256K, 6 - 512K, 7 - 1024K.
+ * @sp_length: the size of the SP in actual number of frames
+ * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver
+ * enabled ACs.
+ * @pkt_ext: optional, exists according to PPE-present bit in the HE/EHT-PHY
+ * capa
+ * @htc_flags: which features are supported in HTC
+ */
+struct iwx_mvm_sta_cfg_cmd {
+ uint32_t sta_id;
+ uint32_t link_id;
+ uint8_t peer_mld_address[6];
+ uint16_t reserved_for_peer_mld_address;
+ uint8_t peer_link_address[6];
+ uint16_t reserved_for_peer_link_address;
+ uint32_t station_type;
+ uint32_t assoc_id;
+ uint32_t beamform_flags;
+ uint32_t mfp;
+ uint32_t mimo;
+ uint32_t mimo_protection;
+ uint32_t ack_enabled;
+ uint32_t trig_rnd_alloc;
+ uint32_t tx_ampdu_spacing;
+ uint32_t tx_ampdu_max_size;
+ uint32_t sp_length;
+ uint32_t uapsd_acs;
+ struct iwx_he_pkt_ext_v2 pkt_ext;
+ uint32_t htc_flags;
+} __packed; /* STA_CMD_API_S_VER_1 */
+
+/**
+ * struct iwx_mvm_remove_sta_cmd - a cmd structure to remove a sta added by
+ * STA_CONFIG_CMD or AUX_STA_CONFIG_CMD
+ * ( STA_REMOVE_CMD = 0xC )
+ *
+ * @sta_id: index of station to remove
+ */
+struct iwx_mvm_remove_sta_cmd {
+ uint32_t sta_id;
+} __packed; /* REMOVE_STA_API_S_VER_1 */
+
static inline uint32_t iwx_reciprocal(uint32_t v)
{
if (!v)
@@ -5481,6 +5890,80 @@ struct iwx_scd_queue_cfg_cmd {
} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3 */
/**
+ * enum iwx_sec_key_flags - security key command key flags
+ * @IWX_SEC_KEY_FLAG_CIPHER_MASK: cipher mask
+ * @IWX_SEC_KEY_FLAG_CIPHER_WEP: WEP cipher
+ * @IWX_SEC_KEY_FLAG_CIPHER_CCMP: CCMP/CMAC cipher
+ * @IWX_SEC_KEY_FLAG_CIPHER_TKIP: TKIP cipher
+ * @IWX_SEC_KEY_FLAG_CIPHER_GCMP: GCMP/GMAC cipher
+ * @IWX_SEC_KEY_FLAG_NO_TX: don't install for TX
+ * @IWX_SEC_KEY_FLAG_KEY_SIZE: large key size (WEP-104, GCMP-256, GMAC-256)
+ * @IWX_SEC_KEY_FLAG_MFP: MFP is in used for this key
+ * @IWX_SEC_KEY_FLAG_MCAST_KEY: this is a multicast key
+ * @IWX_SEC_KEY_FLAG_SPP_AMSDU: SPP A-MSDU should be used
+ */
+enum iwx_sec_key_flags {
+ IWX_SEC_KEY_FLAG_CIPHER_MASK = 0x07,
+ IWX_SEC_KEY_FLAG_CIPHER_WEP = 0x01,
+ IWX_SEC_KEY_FLAG_CIPHER_CCMP = 0x02,
+ IWX_SEC_KEY_FLAG_CIPHER_TKIP = 0x03,
+ IWX_SEC_KEY_FLAG_CIPHER_GCMP = 0x05,
+ IWX_SEC_KEY_FLAG_NO_TX = 0x08,
+ IWX_SEC_KEY_FLAG_KEY_SIZE = 0x10,
+ IWX_SEC_KEY_FLAG_MFP = 0x20,
+ IWX_SEC_KEY_FLAG_MCAST_KEY = 0x40,
+ IWX_SEC_KEY_FLAG_SPP_AMSDU = 0x80,
+};
+
+#define IWX_SEC_WEP_KEY_OFFSET 3
+
+/**
+ * struct iwx_sec_key_cmd - security key command
+ * @action: action from &enum iwx_ctxt_action
+ * @u.add.sta_mask: station mask for the new key
+ * @u.add.key_id: key ID (0-7) for the new key
+ * @u.add.key_flags: key flags per &enum iwx_sec_key_flags
+ * @u.add.key: key material. WEP keys should start from &IWX_SEC_WEP_KEY_OFFSET.
+ * @u.add.tkip_mic_rx_key: TKIP MIC RX key
+ * @u.add.tkip_mic_tx_key: TKIP MIC TX key
+ * @u.add.rx_seq: RX sequence counter value
+ * @u.add.tx_seq: TX sequence counter value
+ * @u.modify.old_sta_mask: old station mask
+ * @u.modify.new_sta_mask: new station mask
+ * @u.modify.key_id: key ID
+ * @u.modify.key_flags: new key flags
+ * @u.remove.sta_mask: station mask
+ * @u.remove.key_id: key ID
+ * @u.remove.key_flags: key flags
+ */
+struct iwx_sec_key_cmd {
+ uint32_t action;
+ union {
+ struct {
+ uint32_t sta_mask;
+ uint32_t key_id;
+ uint32_t key_flags;
+ uint8_t key[32];
+ uint8_t tkip_mic_rx_key[8];
+ uint8_t tkip_mic_tx_key[8];
+ uint64_t rx_seq;
+ uint64_t tx_seq;
+ } __packed add; /* SEC_KEY_ADD_CMD_API_S_VER_1 */
+ struct {
+ uint32_t old_sta_mask;
+ uint32_t new_sta_mask;
+ uint32_t key_id;
+ uint32_t key_flags;
+ } __packed modify; /* SEC_KEY_MODIFY_CMD_API_S_VER_1 */
+ struct {
+ uint32_t sta_mask;
+ uint32_t key_id;
+ uint32_t key_flags;
+ } __packed remove; /* SEC_KEY_REMOVE_CMD_API_S_VER_1 */
+ } __packed u; /* SEC_KEY_OPERATION_API_U_VER_1 */
+} __packed; /* SEC_KEY_CMD_API_S_VER_1 */
+
+/**
* Options for TLC config flags
* @IWX_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC. For HE this enables STBC for
* bandwidths <= 80MHz
diff --git a/sys/dev/pci/if_iwxvar.h b/sys/dev/pci/if_iwxvar.h
index 65f91b4fa86..e82e5bf0fab 100644
--- a/sys/dev/pci/if_iwxvar.h
+++ b/sys/dev/pci/if_iwxvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwxvar.h,v 1.41 2023/03/06 11:53:24 stsp Exp $ */
+/* $OpenBSD: if_iwxvar.h,v 1.42 2024/11/08 09:12:46 kettenis Exp $ */
/*
* Copyright (c) 2014 genua mbh <info@genua.de>
@@ -123,7 +123,7 @@ struct iwx_tx_radiotap_header {
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL))
-#define IWX_UCODE_SECT_MAX 57
+#define IWX_UCODE_SECT_MAX 60
/*
* fw_status is used to determine if we've already parsed the firmware file
@@ -486,6 +486,14 @@ struct iwx_device_cfg {
#define IWX_SO_A_GF4_A_PNVM "iwx-so-a0-gf4-a0.pnvm"
#define IWX_SO_A_HR_B_FW "iwx-so-a0-hr-b0-77"
#define IWX_SO_A_JF_B_FW "iwx-so-a0-jf-b0-77"
+#define IWX_MA_B_HR_B_FW "iwx-ma-a0-hr-b0-83"
+#define IWX_MA_B_HR_B_PNVM "iwx-ma-a0-hr-b0.pnvm"
+#define IWX_MA_B_GF_A_FW "iwx-ma-b0-gf-a0-83"
+#define IWX_MA_B_GF_A_PNVM "iwx-ma-b0-gf-a0.pnvm"
+#define IWX_MA_B_GF4_A_FW "iwx-ma-b0-gf4-a0-83"
+#define IWX_MA_B_GF4_A_PNVM "iwx-ma-b0-gf4-a0.pnvm"
+#define IWX_MA_A_FM_A_FW "iwx-ma-a0-fm-a0-83"
+#define IWX_MA_A_FM_A_PNVM "iwx-ma-a0-fm-a0.pnvm"
const struct iwx_device_cfg iwx_9560_quz_a0_jf_b0_cfg = {
.fw_name = IWX_QUZ_A_JF_B_FW,
@@ -574,6 +582,26 @@ const struct iwx_device_cfg iwx_2ax_cfg_so_jf_b0 = {
.fw_name = IWX_SO_A_JF_B_FW,
};
+const struct iwx_device_cfg iwx_cfg_ma_b0_hr_b0 = {
+ .fw_name = IWX_MA_B_HR_B_FW,
+ .pnvm_name = IWX_MA_B_HR_B_PNVM,
+};
+
+const struct iwx_device_cfg iwx_cfg_ma_b0_gf_a0 = {
+ .fw_name = IWX_MA_B_GF_A_FW,
+ .pnvm_name = IWX_MA_B_GF_A_PNVM,
+};
+
+const struct iwx_device_cfg iwx_cfg_ma_b0_gf4_a0 = {
+ .fw_name = IWX_MA_B_GF4_A_FW,
+ .pnvm_name = IWX_MA_B_GF4_A_PNVM,
+};
+
+const struct iwx_device_cfg iwx_cfg_ma_a0_fm_a0 = {
+ .fw_name = IWX_MA_A_FM_A_FW,
+ .pnvm_name = IWX_MA_A_FM_A_PNVM,
+};
+
#define IWX_CFG_ANY (~0)
#define IWX_CFG_MAC_TYPE_QU 0x33
@@ -693,6 +721,9 @@ struct iwx_softc {
struct iwx_dma_info prph_info_dma;
struct iwx_dma_info iml_dma;
struct iwx_dma_info pnvm_dma;
+ struct iwx_dma_info pnvm_seg_dma[IWX_MAX_DRAM_ENTRY];
+ uint32_t pnvm_size;
+ int pnvm_segs;
uint32_t sc_pnvm_ver;
int sc_fw_chunk_done;
@@ -713,6 +744,7 @@ struct iwx_softc {
struct iwx_fw_cmd_version cmd_versions[IWX_MAX_FW_CMD_VERSIONS];
int n_cmd_versions;
int sc_rate_n_flags_version;
+ int sc_use_mld_api;
int sc_intmask;
int sc_flags;