1
0
mirror of https://github.com/openbsd/src.git synced 2026-06-18 07:13:36 +02:00

Fix mwx_mcu_send_mbuf() for both mt7925 and mt7921 and the next bit

of 7925 bringup.

mwx_mcu_send_mbuf() handling of the len field was not quite right. Also
implement the mt7925 bits for UNI commands. Fix an issue with the wakeup
of commands, register the command in sc_mcu_wait before enqueuing the
command into the tx queue. Cleanup on error as well.

Implement mt7925_mcu_get_nic_capability() and mt7925_mcu_fw_log_2_host()
with this mwx_mcu_init() is done.

In mwx_dma_txwi_enqueue() use the right len0 value (mt_desc is a pointer).

With this MT7925 prints the mac-address (mwx_mcu_init() succeeds) but
more is needed mwx_init_hardware() after that mwx_preinit() should pass
which is a big step.

For MT7921 it seems this fixes the TX issue I was trying to fix for
so long. Also with this the driver works like before with the new
firmware package.

Mostly adapted form a large diff from mlarkin@
This commit is contained in:
claudio
2026-06-04 19:26:48 +00:00
parent 0863b78107
commit fd5e443660
2 changed files with 221 additions and 52 deletions
+179 -43
View File
@@ -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 <claudio@openbsd.org>
* 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;
+42 -9
View File
@@ -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 <claudio@openbsd.org>
* 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;