diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2024-11-08 09:12:47 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2024-11-08 09:12:47 +0000 |
commit | 1ef4445c7bc0ab808a7082b106b0c58db5458d01 (patch) | |
tree | 6805e7acacef58888e4657d5b2b9d6f8c53f4aaa | |
parent | 80a557e14f0fc4aac1a920de028e43fb4b6259dd (diff) |
Add support for MA devices.
ok stsp@
-rw-r--r-- | sys/dev/pci/if_iwx.c | 509 | ||||
-rw-r--r-- | sys/dev/pci/if_iwxreg.h | 485 | ||||
-rw-r--r-- | sys/dev/pci/if_iwxvar.h | 36 |
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; |