diff --git a/sys/dev/pci/if_mwx.c b/sys/dev/pci/if_mwx.c index 4ad8b5edfe8..9beabda783d 100644 --- a/sys/dev/pci/if_mwx.c +++ b/sys/dev/pci/if_mwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mwx.c,v 1.23 2026/06/04 13:15:20 claudio Exp $ */ +/* $OpenBSD: if_mwx.c,v 1.24 2026/06/04 19:26:48 claudio Exp $ */ /* * Copyright (c) 2022 Claudio Jeker * Copyright (c) 2021 MediaTek Inc. @@ -529,7 +529,9 @@ int mwx_mcu_start_patch(struct mwx_softc *); int mwx_mcu_start_firmware(struct mwx_softc *, uint32_t, uint32_t); int mt7921_mcu_get_nic_capability(struct mwx_softc *); +int mt7925_mcu_get_nic_capability(struct mwx_softc *); int mt7921_mcu_fw_log_2_host(struct mwx_softc *, uint8_t); +int mt7925_mcu_fw_log_2_host(struct mwx_softc *, uint8_t); int mt7921_mcu_set_eeprom(struct mwx_softc *); int mt7921_mcu_set_rts_thresh(struct mwx_softc *, uint32_t, uint8_t); @@ -2164,7 +2166,7 @@ mwx_dma_txwi_enqueue(struct mwx_softc *sc, struct mwx_queue *q, BUS_DMASYNC_PREWRITE); buf0 = mt->mt_addr; - len0 = sizeof(mt->mt_desc); + len0 = sizeof(*mt->mt_desc); ctrl = MT_DMA_CTL_SD_LEN0(len0); ctrl |= MT_DMA_CTL_LAST_SEC0; @@ -2390,7 +2392,7 @@ mwx_dma_rx_done(struct mwx_softc *sc, struct mwx_queue *q) struct mbuf * mwx_mcu_alloc_msg(size_t len) { - const int headspace = sizeof(struct mt7921_mcu_txd); + const int headspace = sizeof(struct mwx_mcu_txd); struct mbuf *m; /* Allocate mbuf with enough space */ @@ -2426,16 +2428,17 @@ mwx_mcu_set_len(struct mbuf *m, void *end) int mwx_mcu_send_mbuf(struct mwx_softc *sc, uint32_t cmd, struct mbuf *m, int *seqp) { - struct mt7921_uni_txd *uni_txd; - struct mt7921_mcu_txd *mcu_txd; + struct mwx_uni_txd *uni_txd; + struct mwx_mcu_txd *mcu_txd; struct mwx_queue *q; uint32_t *txd, val; - int s, rv, txd_len, mcu_cmd = cmd & MCU_CMD_FIELD_ID_MASK; - int len = m->m_pkthdr.len; + int s, rv, mcu_cmd = cmd & MCU_CMD_FIELD_ID_MASK; + int tot_len, txd_len, len = m->m_pkthdr.len; uint8_t seq; if (cmd == MCU_CMD_FW_SCATTER) { q = &sc->sc_txfwdlq; + KASSERT(seqp == NULL); goto enqueue; } @@ -2443,30 +2446,47 @@ mwx_mcu_send_mbuf(struct mwx_softc *sc, uint32_t cmd, struct mbuf *m, int *seqp) if (seq == 0) seq = ++sc->sc_mcu_seq & 0x0f; + KASSERT(seq < nitems(sc->sc_mcu_wait)); + txd_len = cmd & MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); + tot_len = txd_len + len; KASSERT(m_leadingspace(m) >= txd_len); m = m_prepend(m, txd_len, M_DONTWAIT); txd = mtod(m, uint32_t *); memset(txd, 0, txd_len); - val = (m->m_len & MT_TXD0_TX_BYTES_MASK) | + val = (tot_len & MT_TXD0_TX_BYTES_MASK) | MT_TX_TYPE_CMD | MT_TXD0_Q_IDX(MT_TX_MCU_PORT_RX_Q0); txd[0] = htole32(val); - val = MT_TXD1_LONG_FORMAT | MT_HDR_FORMAT_CMD; + if (sc->sc_hwtype == MWX_HW_MT7925) + val = MT7925_HDR_FORMAT_CMD; + else + val = MT_TXD1_LONG_FORMAT | MT_HDR_FORMAT_CMD; txd[1] = htole32(val); if (cmd & MCU_CMD_FIELD_UNI) { - uni_txd = (struct mt7921_uni_txd *)txd; - uni_txd->len = htole16(len); - uni_txd->option = MCU_CMD_UNI_EXT_ACK; + uni_txd = (struct mwx_uni_txd *)txd; + uni_txd->len = htole16(tot_len - sizeof(uni_txd->txd)); + if (sc->sc_hwtype == MWX_HW_MT7925) { + if (cmd & MCU_CMD_FIELD_QUERY) + uni_txd->option = MCU_CMD_UNI_QUERY_ACK; + else + uni_txd->option = MCU_CMD_UNI_EXT_ACK; + /* Non-QUERY CHIP_CONFIG/HIF_CTRL must NOT have ACK */ + if (cmd == MCU_UNI_CMD_HIF_CTRL || + cmd == MCU_UNI_CMD_CHIP_CONFIG) + uni_txd->option &= ~MCU_CMD_ACK; + } else { + uni_txd->option = MCU_CMD_UNI_EXT_ACK; + } uni_txd->cid = htole16(mcu_cmd); uni_txd->s2d_index = CMD_S2D_IDX_H2N; uni_txd->pkt_type = MCU_PKT_ID; uni_txd->seq = seq; } else { - mcu_txd = (struct mt7921_mcu_txd *)txd; - mcu_txd->len = htole16(len); + mcu_txd = (struct mwx_mcu_txd *)txd; + mcu_txd->len = htole16(tot_len - sizeof(uni_txd->txd)); mcu_txd->pq_id = htole16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, MT_TX_MCU_PORT_RX_Q0)); mcu_txd->pkt_type = MCU_PKT_ID; @@ -2486,8 +2506,11 @@ mwx_mcu_send_mbuf(struct mwx_softc *sc, uint32_t cmd, struct mbuf *m, int *seqp) } } - if (seqp != NULL) + if (seqp != NULL) { + memset(&sc->sc_mcu_wait[seq], 0, sizeof(sc->sc_mcu_wait[0])); + sc->sc_mcu_wait[seq].mcu_cmd = cmd; *seqp = seq; + } q = &sc->sc_txmcuq; enqueue: @@ -2505,6 +2528,10 @@ printf("%s: %s: cmd %08x\n", DEVNAME(sc), __func__, cmd); tsleep_nsec(q, 0, "mwxq", MSEC_TO_NSEC(100)); } splx(s); + if (rv != 0) { + memset(&sc->sc_mcu_wait[seq], 0, sizeof(sc->sc_mcu_wait[0])); + m_freem(m); + } return rv; } @@ -2667,9 +2694,6 @@ mwx_mcu_wait_resp_int(struct mwx_softc *sc, uint32_t cmd, int seq, KASSERT(seq < nitems(sc->sc_mcu_wait)); - memset(&sc->sc_mcu_wait[seq], 0, sizeof(sc->sc_mcu_wait[0])); - sc->sc_mcu_wait[seq].mcu_cmd = cmd; - rv = tsleep_nsec(&sc->sc_mcu_wait[seq], 0, "mwxwait", SEC_TO_NSEC(3)); if (rv != 0) { printf("%s: command %x timeout\n", DEVNAME(sc), cmd); @@ -2694,9 +2718,6 @@ mwx_mcu_wait_resp_msg(struct mwx_softc *sc, uint32_t cmd, int seq, KASSERT(seq < nitems(sc->sc_mcu_wait)); - memset(&sc->sc_mcu_wait[seq], 0, sizeof(sc->sc_mcu_wait[0])); - sc->sc_mcu_wait[seq].mcu_cmd = cmd; - rv = tsleep_nsec(&sc->sc_mcu_wait[seq], 0, "mwxwait", SEC_TO_NSEC(3)); if (rv != 0) { printf("%s: command %x timeout\n", DEVNAME(sc), cmd); @@ -2974,10 +2995,17 @@ mwx_mcu_init(struct mwx_softc *sc) if ((rv = mwx_load_firmware(sc)) != 0) return rv; - if ((rv = mt7921_mcu_get_nic_capability(sc)) != 0) - return rv; - if ((rv = mt7921_mcu_fw_log_2_host(sc, 1)) != 0) - return rv; + if (sc->sc_hwtype == MWX_HW_MT7925) { + if ((rv = mt7925_mcu_get_nic_capability(sc)) != 0) + return rv; + if ((rv = mt7925_mcu_fw_log_2_host(sc, 1)) != 0) + return rv; + } else { + if ((rv = mt7921_mcu_get_nic_capability(sc)) != 0) + return rv; + if ((rv = mt7921_mcu_fw_log_2_host(sc, 1)) != 0) + return rv; + } /* TODO mark MCU running */ @@ -3196,6 +3224,7 @@ out: DPRINTF("%s: firmware loaded\n", DEVNAME(sc)); rv = 0; + /* TODO load CLC data if available */ fail: free(buf, M_DEVBUF, buflen); free(fwbuf, M_DEVBUF, fwlen); @@ -3396,20 +3425,7 @@ mt7921_mcu_get_nic_capability(struct mwx_softc *sc) uint32_t type; uint32_t len; } __packed *tlv; - struct mt76_connac_phy_cap { - uint8_t ht; - uint8_t vht; - uint8_t _5g; - uint8_t max_bw; - uint8_t nss; - uint8_t dbdc; - uint8_t tx_ldpc; - uint8_t rx_ldpc; - uint8_t tx_stbc; - uint8_t rx_stbc; - uint8_t hw_path; - uint8_t he; - } __packed *cap; + struct mwx_connac_phy_cap *cap; struct mbuf *m; int rv, seq, count, i; @@ -3446,8 +3462,12 @@ mt7921_mcu_get_nic_capability(struct mwx_softc *sc) len = le32toh(tlv->len); m_adj(m, sizeof(*tlv)); - if (m->m_len < len) - break; + if (m->m_len < len) { + printf("%s: GET_NIC_CAPAB tlv length error\n", + DEVNAME(sc)); + m_freem(m); + return EINVAL; + } switch (type) { case MT_NIC_CAP_6G: /* TODO 6GHZ SUPPORT */ @@ -3461,7 +3481,7 @@ mt7921_mcu_get_nic_capability(struct mwx_softc *sc) case MT_NIC_CAP_PHY: if (len < sizeof(*cap)) break; - cap = mtod(m, struct mt76_connac_phy_cap *); + cap = mtod(m, struct mwx_connac_phy_cap *); sc->sc_capa.num_streams = cap->nss; sc->sc_capa.antenna_mask = (1U << cap->nss) - 1; @@ -3481,6 +3501,102 @@ mt7921_mcu_get_nic_capability(struct mwx_softc *sc) return 0; } +int +mt7925_mcu_get_nic_capability(struct mwx_softc *sc) +{ + struct mt76_connac_cap_hdr { + uint16_t n_elements; + uint8_t pad[2]; + } __packed *hdr; + struct tlv_hdr { + uint16_t tag; + uint16_t len; + } __packed *tlv; + struct mwx_connac_phy_cap *cap; + struct mbuf *m; + struct { + uint8_t rsv[4]; + uint16_t tag; + uint16_t len; + } __packed req = { + .tag = htole16(UNI_CHIP_CONFIG_NIC_CAPA), + .len = htole16(sizeof(req) - 4), + }; + int rv, seq, count, i; + + rv = mwx_mcu_send_msg(sc, MCU_UNI_CMD_CHIP_CONFIG, &req, sizeof(req), + &seq); + if (rv != 0) + return rv; + + rv = mwx_mcu_wait_resp_msg(sc, MCU_UNI_CMD_CHIP_CONFIG, seq, &m); + if (rv != 0) + return rv; + + if (m->m_len < sizeof(*hdr)) { + printf("%s: CHIP_CONFIG NIC_CAPA response size error\n", + DEVNAME(sc)); + m_freem(m); + return EINVAL; + } + hdr = mtod(m, struct mt76_connac_cap_hdr *); + count = le16toh(hdr->n_elements); + m_adj(m, sizeof(*hdr)); + + for (i = 0; i < count; i++) { + uint16_t tag, len; + + if (m->m_len < sizeof(*tlv)) { + printf("%s: GET_NIC_CAPAB tlv size error\n", + DEVNAME(sc)); + m_freem(m); + return EINVAL; + } + + tlv = mtod(m, struct tlv_hdr *); + tag = le16toh(tlv->tag); + len = le16toh(tlv->len); + /* unlike 7921 the len includes the header */ + if (len < sizeof(*tlv) || m->m_len < len) { + printf("%s: GET_NIC_CAPAB tlv length error\n", + DEVNAME(sc)); + m_freem(m); + return EINVAL; + } + len -= sizeof(*tlv); + m_adj(m, sizeof(*tlv)); + + switch (tag) { + case MT_NIC_CAP_6G: + /* TODO 6GHZ SUPPORT */ + sc->sc_capa.has_6ghz = 0; /* *mtod(m, caddr_t) != 0; */ + break; + case MT_NIC_CAP_MAC_ADDR: + if (len < ETHER_ADDR_LEN) + break; + memcpy(sc->sc_lladdr, mtod(m, caddr_t), ETHER_ADDR_LEN); + break; + case MT_NIC_CAP_PHY: + if (len < sizeof(*cap)) + break; + cap = mtod(m, struct mwx_connac_phy_cap *); + + sc->sc_capa.num_streams = cap->nss; + sc->sc_capa.antenna_mask = (1U << cap->nss) - 1; + sc->sc_capa.has_2ghz = cap->hw_path & 0x01; + sc->sc_capa.has_5ghz = cap->hw_path & 0x02; + break; + } + + m_adj(m, len); + } + + printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(sc->sc_lladdr)); + + m_freem(m); + return 0; +} + int mt7921_mcu_fw_log_2_host(struct mwx_softc *sc, uint8_t ctrl) { @@ -3495,6 +3611,26 @@ mt7921_mcu_fw_log_2_host(struct mwx_softc *sc, uint8_t ctrl) sizeof(req), NULL); } +int +mt7925_mcu_fw_log_2_host(struct mwx_softc *sc, uint8_t ctrl) +{ + struct { + uint8_t rsv[4]; + uint16_t tag; + uint16_t len; + uint8_t ctrl; + uint8_t interval; + uint8_t rsv2[2]; + } req = { + .tag = htole16(UNI_WSYS_CONFIG_FW_LOG_CTRL), + .len = htole16(sizeof(req) - 4), + .ctrl = ctrl, + }; + + return mwx_mcu_send_msg(sc, MCU_UNI_CMD_WSYS_CONFIG, &req, + sizeof(req), NULL); +} + int mt7921_mcu_set_eeprom(struct mwx_softc *sc) { @@ -5109,7 +5245,7 @@ mt7921_alloc_sta_tlv(int len) return NULL; /* align to have space for the mcu header */ - m->m_data += sizeof(struct mt7921_mcu_txd) + len; + m->m_data += sizeof(struct mwx_mcu_txd) + len; m->m_len = m->m_pkthdr.len = 0; return m; diff --git a/sys/dev/pci/if_mwxreg.h b/sys/dev/pci/if_mwxreg.h index 7a53322ec73..cc4c5e8be0a 100644 --- a/sys/dev/pci/if_mwxreg.h +++ b/sys/dev/pci/if_mwxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mwxreg.h,v 1.15 2026/06/04 13:15:20 claudio Exp $ */ +/* $OpenBSD: if_mwxreg.h,v 1.16 2026/06/04 19:26:48 claudio Exp $ */ /* * Copyright (c) 2022 Claudio Jeker * Copyright (C) 2021 MediaTek Inc. @@ -104,7 +104,7 @@ /* AGG: band 0(0x20800), band 1(0xa0800) */ #define MT_AGG_ACR0(_band) MT_BAND_ADDR(_band, 0x2084) #define MT_AGG_ACR_CFEND_RATE_MASK 0x00001fff -#define MT7921_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ +#define MT7921_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7921_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ #define MT_AGG_ACR_BAR_RATE GENMASK(29, 16) @@ -259,8 +259,8 @@ #define MT_WFDMA0_RST_DTX_PTR 0xd420c #define MT_WFDMA0_RST_DRX_PTR 0xd4280 -#define MT_WFDMA0_INT_RX_PRI 0xd4298 -#define MT_WFDMA0_INT_TX_PRI 0xd429c +#define MT_WFDMA0_INT_RX_PRI 0xd4298 +#define MT_WFDMA0_INT_TX_PRI 0xd429c #define MT_WFDMA0_GLO_CFG_EXT0 0xd42b0 #define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE (1U << 6) #define MT_WFDMA0_PRI_DLY_INT_CFG0 0xd42f0 @@ -465,6 +465,7 @@ struct mt76_txwi { #define MCU_CMD_UNI 0x02 #define MCU_CMD_QUERY 0x04 #define MCU_CMD_UNI_EXT_ACK (MCU_CMD_ACK | MCU_CMD_UNI | MCU_CMD_QUERY) +#define MCU_CMD_UNI_QUERY_ACK (MCU_CMD_ACK | MCU_CMD_UNI) #define MCU_CMD_FIELD_ID_MASK 0x000000ff #define MCU_CMD_FIELD_EXT_ID_MASK 0x0000ff00 @@ -473,6 +474,7 @@ struct mt76_txwi { #define MCU_CMD_FIELD_UNI (1U << 17) #define MCU_CMD_FIELD_CE (1U << 18) #define MCU_CMD_FIELD_WA (1U << 19) +#define MCU_CMD_FIELD_WM (1U << 20) #define MCU_CMD_TARGET_ADDRESS_LEN_REQ 0x00000001 #define MCU_CMD_FW_START_REQ 0x00000002 @@ -542,6 +544,8 @@ struct mt76_txwi { #define MCU_UNI_CMD_SUSPEND 0x00020005 #define MCU_UNI_CMD_OFFLOAD 0x00020006 #define MCU_UNI_CMD_HIF_CTRL 0x00020007 +#define MCU_UNI_CMD_WSYS_CONFIG 0x0002000b +#define MCU_UNI_CMD_CHIP_CONFIG 0x0002000e #define MCU_UNI_CMD_SNIFFER 0x00020024 #define UNI_BSS_INFO_BASIC 0 @@ -554,6 +558,14 @@ struct mt76_txwi { #define UNI_BSS_INFO_PS 21 #define UNI_BSS_INFO_BCNFT 22 +#define UNI_CHIP_CONFIG_CHIP_CFG 2 +#define UNI_CHIP_CONFIG_NIC_CAPA 3 + +#define UNI_EFUSE_ACCESS 1 +#define UNI_EFUSE_BUFFER_MODE 2 + +#define UNI_WSYS_CONFIG_FW_LOG_CTRL 0 + /* offload mcu commands */ #define MCU_CE_CMD_TEST_CTRL 0x00040001 #define MCU_CE_CMD_START_HW_SCAN 0x00040003 @@ -656,12 +668,18 @@ struct mt76_txwi { #define MT_TXD0_ETH_TYPE_OFFSET 0x007f0000 #define MT_TXD0_TX_BYTES_MASK 0x0000ffff -/* values for MT_TXD1_HDR_FORMAT */ +/* values for MT_TXD1_HDR_FORMAT for connac2 */ #define MT_HDR_FORMAT_802_3 (0 << 16) #define MT_HDR_FORMAT_CMD (1 << 16) #define MT_HDR_FORMAT_802_11 (2 << 16) #define MT_HDR_FORMAT_802_11_EXT (3 << 16) +/* values for MT_TXD1_HDR_FORMAT for connac3 (MT7925) */ +#define MT7925_HDR_FORMAT_802_3 (0 << 14) +#define MT7925_HDR_FORMAT_CMD (1 << 14) +#define MT7925_HDR_FORMAT_802_11 (2 << 14) +#define MT7925_HDR_FORMAT_802_11_EXT (3 << 14) + #define MT_TXD1_LONG_FORMAT (1U << 31) #define MT_TXD1_TGID (1U << 30) #define MT_TXD1_OWN_MAC_MASK 0x3f000000 @@ -858,7 +876,7 @@ struct mt76_txwi { #define PKT_TYPE_RX_EVENT 7 #define PKT_TYPE_NORMAL_MCU 8 -struct mt7921_mcu_txd { +struct mwx_mcu_txd { uint32_t txd[8]; uint16_t len; @@ -878,7 +896,7 @@ struct mt7921_mcu_txd { } __packed __aligned(4); /** - * struct mt7921_uni_txd - mcu command descriptor for firmware v3 + * struct mwx_uni_txd - mcu command descriptor for firmware v3 * @txd: hardware descriptor * @len: total length not including txd * @cid: command identifier @@ -906,7 +924,7 @@ struct mt7921_mcu_txd { * 0: QUERY command * 1: SET command */ -struct mt7921_uni_txd { +struct mwx_uni_txd { uint32_t txd[8]; /* DW1 */ @@ -960,6 +978,21 @@ struct mt7921_mcu_reg_event { uint32_t val; } __packed; +struct mwx_connac_phy_cap { + uint8_t ht; + uint8_t vht; + uint8_t _5g; + uint8_t max_bw; + uint8_t nss; + uint8_t dbdc; + uint8_t tx_ldpc; + uint8_t rx_ldpc; + uint8_t tx_stbc; + uint8_t rx_stbc; + uint8_t hw_path; + uint8_t he; +} __packed; + struct mt76_connac_config { uint16_t id; uint8_t type; @@ -969,7 +1002,7 @@ struct mt76_connac_config { uint8_t data[320]; }; -#define MT_SKU_POWER_LIMIT 161 +#define MT_SKU_POWER_LIMIT 161 struct mt76_connac_sku_tlv { uint8_t channel;