iaxwifi200: Merge changes from upstream OpenBSD.

Includes changes to support "MA" devices (but these also need
new firmware.)
This commit is contained in:
Augustin Cavalier
2025-03-01 15:58:59 -05:00
parent e38d10fd9f
commit d9399d4673
3 changed files with 1012 additions and 49 deletions
@@ -1,4 +1,4 @@
/* $OpenBSD: if_iwx.c,v 1.182 2024/02/26 18:00:09 stsp Exp $ */
/* $OpenBSD: if_iwx.c,v 1.189 2025/02/04 09:15:04 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -96,12 +96,8 @@
//#include "bpfilter.h"
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/rwlock.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -423,7 +419,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 *);
@@ -444,6 +442,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 *);
@@ -462,7 +462,6 @@ uint16_t iwx_rs_vht_rates(struct iwx_softc *, struct ieee80211_node *, int);
int iwx_rs_init_v3(struct iwx_softc *, struct iwx_node *);
int iwx_rs_init_v4(struct iwx_softc *, struct iwx_node *);
int iwx_rs_init(struct iwx_softc *, struct iwx_node *);
int iwx_enable_data_tx_queues(struct iwx_softc *);
int iwx_phy_send_rlc(struct iwx_softc *, struct iwx_phy_ctxt *,
uint8_t, uint8_t);
int iwx_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *,
@@ -612,7 +611,8 @@ iwx_ctxt_info_alloc_dma(struct iwx_softc *sc,
return 0;
}
void iwx_ctxt_info_free_paging(struct iwx_softc *sc)
void
iwx_ctxt_info_free_paging(struct iwx_softc *sc)
{
struct iwx_self_init_dram *dram = &sc->init_dram;
int i;
@@ -795,7 +795,7 @@ iwx_alloc_fw_monitor(struct iwx_softc *sc, uint8_t max_power)
}
if (max_power > 26) {
DPRINTF(("%s: External buffer size for monitor is too big %d, "
DPRINTF(("%s: External buffer size for monitor is too big %d, "
"check the FW TLV\n", DEVNAME(sc), max_power));
return 0;
}
@@ -2731,6 +2731,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
@@ -4047,6 +4049,70 @@ iwx_start_fw(struct iwx_softc *sc)
return iwx_load_firmware(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)
@@ -4054,10 +4120,13 @@ iwx_pnvm_handle_section(struct iwx_softc *sc, const uint8_t *data,
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;
@@ -4110,16 +4179,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;
}
@@ -4141,18 +4213,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;
}
@@ -4200,15 +4273,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);
}
/*
@@ -4406,6 +4483,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;
}
@@ -5522,6 +5609,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)
@@ -6454,6 +6545,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));
@@ -6645,6 +6740,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) {
@@ -6750,6 +6848,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)
{
@@ -6760,6 +7022,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;
@@ -6839,6 +7104,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,
@@ -7232,7 +7532,7 @@ iwx_rval2ridx(int rval)
break;
}
return ridx;
return ridx;
}
void
@@ -7450,6 +7750,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);
@@ -7477,6 +7780,53 @@ iwx_mac_ctxt_cmd(struct iwx_softc *sc, struct iwx_node *in, uint32_t action,
return iwx_send_cmd_pdu(sc, IWX_MAC_CONTEXT_CMD, 0, sizeof(cmd), &cmd);
}
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)
{
@@ -7549,7 +7899,7 @@ iwx_scan(struct iwx_softc *sc)
* The current mode might have been fixed during association.
* Ensure all channels get scanned.
*/
if (IFM_SUBTYPE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO)
if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO)
ieee80211_setmode(ic, IEEE80211_MODE_AUTO);
sc->sc_flags |= IWX_FLAG_SCANNING;
@@ -8344,6 +8694,9 @@ iwx_run(struct iwx_softc *sc)
return err;
}
#endif
if (ic->ic_opmode == IEEE80211_M_MONITOR)
return 0;
err = iwx_power_mac_update_mode(sc, in);
if (err) {
printf("%s: could not update MAC power (error %d)\n",
@@ -8351,9 +8704,6 @@ iwx_run(struct iwx_softc *sc)
return err;
}
if (ic->ic_opmode == IEEE80211_M_MONITOR)
return 0;
/* Start at lowest available bit-rate. Firmware will raise. */
in->in_ni.ni_txrate = 0;
in->in_ni.ni_txmcs = 0;
@@ -8459,23 +8809,46 @@ 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_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);
struct iwx_sec_key_cmd cmd;
uint32_t flags = IWX_SEC_KEY_FLAG_CIPHER_CCMP;
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);
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_add_sta_key_cmd cmd;
uint32_t status;
int err;
memset(&cmd, 0, sizeof(cmd));
@@ -8508,6 +8881,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
@@ -9852,7 +10255,7 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *data, struct mbuf_list *ml)
* For v5 and above, we can check the version, for older
* versions we need to check the size.
*/
if (iwx_lookup_notif_ver(sc, IWX_LEGACY_GROUP,
if (iwx_lookup_notif_ver(sc, IWX_LEGACY_GROUP,
IWX_ALIVE) == 6) {
SYNC_RESP_STRUCT(resp6, pkt);
if (iwx_rx_packet_payload_len(pkt) !=
@@ -9952,8 +10355,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:
@@ -10445,7 +10858,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,},
@@ -10590,6 +11003,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,
@@ -10834,6 +11251,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
@@ -10943,7 +11382,7 @@ iwx_find_device_cfg(struct iwx_softc *sc)
cores = IWX_SUBDEVICE_CORES(sdev_id);
for (i = nitems(iwx_dev_info_table) - 1; i >= 0; i--) {
const struct iwx_dev_info *dev_info = &iwx_dev_info_table[i];
const struct iwx_dev_info *dev_info = &iwx_dev_info_table[i];
if (dev_info->device != (uint16_t)IWX_CFG_ANY &&
dev_info->device != sc->sc_pid)
@@ -11197,7 +11636,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;
@@ -11223,6 +11661,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));
goto fail;
@@ -11261,7 +11710,7 @@ iwx_attach(struct device *parent, struct device *self, void *aux)
if (err) {
printf("%s: could not allocate memory for loading firmware\n",
DEVNAME(sc));
goto fail;
goto fail1;
}
if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) {
@@ -1,4 +1,4 @@
/* $OpenBSD: if_iwxreg.h,v 1.52 2023/10/06 15:15:41 stsp 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
@@ -1760,7 +1766,7 @@ struct iwx_gen3_bc_tbl_entry {
#define IWX_DQA_CMD_QUEUE 0
#define IWX_DQA_AUX_QUEUE 1
#define IWX_DQA_INJECT_MONITOR_QUEUE 2 /* used in monitor mode only */
#define IWX_DQA_INJECT_MONITOR_QUEUE 1 /* used in monitor mode only */
#define IWX_DQA_MGMT_QUEUE 1 /* default queue other modes */
/* Reserve 8 DQA Tx queues for QoS data frames. */
@@ -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
@@ -2016,7 +2027,6 @@ struct iwx_tx_queue_cfg_rsp {
/* REGULATORY_AND_NVM group subcommand IDs */
#define IWX_NVM_ACCESS_COMPLETE 0x00
#define IWX_NVM_GET_INFO 0x02
#define IWX_NVM_GET_INFO 0x02
#define IWX_PNVM_INIT_COMPLETE 0xfe
/*
@@ -4509,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 +5889,80 @@ struct iwx_scd_queue_cfg_cmd {
} __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1 */
} __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
@@ -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 <[email protected]>
@@ -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
@@ -699,6 +727,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;
@@ -719,6 +750,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;