If there's someone who wants to dig into this, but lack a card, I have one I can send.
Claudio Jeker <cje...@diehard.n-r-g.com> wrote: > Here is the start of mwx(4) a driver for the MediaTek MT7921 chip which > shipped for example in Lenovo AMD T14 Gen 2 laptops. > So far the firmware loading works reliably and also the various DMA ring > operate. It is possible to send commands and get answers. The problem > where I got stuck now for a while is that the scan command fails to scan > more than channel 1 and switching channel puts the device into a broken > state. > > I kind of hit a wall and hope someone else would like to join and share > the pain. To enable the driver add 'mwx* at pci?' to your kernel config. > > -- > :wq Claudio > > Index: files.pci > =================================================================== > RCS file: /cvs/src/sys/dev/pci/files.pci,v > retrieving revision 1.359 > diff -u -p -r1.359 files.pci > --- files.pci 31 Mar 2022 21:41:17 -0000 1.359 > +++ files.pci 5 Apr 2022 06:44:51 -0000 > @@ -850,5 +850,10 @@ file dev/pci/igc_phy.c igc > attach com at pci with com_pci > file dev/pci/com_pci.c com_pci > > +# MediaTek MT7921E wifi > +device mwx: ifnet, wlan, firmload > +attach mwx at pci > +file dev/pci/if_mwx.c mwx > + > include "dev/pci/files.agp" > include "dev/pci/drm/files.drm" > Index: if_mwx.c > =================================================================== > RCS file: if_mwx.c > diff -N if_mwx.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ if_mwx.c 9 Dec 2022 17:03:39 -0000 > @@ -0,0 +1,3652 @@ > +/* > + * Copyright (c) 2022 Claudio Jeker <clau...@openbsd.org> > + * Copyright (c) 2021 MediaTek Inc. > + * Copyright (c) 2021 Lorenzo Bianconi <lorenzo.biancon...@gmail.com> > + * Copyright (c) 2017 Stefan Sperling <s...@openbsd.org> > + * Copyright (c) 2016 Felix Fietkau <n...@nbd.name> > + * Copyright (c) 2007-2010 Damien Bergamini <damien.bergam...@free.fr> > + * > + * Permission to use, copy, modify, and/or distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include "bpfilter.h" > + > +#include <sys/param.h> > +#include <sys/systm.h> > +#include <sys/atomic.h> > +#include <sys/sockio.h> > + > +#include <machine/bus.h> > +#include <machine/intr.h> > + > +#include <dev/pci/pcireg.h> > +#include <dev/pci/pcivar.h> > +#include <dev/pci/pcidevs.h> > + > +#if NBPFILTER > 0 > +#include <net/bpf.h> > +#endif > +#include <net/if.h> > +#include <net/if_dl.h> > +#include <net/if_media.h> > + > +#include <netinet/in.h> > +#include <netinet/if_ether.h> > + > +#include <net80211/ieee80211_var.h> > +#include <net80211/ieee80211_radiotap.h> > + > +#include <dev/pci/if_mwxreg.h> > + > +static const struct pci_matchid mwx_devices[] = { > + { PCI_VENDOR_MEDIATEK, PCI_PRODUCT_MEDIATEK_MT7921 }, > + { PCI_VENDOR_MEDIATEK, PCI_PRODUCT_MEDIATEK_MT7921K }, > +}; > + > +#define MWX_DEBUG 1 > + > +#define MT7921_ROM_PATCH "mt7961_1_2_rom_patch.bin" > +#define MT7921_FIRMWARE_WM "mt7961_1.bin" > + > +#if NBPFILTER > 0 > +struct mwx_rx_radiotap_header { > + struct ieee80211_radiotap_header wr_ihdr; > + uint64_t wr_tsft; > + uint8_t wr_flags; > + uint8_t wr_rate; > + uint16_t wr_chan_freq; > + uint16_t wr_chan_flags; > + int8_t wr_dbm_antsignal; > + int8_t wr_dbm_antnoise; > +} __packed; > + > +#define MWX_RX_RADIOTAP_PRESENT \ > + ((1 << IEEE80211_RADIOTAP_TSFT) | \ > + (1 << IEEE80211_RADIOTAP_FLAGS) | \ > + (1 << IEEE80211_RADIOTAP_RATE) | \ > + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ > + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ > + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)) > + > +struct mwx_tx_radiotap_header { > + struct ieee80211_radiotap_header wt_ihdr; > + uint8_t wt_flags; > + uint8_t wt_rate; > + uint16_t wt_chan_freq; > + uint16_t wt_chan_flags; > +} __packed; > + > +#define MWX_TX_RADIOTAP_PRESENT \ > + ((1 << IEEE80211_RADIOTAP_FLAGS) | \ > + (1 << IEEE80211_RADIOTAP_RATE) | \ > + (1 << IEEE80211_RADIOTAP_CHANNEL)) > + > +#endif > + > +struct mwx_data { > + struct mbuf *md_data; > + bus_dmamap_t md_map; > +}; > + > +struct mwx_queue { > + uint32_t mq_regbase; > + u_int mq_count; > + u_int mq_prod; > + u_int mq_cons; > + > + struct mt76_desc *mq_desc; > + struct mwx_data *mq_data; > + > + bus_dmamap_t mq_map; > + bus_dma_segment_t mq_seg; > + int mq_wakeme; > +}; > + > +struct mwx_hw_capa { > + int8_t has_2ghz; > + int8_t has_5ghz; > + int8_t has_6ghz; > + uint8_t antenna_mask; > + uint8_t num_streams; > +}; > + > +struct mwx_node { > + struct ieee80211_node ni; > + uint16_t wcid; > + uint8_t hw_key_idx; /* encryption key index */ > + uint8_t hw_key_idx2; > +}; > + > +struct mwx_vif { > + uint8_t idx; > + uint8_t omac_idx; > + uint8_t band_idx; > + uint8_t wmm_idx; > + uint8_t scan_seq_num; > +}; > + > +struct mwx_softc { > + struct device sc_dev; > + struct ieee80211com sc_ic; > + > + struct mwx_queue sc_txq; > + struct mwx_queue sc_txmcuq; > + struct mwx_queue sc_txfwdlq; > + > + struct mwx_queue sc_rxq; > + struct mwx_queue sc_rxmcuq; > + struct mwx_queue sc_rxfwdlq; > + > + bus_space_tag_t sc_st; > + bus_space_handle_t sc_memh; > + bus_size_t sc_mems; > + bus_dma_tag_t sc_dmat; > + pcitag_t sc_tag; > + pci_chipset_tag_t sc_pc; > + void *sc_ih; > + > + int (*sc_newstate)(struct ieee80211com *, > + enum ieee80211_state, int); > + > + struct task sc_reset_task; > + u_int sc_flags; > +#define MWX_FLAG_SCANNING 0x01 > +#define MWX_FLAG_BGSCAN 0x02 > + int8_t sc_resetting; > + int8_t sc_fw_loaded; > + > +#if NBPFILTER > 0 > + caddr_t sc_drvbpf; > + union { > + struct mwx_rx_radiotap_header th; > + uint8_t pad[IEEE80211_RADIOTAP_HDRLEN]; > + } sc_rxtapu; > + int sc_rxtap_len; > + union { > + struct mwx_tx_radiotap_header th; > + uint8_t pad[IEEE80211_RADIOTAP_HDRLEN]; > + } sc_txtapu; > + int sc_txtap_len; > +#define sc_rxtap sc_rxtapu.th > +#define sc_txtap sc_txtapu.th > +#endif > + > + /* mcu */ > + uint32_t sc_mcu_seq; > + struct { > + struct mbuf *mcu_m; > + uint32_t mcu_cmd; > + uint32_t mcu_int; > + } sc_mcu_wait[16]; > + struct mwx_vif sc_vif; > + uint8_t sc_scan_seq_num; > + > + /* phy / hw */ > + struct mwx_hw_capa sc_capa; > + uint8_t sc_lladdr[ETHER_ADDR_LEN]; > + char sc_alpha2[4]; /* regulatory-domain */ > + > + /* mac specific */ > + uint32_t sc_rxfilter; > + > +}; > + > +const uint8_t mwx_channels_2ghz[] = { > + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 > +}; > + > +#define MWX_NUM_2GHZ_CHANNELS nitems(mwx_channels_2ghz) > + > +const uint8_t mwx_channels_5ghz[] = { > + 36, 40, 44, 48, 52, 56, 60, 64, > + 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, > + 149, 153, 157, 161, 165, 169, 173 > +}; > + > +#define MWX_NUM_5GHZ_CHANNELS nitems(mwx_channels_5ghz) > + > +const uint8_t mwx_channels_6ghz[] = { > + /* UNII-5 */ > + 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, > + 61, 65, 69, 73, 77, 81, 85, 89, 93, > + /* UNII-6 */ > + 97, 101, 105, 109, 113, 117, > + /* UNII-7 */ > + 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, > + 173, 177, 181, 185, > + /* UNII-8 */ > + 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233 > +}; > + > +#define MWX_NUM_6GHZ_CHANNELS nitems(mwx_channels_6ghz) > + > +#define DEVNAME(s) ((s)->sc_dev.dv_xname) > +#define DEVDEBUG(x) ((x)->sc_ic.ic_if.if_flags & IFF_DEBUG) > + > +#ifdef MWX_DEBUG > +#define DPRINTF(x...) printf(x) > +#else > +#define DPRINTF(x...) > +#endif > + > +int mwx_init(struct ifnet *); > +void mwx_stop(struct ifnet *); > +void mwx_watchdog(struct ifnet *); > +void mwx_start(struct ifnet *); > +int mwx_ioctl(struct ifnet *, u_long, caddr_t); > + > +struct ieee80211_node *mwx_node_alloc(struct ieee80211com *); > +int mwx_media_change(struct ifnet *); > +#if NBPFILTER > 0 > +void mwx_radiotap_attach(struct mwx_softc *); > +#endif > + > +int mwx_tx(struct mwx_softc *, struct mbuf *, struct ieee80211_node *); > +void mwx_rx(struct mwx_softc *, struct mbuf *, struct mbuf_list *); > +int mwx_intr(void *); > +int mwx_preinit(struct mwx_softc *); > +void mwx_attach_hook(struct device *); > +int mwx_match(struct device *, void *, void *); > +void mwx_attach(struct device *, struct device *, void *); > +int mwx_activate(struct device *, int); > + > +void mwx_reset(struct mwx_softc *); > +void mwx_reset_task(void *); > +int mwx_queue_alloc(struct mwx_softc *, struct mwx_queue *, int, uint32_t); > +void mwx_queue_free(struct mwx_softc *, struct mwx_queue *); > +void mwx_queue_reset(struct mwx_softc *, struct mwx_queue *); > +int mwx_buf_fill(struct mwx_softc *, struct mwx_data *, struct mt76_desc *); > +int mwx_queue_fill(struct mwx_softc *, struct mwx_queue *); > +int mwx_dma_alloc(struct mwx_softc *); > +int mwx_dma_reset(struct mwx_softc *, int); > +void mwx_dma_free(struct mwx_softc *); > +int mwx_dma_tx_enqueue(struct mwx_softc *, struct mwx_queue *, > + struct mbuf *, uint32_t); > +void mwx_dma_tx_cleanup(struct mwx_softc *, struct mwx_queue *); > +void mwx_dma_tx_done(struct mwx_softc *); > +void mwx_dma_rx_process(struct mwx_softc *, struct mbuf_list *); > +void mwx_dma_rx_dequeue(struct mwx_softc *, struct mwx_queue *, > + struct mbuf_list *); > +void mwx_dma_rx_done(struct mwx_softc *, struct mwx_queue *); > + > +int mwx_mcu_send_msg(struct mwx_softc *, uint32_t, void *, size_t, int *); > +int mwx_mcu_send_wait(struct mwx_softc *, uint32_t, void *, size_t); > +void mwx_mcu_rx_event(struct mwx_softc *, struct mbuf *); > +int mwx_mcu_wait_resp_int(struct mwx_softc *, uint32_t, int, uint32_t *); > +int mwx_mcu_wait_resp_msg(struct mwx_softc *, uint32_t, int, > + struct mbuf **); > + > +int mt7921_dma_disable(struct mwx_softc *sc, int force); > +void mt7921_dma_enable(struct mwx_softc *sc); > +int mt7921_wfsys_reset(struct mwx_softc *sc); > +uint32_t mt7921_reg_addr(struct mwx_softc *, uint32_t); > +int mt7921_init_hardware(struct mwx_softc *); > +int mt7921_mcu_init(struct mwx_softc *); > +int mt7921_load_firmware(struct mwx_softc *); > +int mt7921_mac_wtbl_update(struct mwx_softc *, int); > +void mt7921_mac_init_band(struct mwx_softc *sc, uint32_t); > +int mt7921_mac_init(struct mwx_softc *); > +int mt7921_mcu_patch_sem_ctrl(struct mwx_softc *, int); > +int mt7921_mcu_init_download(struct mwx_softc *, uint32_t, > + uint32_t, uint32_t); > +int mt7921_mcu_send_firmware(struct mwx_softc *, int, > + u_char *, size_t, size_t); > +int mt7921_mcu_start_patch(struct mwx_softc *); > +int mt7921_mcu_start_firmware(struct mwx_softc *, uint32_t, > + uint32_t); > +int mt7921_mcu_get_nic_capability(struct mwx_softc *); > +int mt7921_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); > +int mt7921_mcu_set_deep_sleep(struct mwx_softc *, int); > +void mt7921_mcu_low_power_event(struct mwx_softc *, struct mbuf *); > +void mt7921_mcu_tx_done_event(struct mwx_softc *, struct mbuf *); > +void mt7921_mcu_scan_event(struct mwx_softc *, struct mbuf *); > +int mt7921_hw_scan(struct mwx_softc *, int); > +int mt7921_hw_scan_cancel(struct mwx_softc *); > +int mt7921_mcu_set_mac_enable(struct mwx_softc *, int, int); > +int mt7921_mcu_set_channel_domain(struct mwx_softc *); > +uint8_t mt7921_mcu_chan_bw(struct ieee80211_channel *channel); > +int mt7921_mcu_set_chan_info(struct mwx_softc *, int); > +void mt7921_mac_reset_counters(struct mwx_softc *); > +int mt7921_mcu_uni_add_dev(struct mwx_softc *, struct mwx_vif *, > + struct mwx_node *, int); > +int mt7921_mcu_set_sniffer(struct mwx_softc *, int); > +int mt7921_mcu_set_beacon_filter(struct mwx_softc *, int); > +int mt7921_mac_fill_rx(struct mwx_softc *, struct mbuf *, > + struct ieee80211_rxinfo *); > + > + > +static inline uint32_t > +mwx_read(struct mwx_softc *sc, uint32_t reg) > +{ > + reg = mt7921_reg_addr(sc, reg); > + return bus_space_read_4(sc->sc_st, sc->sc_memh, reg); > +} > + > +static inline void > +mwx_write(struct mwx_softc *sc, uint32_t reg, uint32_t val) > +{ > + reg = mt7921_reg_addr(sc, reg); > + bus_space_write_4(sc->sc_st, sc->sc_memh, reg, val); > +} > + > +static inline void > +mwx_barrier(struct mwx_softc *sc) > +{ > + bus_space_barrier(sc->sc_st, sc->sc_memh, 0, sc->sc_mems, > + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); > +} > + > +static inline uint32_t > +mwx_rmw(struct mwx_softc *sc, uint32_t reg, uint32_t val, uint32_t mask) > +{ > + reg = mt7921_reg_addr(sc, reg); > + val |= bus_space_read_4(sc->sc_st, sc->sc_memh, reg) & ~mask; > + bus_space_write_4(sc->sc_st, sc->sc_memh, reg, val); > + return val; > +} > + > +static inline uint32_t > +mwx_set(struct mwx_softc *sc, uint32_t reg, uint32_t bits) > +{ > + return mwx_rmw(sc, reg, bits, 0); > +} > + > +static inline uint32_t > +mwx_clear(struct mwx_softc *sc, uint32_t reg, uint32_t bits) > +{ > + return mwx_rmw(sc, reg, 0, bits); > +} > + > +static inline uint32_t > +mwx_map_reg_l1(struct mwx_softc *sc, uint32_t reg) > +{ > + uint32_t offset = MT_HIF_REMAP_L1_GET_OFFSET(reg); > + uint32_t base = MT_HIF_REMAP_L1_GET_BASE(reg); > + > + mwx_rmw(sc, MT_HIF_REMAP_L1, base, MT_HIF_REMAP_L1_MASK); > + mwx_barrier(sc); > + > + return MT_HIF_REMAP_BASE_L1 + offset; > +} > + > +/* > + * Poll for timeout miliseconds or until register reg read the value val > + * after applying the mask to the value read. Returns 0 on success ETIMEDOUT > + * on failure. > + */ > +int > +mwx_poll(struct mwx_softc *sc, uint32_t reg, uint32_t val, uint32_t mask, > + int timeout) > +{ > + uint32_t cur; > + > + reg = mt7921_reg_addr(sc, reg); > + timeout *= 100; > + do { > + cur = bus_space_read_4(sc->sc_st, sc->sc_memh, reg) & mask; > + if (cur == val) > + return 0; > + delay(10); > + } while (timeout-- > 0); > + > + DPRINTF("%s: poll timeout reg %x val %x mask %x cur %x\n", > + DEVNAME(sc), reg, val, mask, cur); > + return ETIMEDOUT; > +} > + > +/* > + * ifp specific functions > + */ > +int > +mwx_init(struct ifnet *ifp) > +{ > + struct mwx_softc *sc = ifp->if_softc; > + struct ieee80211com *ic = &sc->sc_ic; > + int rv; > + > + if (!sc->sc_fw_loaded) { > + rv = mwx_preinit(sc); > + if (rv) > + return rv; > + } > + > + DPRINTF("%s: init\n", DEVNAME(sc)); > + mt7921_mcu_set_deep_sleep(sc, 0); > + > + rv = mt7921_mcu_set_mac_enable(sc, 0, 1); > + if (rv) > + return rv; > + > + rv = mt7921_mcu_set_channel_domain(sc); > + if (rv) > + return rv; > + > + rv = mt7921_mcu_set_chan_info(sc, MCU_EXT_CMD_SET_RX_PATH); > + if (rv) > + return rv; > + > + /* XXX TODO > + rv = mt76_connac_mcu_set_rate_txpower(sc); > + if (rv) > + return rv; > + */ > + > + if (ic->ic_opmode == IEEE80211_M_MONITOR) { > + mt7921_mcu_set_sniffer(sc, 1); > + mt7921_mcu_set_beacon_filter(sc, 0); > + sc->sc_rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; > + mwx_set(sc, MT_DMA_DCR0(0), MT_DMA_DCR0_RXD_G5_EN); > + } else { > + mt7921_mcu_set_sniffer(sc, 0); > + sc->sc_rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; > + mwx_clear(sc, MT_DMA_DCR0(0), MT_DMA_DCR0_RXD_G5_EN); > + } > + mwx_write(sc, MT_WF_RFCR(0), sc->sc_rxfilter); > + > + mt7921_mac_reset_counters(sc); > + > + rv = mt7921_mcu_uni_add_dev(sc, &sc->sc_vif, (void *)ic->ic_bss, 1); > + if (rv) > + return rv; > + > + ifp->if_flags |= IFF_RUNNING; > + ifq_clr_oactive(&ifp->if_snd); > + > + if (ic->ic_opmode == IEEE80211_M_MONITOR) { > + ic->ic_bss->ni_chan = ic->ic_ibss_chan; > + ieee80211_new_state(ic, IEEE80211_S_RUN, -1); > + return 0; > + } > + > + ieee80211_begin_scan(ifp); > + > + /* > + * ieee80211_begin_scan() ends up scheduling iwx_newstate_task(). > + * Wait until the transition to SCAN state has completed. > + */ > + > + return 0; > +} > + > +void > +mwx_stop(struct ifnet *ifp) > +{ > + struct mwx_softc *sc = ifp->if_softc; > + struct ieee80211com *ic = &sc->sc_ic; > + > + DPRINTF("%s: stop\n", DEVNAME(sc)); > + > + //XXX sc->sc_flags |= MWX_FLAG_SHUTDOWN; > + /* Cancel scheduled tasks and let any stale tasks finish up. */ > + task_del(systq, &sc->sc_reset_task); > + > + ifp->if_timer = 0; > + ifp->if_flags &= ~IFF_RUNNING; > + ifq_clr_oactive(&ifp->if_snd); > + > + ieee80211_new_state(ic, IEEE80211_S_INIT, -1); /* free all nodes */ > + > + mt7921_mcu_set_mac_enable(sc, 0, 0); > + > + /* XXX anything more ??? */ > + /* check out mt7921e_mac_reset, mt7921e_unregister_device and > + mt7921_pci_suspend > + */ > +} > + > +void > +mwx_watchdog(struct ifnet *ifp) > +{ > + ifp->if_timer = 0; > + ieee80211_watchdog(ifp); > +} > + > +void > +mwx_start(struct ifnet *ifp) > +{ > + struct mwx_softc *sc = ifp->if_softc; > + struct ieee80211com *ic = &sc->sc_ic; > + struct ieee80211_node *ni; > + struct ether_header *eh; > + struct mbuf *m; > + > + if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) > + return; > + > + for (;;) { > + /* XXX TODO handle oactive > + ifq_set_oactive(&ifp->if_snd); > + */ > + > + /* need to send management frames even if we're not RUNning */ > + m = mq_dequeue(&ic->ic_mgtq); > + if (m) { > + ni = m->m_pkthdr.ph_cookie; > + goto sendit; > + } > + > + if (ic->ic_state != IEEE80211_S_RUN || > + (ic->ic_xflags & IEEE80211_F_TX_MGMT_ONLY)) > + break; > + > + m = ifq_dequeue(&ifp->if_snd); > + if (!m) > + break; > + if (m->m_len < sizeof (*eh) && > + (m = m_pullup(m, sizeof (*eh))) == NULL) { > + ifp->if_oerrors++; > + continue; > + } > +#if NBPFILTER > 0 > + if (ifp->if_bpf != NULL) > + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); > +#endif > + if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) { > + ifp->if_oerrors++; > + continue; > + } > + > + sendit: > +#if NBPFILTER > 0 > + if (ic->ic_rawbpf != NULL) > + bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT); > +#endif > + if (mwx_tx(sc, m, ni) != 0) { > + ieee80211_release_node(ic, ni); > + ifp->if_oerrors++; > + continue; > + } > + > + if (ifp->if_flags & IFF_UP) > + ifp->if_timer = 1; > + } > +} > + > +int > +mwx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) > +{ > + int s, err = 0; > + > + s = splnet(); > + switch (cmd) { > + case SIOCSIFADDR: > + ifp->if_flags |= IFF_UP; > + /* FALLTHROUGH */ > + case SIOCSIFFLAGS: > + if (ifp->if_flags & IFF_UP) { > + if (!(ifp->if_flags & IFF_RUNNING)) { > + mwx_stop(ifp); > + err = mwx_init(ifp); > + } > + } else { > + if (ifp->if_flags & IFF_RUNNING) > + mwx_stop(ifp); > + } > + break; > + default: > + err = ieee80211_ioctl(ifp, cmd, data); > + break; > + } > + > + if (err == ENETRESET) { > + err = 0; > + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == > + (IFF_UP | IFF_RUNNING)) { > + mwx_stop(ifp); > + err = mwx_init(ifp); > + } > + } > + splx(s); > + return err; > +} > + > +int > +mwx_media_change(struct ifnet *ifp) > +{ > + struct mwx_softc *sc = ifp->if_softc; > + struct ieee80211com *ic = &sc->sc_ic; > + int err; > + > + err = ieee80211_media_change(ifp); > + if (err != ENETRESET) > + return err; > + > + /* TODO lot more handling here */ > + if (ic->ic_fixed_mcs != -1) { > + ; > + } else if (ic->ic_fixed_rate != -1) { > + ; > + } > + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == > + (IFF_UP | IFF_RUNNING)) { > + /* XXX could be a bit harsh */ > + mwx_stop(ifp); > + err = mwx_init(ifp); > + } > + return err; > +} > + > +/* > + * net80211 specific functions. > + */ > + > +struct ieee80211_node * > +mwx_node_alloc(struct ieee80211com *ic) > +{ > + return malloc(sizeof(struct mwx_node), M_DEVBUF, M_NOWAIT | M_ZERO); > +} > + > +void > +mwx_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew) > +{ > + struct mwx_softc *sc = ic->ic_softc; > + struct mwx_node *mn = (void *)ni; > + uint16_t wcid = 0; > + > + if (isnew && ni->ni_associd != 0) { > + /* only interested in true associations */ > + wcid = mn->wcid = IEEE80211_AID(ni->ni_associd); > + > + /* init WCID table entry */ > + /* XXX TODO */ > + } > + printf("%s: new assoc isnew=%d addr=%s WCID=%d\n", DEVNAME(sc), > + isnew, ether_sprintf(ni->ni_macaddr), wcid); > + > + /* XXX TODO rate handling here */ > +} > + > +#ifndef IEEE80211_STA_ONLY > +void > +mwx_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) > +{ > +#if 0 > + struct mwx_softc *sc = ic->ic_softc; > + struct mwx_node *mn = (void *)ni; > + uint16_t wcid = mn->wcid; > + > + /* TODO clear WCID */ > +#endif > +} > +#endif > + > +int > +mwx_scan(struct mwx_softc *sc) > +{ > + struct ieee80211com *ic = &sc->sc_ic; > + struct ifnet *ifp = &ic->ic_if; > + int rv; > + > + if (sc->sc_flags & MWX_FLAG_BGSCAN) { > + rv = mt7921_hw_scan_cancel(sc); > + if (rv) { > + printf("%s: could not abort background scan\n", > + DEVNAME(sc)); > + return rv; > + } > + } > + > + rv = mt7921_hw_scan(sc, 0); > + if (rv) { > + printf("%s: could not initiate scan\n", DEVNAME(sc)); > + return rv; > + } > + > + /* > + * The current mode might have been fixed during association. > + * Ensure all channels get scanned. > + */ > + if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) > + ieee80211_setmode(ic, IEEE80211_MODE_AUTO); > + > + sc->sc_flags |= MWX_FLAG_SCANNING; > + if (ifp->if_flags & IFF_DEBUG) > + printf("%s: %s -> %s\n", ifp->if_xname, > + ieee80211_state_name[ic->ic_state], > + ieee80211_state_name[IEEE80211_S_SCAN]); > + if ((sc->sc_flags & MWX_FLAG_BGSCAN) == 0) { > + ieee80211_set_link_state(ic, LINK_STATE_DOWN); > + ieee80211_node_cleanup(ic, ic->ic_bss); > + } > + ic->ic_state = IEEE80211_S_SCAN; > + > + return 0; > +} > + > +int > +mwx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) > +{ > + struct mwx_softc *sc = ic->ic_softc; > + enum ieee80211_state ostate; > + int rv; > + > + ostate = ic->ic_state; > + > +printf("%s: %s %d -> %d\n", DEVNAME(sc), __func__, ostate, nstate); > + > + switch (ostate) { > + case IEEE80211_S_RUN: > + mt7921_mcu_set_deep_sleep(sc, 1); > + break; > + case IEEE80211_S_SCAN: > + if (nstate == ostate) { > + if (sc->sc_flags & MWX_FLAG_SCANNING) > + return 0; > + } > + break; > + default: > + break; > + } > + > + /* XXX TODO */ > + switch (nstate) { > + case IEEE80211_S_INIT: > + break; > + case IEEE80211_S_SCAN: > + rv = mwx_scan(sc); > + if (rv) > + /* XXX error handling */ > + return rv; > + return 0; > + case IEEE80211_S_AUTH: > + case IEEE80211_S_ASSOC: > + break; > + case IEEE80211_S_RUN: > + mt7921_mcu_set_deep_sleep(sc, 0); > + break; > + } > + > + return sc->sc_newstate(ic, nstate, arg); > +} > + > +#if NBPFILTER > 0 > +void > +mwx_radiotap_attach(struct mwx_softc *sc) > +{ > + bpfattach(&sc->sc_drvbpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO, > + sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN); > + > + sc->sc_rxtap_len = sizeof sc->sc_rxtapu; > + sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); > + sc->sc_rxtap.wr_ihdr.it_present = htole32(MWX_RX_RADIOTAP_PRESENT); > + > + sc->sc_txtap_len = sizeof sc->sc_txtapu; > + sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); > + sc->sc_txtap.wt_ihdr.it_present = htole32(MWX_TX_RADIOTAP_PRESENT); > +} > +#endif > + > +int > +mwx_tx(struct mwx_softc *sc, struct mbuf *m, struct ieee80211_node *ni) > +{ > + return ENOBUFS; > +} > + > +void > +mwx_rx(struct mwx_softc *sc, struct mbuf *m, struct mbuf_list *ml) > +{ > + struct ieee80211com *ic = &sc->sc_ic; > + struct ifnet *ifp = &ic->ic_if; > + struct ieee80211_node *ni; > + struct ieee80211_frame *wh; > + struct ieee80211_rxinfo rxi = { 0 }; > + > + > + if (mt7921_mac_fill_rx(sc, m, &rxi) == -1) { > + ifp->if_ierrors++; > + m_freem(m); > + return; > + } > + > + wh = mtod(m, struct ieee80211_frame *); > + > +#if NBPFILTER > 0 > + if (__predict_false(sc->sc_drvbpf != NULL)) { > + struct mwx_rx_radiotap_header *tap = &sc->sc_rxtap; > + uint32_t tsf_lo, tsf_hi; > + /* get timestamp (low and high 32 bits) */ > + tsf_hi = 0; > + tsf_lo = 0; > + tap->wr_tsft = htole64(((uint64_t)tsf_hi << 32) | tsf_lo); > + tap->wr_flags = 0; > + tap->wr_rate = 2; /* XXX */ > + tap->wr_chan_freq = > + htole16(ic->ic_channels[rxi.rxi_chan].ic_freq); > + tap->wr_chan_flags = > + ic->ic_channels[rxi.rxi_chan].ic_flags; > + tap->wr_dbm_antsignal = 0; > + bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, > + BPF_DIRECTION_IN); > + } > +#endif > + > + /* grab a reference to the source node */ > + ni = ieee80211_find_rxnode(ic, wh); > + > + /* send the frame to the 802.11 layer */ > + /* TODO MAYBE rxi.rxi_rssi = rssi; */ > + ieee80211_inputm(ifp, m, ni, &rxi, ml); > + > + /* node is no longer needed */ > + ieee80211_release_node(ic, ni); > +} > + > +/* > + * Driver specific functions. > + */ > +int > +mwx_intr(void *arg) > +{ > + struct mwx_softc *sc = arg; > + uint32_t intr, intr_sw; > + uint32_t mask = MT_INT_RX_DONE_ALL|MT_INT_TX_DONE_ALL|MT_INT_MCU_CMD; > + > + mwx_write(sc, MT_WFDMA0_HOST_INT_ENA, 0); > + intr = mwx_read(sc, MT_WFDMA0_HOST_INT_STA); > + if (intr == 0) { > + mwx_write(sc, MT_WFDMA0_HOST_INT_ENA, mask); > + return 0; > + } > + > + /* TODO power management */ > +// mt76_connac_pm_ref(&dev->mphy, &dev->pm); > + > + if (intr & ~mask) > + printf("%s: unhandled interupt %08x\n", DEVNAME(sc), > + intr & ~mask); > + /* ack interrupts */ > + intr &= mask; > + mwx_write(sc, MT_WFDMA0_HOST_INT_STA, intr); > + > + if (intr & MT_INT_MCU_CMD) { > + intr_sw = mwx_read(sc, MT_MCU_CMD); > + /* ack MCU2HOST_SW_INT_STA */ > + mwx_write(sc, MT_MCU_CMD, intr_sw); > + if (intr_sw & MT_MCU_CMD_WAKE_RX_PCIE) > + intr |= MT_INT_RX_DONE_DATA; > + } > + > + if (intr & MT_INT_TX_DONE_ALL) > + mwx_dma_tx_done(sc); > + > + if (intr & MT_INT_RX_DONE_WM) > + mwx_dma_rx_done(sc, &sc->sc_rxfwdlq); > + if (intr & MT_INT_RX_DONE_WM2) > + mwx_dma_rx_done(sc, &sc->sc_rxmcuq); > + if (intr & MT_INT_RX_DONE_DATA) > + mwx_dma_rx_done(sc, &sc->sc_rxq); > + > + /* TODO power management */ > +// mt76_connac_pm_unref(&dev->mphy, &dev->pm); > + > + mwx_write(sc, MT_WFDMA0_HOST_INT_ENA, mask); > + > + return 1; > +} > + > +int > +mwx_preinit(struct mwx_softc *sc) > +{ > + struct ieee80211com *ic = &sc->sc_ic; > + struct ifnet *ifp = &ic->ic_if; > + int rv, i; > + uint8_t chan; > + > + DPRINTF("%s: init\n", DEVNAME(sc)); > + > + if ((rv = mt7921_init_hardware(sc)) != 0) > + return rv; > + > + if ((rv = mt7921_mcu_set_deep_sleep(sc, 1)) != 0) > + return rv; > + > + ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; > + ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; > + > + if (sc->sc_capa.has_2ghz) { > + for (i = 0; i < MWX_NUM_2GHZ_CHANNELS; i++) { > + chan = mwx_channels_2ghz[i]; > + ic->ic_channels[chan].ic_freq = > + ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); > + ic->ic_channels[chan].ic_flags = > + IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | > + IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; > + /* TODO 11n and 11ac flags */ > + } > + > + } > + if (sc->sc_capa.has_5ghz) { > + ic->ic_sup_rates[IEEE80211_MODE_11A] = > + ieee80211_std_rateset_11a; > + /* set supported .11a channels */ > + for (i = 0; i < MWX_NUM_5GHZ_CHANNELS; i++) { > + chan = mwx_channels_5ghz[i]; > + ic->ic_channels[chan].ic_freq = > + ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); > + ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A; > + /* TODO 11n and 11ac flags */ > + } > + } > +#ifdef NOTYET > + /* TODO support for 6GHz */ > + if (sc->sc_capa.has_6ghz) { > + for (i = 0; i < MWX_NUM_6GHZ_CHANNELS; i++) { > + } > + } > +#endif > + > + /* Configure channel information obtained from firmware. */ > + ieee80211_channel_init(ifp); > + > + if (IEEE80211_ADDR_EQ(etheranyaddr, sc->sc_ic.ic_myaddr)) > + IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_lladdr); > + > + /* Configure MAC address. */ > + rv = if_setlladdr(ifp, ic->ic_myaddr); > + if (rv) > + printf("%s: could not set MAC address (error %d)\n", > + DEVNAME(sc), rv); > + > + ieee80211_media_init(ifp, mwx_media_change, ieee80211_media_status); > + > + sc->sc_fw_loaded = 1; > + return 0; > +} > + > +void > +mwx_attach_hook(struct device *self) > +{ > + struct mwx_softc *sc = (void *)self; > + > + mwx_preinit(sc); > +} > + > +int > +mwx_match(struct device *parent, void *match __unused, void *aux) > +{ > + struct pci_attach_args *pa = aux; > + > + return pci_matchbyid(pa, mwx_devices, nitems(mwx_devices)); > +} > + > +void > +mwx_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct mwx_softc *sc = (struct mwx_softc *)self; > + struct ieee80211com *ic = &sc->sc_ic; > + struct ifnet *ifp = &ic->ic_if; > + struct pci_attach_args *pa = aux; > + pci_intr_handle_t ih; > + pcireg_t memtype; > + uint32_t hwid, hwrev; > + int error; > + > + sc->sc_pc = pa->pa_pc; > + sc->sc_tag = pa->pa_tag; > + sc->sc_dmat = pa->pa_dmat; > + > + memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START); > + if (pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, > + &sc->sc_st, &sc->sc_memh, NULL, &sc->sc_mems, 0)) { > + printf("%s: can't map mem space\n", DEVNAME(sc)); > + return; > + } > + > + if (pci_intr_map_msix(pa, 0, &ih) && > + pci_intr_map_msi(pa, &ih) && > + pci_intr_map(pa, &ih)) { > + printf("%s: can't map interrupt\n", DEVNAME(sc)); > + bus_space_unmap(sc->sc_st, sc->sc_memh, sc->sc_mems); > + return; > + } > + > + hwid = mwx_read(sc, MT_HW_CHIPID) & 0xffff; > + hwrev = mwx_read(sc, MT_HW_REV) & 0xff; > + > + printf(": %s, rev: %x.%x\n", pci_intr_string(pa->pa_pc, ih), > + hwid, hwrev); > + > + mwx_write(sc, MT_WFDMA0_HOST_INT_ENA, 0); > + mwx_write(sc, MT_PCIE_MAC_INT_ENABLE, 0xff); > + > + sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, > + mwx_intr, sc, DEVNAME(sc)); > + > + if ((error = mwx_dma_alloc(sc)) != 0) { > + printf("%s: failed to allocate DMA resources %d\n", > + DEVNAME(sc), error); > + goto fail; > + } > + > + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ > + ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ > + ic->ic_state = IEEE80211_S_INIT; > + > + /* Set device capabilities. */ > + ic->ic_caps = > + IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU | /* A-MPDU */ > + IEEE80211_C_ADDBA_OFFLOAD | /* device sends ADDBA/DELBA frames */ > + IEEE80211_C_WEP | /* WEP */ > + IEEE80211_C_RSN | /* WPA/RSN */ > + IEEE80211_C_SCANALL | /* device scans all channels at once */ > + IEEE80211_C_SCANALLBAND | /* device scans all bands at once */ > + IEEE80211_C_MONITOR | /* monitor mode supported */ > +#ifndef IEEE80211_STA_ONLY > + IEEE80211_C_IBSS | /* IBSS mode supported */ > + IEEE80211_C_HOSTAP | /* HostAP mode supported */ > + IEEE80211_C_APPMGT | /* HostAP power management */ > +#endif > + IEEE80211_C_SHSLOT | /* short slot time supported */ > + IEEE80211_C_SHPREAMBLE; /* short preamble supported */ > + > + ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_SGI40; > + ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40; > + ic->ic_htcaps |= > + (IEEE80211_HTCAP_SMPS_DIS << IEEE80211_HTCAP_SMPS_SHIFT); > + ic->ic_htxcaps = 0; > + ic->ic_txbfcaps = 0; > + ic->ic_aselcaps = 0; > + ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_4 | 0x3 /* 64k */); > + > + ic->ic_vhtcaps = IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895 | > + (IEEE80211_VHTCAP_MAX_AMPDU_LEN_64K << > + IEEE80211_VHTCAP_MAX_AMPDU_LEN_SHIFT) | > + (IEEE80211_VHTCAP_CHAN_WIDTH_80 << > + IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT) | IEEE80211_VHTCAP_SGI80 | > + IEEE80211_VHTCAP_RX_ANT_PATTERN | IEEE80211_VHTCAP_TX_ANT_PATTERN; > + > + /* IBSS channel undefined for now. */ > + ic->ic_ibss_chan = &ic->ic_channels[1]; > + > + /* HW supports up to 288 STAs in HostAP and IBSS modes */ > + ic->ic_max_aid = min(IEEE80211_AID_MAX, MWX_WCID_MAX); > + > + //XXX TODO ic->ic_max_rssi = IWX_MAX_DBM - IWX_MIN_DBM; > + > + ifp->if_softc = sc; > + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; > + ifp->if_ioctl = mwx_ioctl; > + ifp->if_start = mwx_start; > + ifp->if_watchdog = mwx_watchdog; > + memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); > + > + if_attach(ifp); > + ieee80211_ifattach(ifp); > + ieee80211_media_init(ifp, mwx_media_change, ieee80211_media_status); > + > +#if NBPFILTER > 0 > + mwx_radiotap_attach(sc); > +#endif > + > + ic->ic_node_alloc = mwx_node_alloc; > + ic->ic_newassoc = mwx_newassoc; > +#ifndef IEEE80211_STA_ONLY > + ic->ic_node_leave = mwx_node_leave; > +#endif > + /* TODO XXX > + ic->ic_bgscan_start = mwx_bgscan; > + ic->ic_bgscan_done = mwx_bgscan_done; > + ic->ic_set_key = mwx_set_key; > + ic->ic_delete_key = mwx_delete_key; > + */ > + > + /* Override 802.11 state transition machine. */ > + sc->sc_newstate = ic->ic_newstate; > + ic->ic_newstate = mwx_newstate; > + > + task_set(&sc->sc_reset_task, mwx_reset_task, sc); > + > + /* > + * We cannot read the MAC address without loading the > + * firmware from disk. Postpone until mountroot is done. > + */ > + config_mountroot(self, mwx_attach_hook); > + > + return; > + > +fail: > + mwx_dma_free(sc); > + pci_intr_disestablish(pa->pa_pc, sc->sc_ih); > + bus_space_unmap(sc->sc_st, sc->sc_memh, sc->sc_mems); > + return; > +} > + > +int > +mwx_activate(struct device *self, int act) > +{ > + /* XXX TODO */ > + return 0; > +} > + > +struct cfdriver mwx_cd = { > + NULL, "mwx", DV_IFNET > +}; > + > +struct cfattach mwx_ca = { > + sizeof(struct mwx_softc), mwx_match, mwx_attach, > + NULL, mwx_activate > +}; > + > +void > +mwx_reset(struct mwx_softc *sc) > +{ > + if (sc->sc_resetting) > + return; > + sc->sc_resetting = 1; > + task_add(systq, &sc->sc_reset_task); > +} > + > +void > +mwx_reset_task(void *arg) > +{ > + struct mwx_softc *sc = arg; > + struct ifnet *ifp = &sc->sc_ic.ic_if; > + int fatal = 0; > + > + if (ifp->if_flags & IFF_RUNNING) > + mwx_stop(ifp); > + > + if (!fatal && (ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) > + mwx_init(ifp); > +} > + > +int > +mwx_queue_alloc(struct mwx_softc *sc, struct mwx_queue *q, int count, > + uint32_t regbase) > +{ > + int error, nsegs, i; > + bus_size_t size = count * sizeof(*q->mq_desc); > + > + q->mq_regbase = regbase; > + q->mq_count = count; > + > + error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, > + BUS_DMA_NOWAIT, &q->mq_map); > + if (error != 0) { > + printf("%s: could not create desc DMA map\n", DEVNAME(sc)); > + goto fail; > + } > + > + error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &q->mq_seg, > + 1, &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO); > + if (error != 0) { > + printf("%s: could not allocate DMA memory\n", DEVNAME(sc)); > + goto fail; > + } > + > + error = bus_dmamem_map(sc->sc_dmat, &q->mq_seg, nsegs, size, > + (caddr_t *)&q->mq_desc, BUS_DMA_NOWAIT); > + if (error != 0) { > + printf("%s: can't map desc DMA memory\n", DEVNAME(sc)); > + goto fail; > + } > + > + error = bus_dmamap_load(sc->sc_dmat, q->mq_map, q->mq_desc, > + size, NULL, BUS_DMA_NOWAIT); > + if (error != 0) { > + printf("%s: could not load desc DMA map\n", DEVNAME(sc)); > + goto fail; > + } > + > + q->mq_data = mallocarray(count, sizeof(*q->mq_data), > + M_DEVBUF, M_NOWAIT | M_ZERO); > + if (q->mq_data == NULL) { > + printf("%s: could not allocate soft data\n", DEVNAME(sc)); > + error = ENOMEM; > + goto fail; > + } > + > + for (i = 0; i < count; i++) { > + error = bus_dmamap_create(sc->sc_dmat, MT_MAX_SIZE, > + MT_MAX_SCATTER, MT_MAX_SIZE, 0, BUS_DMA_NOWAIT, > + &q->mq_data[i].md_map); > + if (error != 0) { > + printf("%s: could not create data DMA map\n", > + DEVNAME(sc)); > + goto fail; > + } > + } > + > + mwx_queue_reset(sc, q); > + return 0; > + > +fail: > + mwx_queue_free(sc, q); > + return error; > + > +} > + > +void > +mwx_queue_free(struct mwx_softc *sc, struct mwx_queue *q) > +{ > + if (q->mq_data != NULL) { > + int i; > + for (i = 0; i < q->mq_count; i++) { > + struct mwx_data *md = &q->mq_data[i]; > + bus_dmamap_destroy(sc->sc_dmat, md->md_map); > + m_freem(md->md_data); > + } > + free(q->mq_data, M_DEVBUF, q->mq_count * sizeof(*q->mq_data)); > + } > + > + if (q->mq_desc != NULL) { > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, > + q->mq_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); > + bus_dmamap_unload(sc->sc_dmat, q->mq_map); > + } > + > + /* > + * XXX TODO this is probably not correct as a check, should use > + * some state variable bitfield to decide which steps need to be run. > + */ > + if (q->mq_seg.ds_len != 0) > + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)q->mq_desc, > + q->mq_count * sizeof(*q->mq_desc)); > + if (q->mq_map != NULL) > + bus_dmamem_free(sc->sc_dmat, &q->mq_seg, 1); > + > + memset(q, 0, sizeof(*q)); > +} > + > +void > +mwx_queue_reset(struct mwx_softc *sc, struct mwx_queue *q) > +{ > + int i; > + uint32_t dmaaddr; > + struct mwx_data *md; > + > + /* clear descriptors */ > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_PREWRITE); > + > + for (i = 0; i < q->mq_count; i++) { > + q->mq_desc[i].buf0 = 0; > + q->mq_desc[i].buf1 = 0; > + q->mq_desc[i].info = 0; > + q->mq_desc[i].ctrl = htole32(MT_DMA_CTL_DMA_DONE); > + } > + > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_POSTWRITE); > + > + /* reset DMA registers */ > + KASSERT(q->mq_map->dm_nsegs == 1); > + KASSERT(q->mq_map->dm_segs[0].ds_addr <= UINT32_MAX); > + dmaaddr = q->mq_map->dm_segs[0].ds_addr; > + mwx_write(sc, q->mq_regbase + MT_DMA_DESC_BASE, dmaaddr); > + mwx_write(sc, q->mq_regbase + MT_DMA_RING_SIZE, q->mq_count); > + mwx_write(sc, q->mq_regbase + MT_DMA_CPU_IDX, 0); > + mwx_write(sc, q->mq_regbase + MT_DMA_DMA_IDX, 0); > + q->mq_cons = 0; > + q->mq_prod = 0; > + > + /* free buffers */ > + for (i = 0; i < q->mq_count; i++) { > + md = &q->mq_data[i]; > + if (md->md_data != NULL) { > + bus_dmamap_sync(sc->sc_dmat, md->md_map, 0, > + md->md_map->dm_mapsize, > + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); > + bus_dmamap_unload(sc->sc_dmat, md->md_map); > + m_freem(md->md_data); > + md->md_data = NULL; > + } > + } > +} > + > +int > +mwx_buf_fill(struct mwx_softc *sc, struct mwx_data *md, struct mt76_desc > *desc) > +{ > + struct mbuf *m; > + uint32_t buf0, len0, ctrl; > + int rv; > + > + m = MCLGETL(NULL, M_DONTWAIT, MT_RX_BUF_SIZE); > + if (m == NULL) > + return (ENOMEM); > + > + m->m_pkthdr.len = m->m_len = MT_RX_BUF_SIZE; > + > + rv = bus_dmamap_load_mbuf(sc->sc_dmat, md->md_map, m, > + BUS_DMA_READ | BUS_DMA_NOWAIT); > + if (rv != 0) { > + printf("%s: could not load data, %d\n", DEVNAME(sc), rv); > + m_freem(m); > + return (rv); > + } > + > + bus_dmamap_sync(sc->sc_dmat, md->md_map, 0, > + md->md_map->dm_mapsize, BUS_DMASYNC_PREREAD); > + > + md->md_data = m; > + > + KASSERT(md->md_map->dm_nsegs == 1); > + KASSERT(md->md_map->dm_segs[0].ds_addr <= UINT32_MAX); > + buf0 = md->md_map->dm_segs[0].ds_addr; > + len0 = md->md_map->dm_segs[0].ds_len; > + ctrl = MT_DMA_CTL_SD_LEN0(len0); > + ctrl |= MT_DMA_CTL_LAST_SEC0; > + > + desc->buf0 = htole32(buf0); > + desc->buf1 = 0; > + desc->info = 0; > + desc->ctrl = htole32(ctrl); > + > + return 0; > +} > + > +int > +mwx_queue_fill(struct mwx_softc *sc, struct mwx_queue *q) > +{ > + u_int idx, last; > + int rv; > + > + last = (q->mq_count + q->mq_cons - 1) % q->mq_count; > + idx = q->mq_prod; > + > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_PREWRITE); > + > + while (idx != last) { > + rv = mwx_buf_fill(sc, &q->mq_data[idx], &q->mq_desc[idx]); > + if (rv != 0) { > + printf("%s: could not fill data, slot %d err %d\n", > + DEVNAME(sc), idx, rv); > + return rv; > + } > + idx = (idx + 1) % q->mq_count; > + } > + > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_POSTWRITE); > + > + q->mq_prod = idx; > + mwx_write(sc, q->mq_regbase + MT_DMA_CPU_IDX, q->mq_prod); > + > + return 0; > +} > + > +int > +mwx_dma_alloc(struct mwx_softc *sc) > +{ > + int rv; > + > + /* Stop DMA engine and reset wfsys */ > + if ((rv = mt7921_dma_disable(sc, 1)) != 0) > + return rv; > + if ((rv = mt7921_wfsys_reset(sc)) != 0) > + return rv; > + > + /* TX queues */ > + if ((rv = mwx_queue_alloc(sc, &sc->sc_txq, 256, > + MT_TX_DATA_RING_BASE)) != 0) > + return rv; > + if ((rv = mwx_queue_alloc(sc, &sc->sc_txmcuq, 16 /* XXX */, > + MT_TX_MCU_RING_BASE)) != 0) > + return rv; > + if ((rv = mwx_queue_alloc(sc, &sc->sc_txfwdlq, 16 /* XXX */, > + MT_TX_FWDL_RING_BASE)) != 0) > + return rv; > + > + /* RX queues */ > + if ((rv = mwx_queue_alloc(sc, &sc->sc_rxq, 256, > + MT_RX_DATA_RING_BASE)) != 0 || > + (rv = mwx_queue_fill(sc, &sc->sc_rxq)) != 0) > + return rv; > + if ((rv = mwx_queue_alloc(sc, &sc->sc_rxmcuq, 16 /* XXX */, > + MT_RX_MCU_RING_BASE)) != 0 || > + (rv = mwx_queue_fill(sc, &sc->sc_rxmcuq)) != 0) > + return rv; > + if ((rv = mwx_queue_alloc(sc, &sc->sc_rxfwdlq, 16 /* XXX */, > + MT_RX_FWDL_RING_BASE)) != 0 || > + (rv = mwx_queue_fill(sc, &sc->sc_rxfwdlq)) != 0) > + return rv; > + > + /* enable DMA engine */ > + mt7921_dma_enable(sc); > + > + return 0; > +} > + > +int > +mwx_dma_reset(struct mwx_softc *sc, int fullreset) > +{ > + int rv; > + > + DPRINTF("%s: DMA reset\n", DEVNAME(sc)); > + > + if ((rv = mt7921_dma_disable(sc, fullreset)) != 0) > + return rv; > + if (fullreset) > + if ((rv = mt7921_wfsys_reset(sc)) != 0) > + return rv; > + > + /* TX queues */ > + mwx_queue_reset(sc, &sc->sc_txq); > + mwx_queue_reset(sc, &sc->sc_txmcuq); > + mwx_queue_reset(sc, &sc->sc_txfwdlq); > + > + /* RX queues */ > + mwx_queue_reset(sc, &sc->sc_rxq); > + mwx_queue_reset(sc, &sc->sc_rxmcuq); > + mwx_queue_reset(sc, &sc->sc_rxfwdlq); > + > + /* TDOD mt76_tx_status_check */ > + > + /* refill RX queues */ > + if ((rv = mwx_queue_fill(sc, &sc->sc_rxq)) != 0 || > + (rv = mwx_queue_fill(sc, &sc->sc_rxmcuq)) != 0 || > + (rv = mwx_queue_fill(sc, &sc->sc_rxfwdlq)) != 0) > + return rv; > + > + /* enable DMA engine */ > + mt7921_dma_enable(sc); > + > + return 0; > +} > + > +void > +mwx_dma_free(struct mwx_softc *sc) > +{ > + /* TX queues */ > + mwx_queue_free(sc, &sc->sc_txq); > + mwx_queue_free(sc, &sc->sc_txmcuq); > + mwx_queue_free(sc, &sc->sc_txfwdlq); > + > + /* RX queues */ > + mwx_queue_free(sc, &sc->sc_rxq); > + mwx_queue_free(sc, &sc->sc_rxmcuq); > + mwx_queue_free(sc, &sc->sc_rxfwdlq); > +} > + > +static inline int > +mwx_dma_free_slots(struct mwx_queue *q) > +{ > + int free = q->mq_count - 1; > + free += q->mq_cons; > + free -= q->mq_prod; > + free %= q->mq_count; > + return free; > +} > + > +int > +mwx_dma_tx_enqueue(struct mwx_softc *sc, struct mwx_queue *q, struct mbuf *m, > + uint32_t tx_info) > +{ > + struct mwx_data *md; > + struct mt76_desc *desc; > + int i, nsegs, idx, rv; > + > + idx = q->mq_prod; > + md = &q->mq_data[idx]; > + desc = &q->mq_desc[idx]; > + > + rv = bus_dmamap_load_mbuf(sc->sc_dmat, md->md_map, m, > + BUS_DMA_WRITE | BUS_DMA_NOWAIT); > + if (rv == EFBIG && m_defrag(m, M_DONTWAIT) == 0) > + rv = bus_dmamap_load_mbuf(sc->sc_dmat, md->md_map, m, > + BUS_DMA_WRITE | BUS_DMA_NOWAIT); > + if (rv != 0) > + return rv; > + > + nsegs = md->md_map->dm_nsegs; > + > + /* check if there is enough space */ > + if ((nsegs + 1)/2 > mwx_dma_free_slots(q)) { > + bus_dmamap_unload(sc->sc_dmat, md->md_map); > + return EBUSY; > + } > + > + bus_dmamap_sync(sc->sc_dmat, md->md_map, 0, md->md_map->dm_mapsize, > + BUS_DMASYNC_PREWRITE); > + md->md_data = m; > + > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_PREWRITE); > + for (i = 0; i < nsegs; i += 2) { > + uint32_t buf0, buf1 = 0; > + uint32_t len0, len1 = 0, ctrl; > + > + KASSERT(md->md_map->dm_segs[i].ds_addr <= UINT32_MAX); > + buf0 = md->md_map->dm_segs[i].ds_addr; > + len0 = md->md_map->dm_segs[i].ds_len; > + ctrl = MT_DMA_CTL_SD_LEN0(len0); > + > + if (i < nsegs - 1) { > + KASSERT(md->md_map->dm_segs[i + 1].ds_addr <= > + UINT32_MAX); > + buf1 = md->md_map->dm_segs[i + 1].ds_addr; > + len1 = md->md_map->dm_segs[i + 1].ds_len; > + ctrl |= MT_DMA_CTL_SD_LEN1(len1); > + } > + > + if (i == nsegs - 1) > + ctrl |= MT_DMA_CTL_LAST_SEC0; > + else if (i == nsegs - 2) > + ctrl |= MT_DMA_CTL_LAST_SEC1; > + > + desc->buf0 = htole32(buf0); > + desc->buf1 = htole32(buf1); > + desc->info = htole32(tx_info); > + desc->ctrl = htole32(ctrl); > + > + idx = (idx + 1) % q->mq_count; > + KASSERT(idx != q->mq_cons); > + md = &q->mq_data[idx]; > + desc = &q->mq_desc[idx]; > + } > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_POSTWRITE); > + > + q->mq_prod = idx; > + > + mwx_write(sc, q->mq_regbase + MT_DMA_CPU_IDX, q->mq_prod); > + > + return 0; > +} > + > +void > +mwx_dma_tx_cleanup(struct mwx_softc *sc, struct mwx_queue *q) > +{ > + struct mwx_data *md; > + struct mt76_desc *desc; > + int idx, last; > + > + idx = q->mq_cons; > + last = mwx_read(sc, q->mq_regbase + MT_DMA_DMA_IDX); > + > + if (idx == last) > + return; > + > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_PREWRITE); > + > + while (idx != last) { > + md = &q->mq_data[idx]; > + desc = &q->mq_desc[idx]; > + > + if (md->md_data != NULL) { > + bus_dmamap_sync(sc->sc_dmat, md->md_map, 0, > + md->md_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); > + bus_dmamap_unload(sc->sc_dmat, md->md_map); > + m_freem(md->md_data); > + md->md_data = NULL; > + } > + > + /* clear DMA desc just to be sure */ > + desc->buf0 = 0; > + desc->buf1 = 0; > + desc->info = 0; > + desc->ctrl = htole32(MT_DMA_CTL_DMA_DONE); > + > + idx = (idx + 1) % q->mq_count; > + > + /* check if more data made it in */ > + /* XXX should we actually do that? */ > + if (idx == last) > + last = mwx_read(sc, q->mq_regbase + MT_DMA_DMA_IDX); > + } > + > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_POSTWRITE); > + > + q->mq_cons = idx; > + if (q->mq_wakeme) { > + q->mq_wakeme = 0; > + wakeup(q); > + } > +} > + > +void > +mwx_dma_tx_done(struct mwx_softc *sc) > +{ > + mwx_dma_tx_cleanup(sc, &sc->sc_txq); > + mwx_dma_tx_cleanup(sc, &sc->sc_txmcuq); > + mwx_dma_tx_cleanup(sc, &sc->sc_txfwdlq); > + > + /* XXX do we need to wakeup someone */ > +} > + > +/* XXX wrong place */ > +void > +mwx_dma_rx_process(struct mwx_softc *sc, struct mbuf_list *ml) > +{ > + struct mbuf_list mlout = MBUF_LIST_INITIALIZER(); > + struct mbuf *m; > + uint32_t *data, rxd, type, flag; > + > + while ((m = ml_dequeue(ml)) != NULL) { > + data = mtod(m, uint32_t *); > + rxd = le32toh(data[0]); > + > + type = MT_RXD0_PKT_TYPE_GET(rxd); > + flag = (rxd & MT_RXD0_PKT_FLAG_MASK) >> MT_RXD0_PKT_FLAG_SHIFT; > + > + if (type == PKT_TYPE_RX_EVENT && flag == 0x1) > + type = PKT_TYPE_NORMAL_MCU; > + > + switch (type) { > + case PKT_TYPE_RX_EVENT: > + mwx_mcu_rx_event(sc, m); > + break; > +#if TODO > + case PKT_TYPE_TXRX_NOTIFY: > + mt7921_mac_tx_free(sc, m); > + break; > + case PKT_TYPE_TXS: > + for (rxd += 2; rxd + 8 <= end; rxd += 8) > + mt7921_mac_add_txs(dev, rxd); > + m_freem(m); > + break; > +#endif > + case PKT_TYPE_NORMAL_MCU: > + case PKT_TYPE_NORMAL: > + mwx_rx(sc, m, &mlout); > + break; > + default: > + if (DEVDEBUG(sc)) > + printf("%s: recevied unknown pkt type %d\n", > + DEVNAME(sc), type); > + m_freem(m); > + break; > + } > + } > + > + if_input(&sc->sc_ic.ic_if, &mlout); > +} > + > +void > +mwx_dma_rx_dequeue(struct mwx_softc *sc, struct mwx_queue *q, > + struct mbuf_list *ml) > +{ > + struct mwx_data *md; > + struct mt76_desc *desc; > + struct mbuf *m, *m0 = NULL, *mtail = NULL; > + int idx, last; > + > + idx = q->mq_cons; > + last = mwx_read(sc, q->mq_regbase + MT_DMA_DMA_IDX); > + > + if (idx == last) > + return; > + > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_PREREAD); > + > + while (idx != last) { > + uint32_t ctrl; > + > + md = &q->mq_data[idx]; > + desc = &q->mq_desc[idx]; > + > + bus_dmamap_sync(sc->sc_dmat, md->md_map, 0, > + md->md_map->dm_mapsize, BUS_DMASYNC_POSTREAD); > + bus_dmamap_unload(sc->sc_dmat, md->md_map); > + > + /* dequeue mbuf */ > + m = md->md_data; > + md->md_data = NULL; > + > + /* only buf0 is used on RX rings */ > + ctrl = le32toh(desc->ctrl); > + m->m_len = MT_DNA_CTL_SD_GET_LEN0(ctrl); > + > + if (m0 == NULL) { > + m0 = mtail = m; > + m0->m_pkthdr.len = m->m_len; > + } else { > + mtail->m_next = m; > + mtail = m; > + m0->m_pkthdr.len += m->m_len; > + } > + > + /* TODO handle desc->info */ > + > + /* check if this was the last mbuf of the chain */ > + if (ctrl & MT_DMA_CTL_LAST_SEC0) { > + ml_enqueue(ml, m0); > + m0 = NULL; > + mtail = NULL; > + } > + > + idx = (idx + 1) % q->mq_count; > + > + /* check if more data made it in */ > + /* XXX should we actually do that? */ > + if (idx == last) > + last = mwx_read(sc, q->mq_regbase + MT_DMA_DMA_IDX); > + } > + > + /* XXX make sure we don't have half processed data */ > + KASSERT(m0 == NULL); > + > + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, > + BUS_DMASYNC_POSTREAD); > + > + q->mq_cons = idx; > +} > + > +void > +mwx_dma_rx_done(struct mwx_softc *sc, struct mwx_queue *q) > +{ > + struct mbuf_list ml = MBUF_LIST_INITIALIZER(); > + > + mwx_dma_rx_dequeue(sc, q, &ml); > + > + if (ml_empty(&ml)) > + return; > + > + mwx_queue_fill(sc, q); /* TODO what if it fails, run timer? */ > + > + mwx_dma_rx_process(sc, &ml); > +} > + > +int > +mwx_mcu_send_msg(struct mwx_softc *sc, uint32_t cmd, void *data, size_t len, > + int *seqp) > +{ > + const int headspace = sizeof(struct mt7921_mcu_txd); > + struct mbuf *m; > + struct mt7921_uni_txd *uni_txd; > + struct mt7921_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; > + uint8_t seq; > + > + /* Allocate mbuf with enough space */ > + m = m_gethdr(MT_DATA, M_DONTWAIT); > + if (m == NULL) > + return ENOMEM; > + if (len + headspace > MHLEN) { > + m_clget(m, M_DONTWAIT, len + sizeof(*mcu_txd)); > + if (!ISSET(m->m_flags, M_EXT)) { > + m_freem(m); > + return ENOMEM; > + } > + } > + > + m_align(m, len + headspace); > + m->m_pkthdr.len = m->m_len = len + headspace; > + m_adj(m, headspace); > + if (len != 0) > + memcpy(mtod(m, caddr_t), data, len); > + > + if (cmd == MCU_CMD_FW_SCATTER) { > + q = &sc->sc_txfwdlq; > + goto enqueue; > + } > + > + seq = ++sc->sc_mcu_seq & 0x0f; > + if (seq == 0) > + seq = ++sc->sc_mcu_seq & 0x0f; > + > + txd_len = cmd & MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); > + 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) | > + 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; > + 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->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->pq_id = htole16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, > + MT_TX_MCU_PORT_RX_Q0)); > + mcu_txd->pkt_type = MCU_PKT_ID; > + mcu_txd->seq = seq; > + mcu_txd->cid = mcu_cmd; > + mcu_txd->s2d_index = CMD_S2D_IDX_H2N; > + mcu_txd->ext_cid = MCU_GET_EXT_CMD(cmd); > + > + if (mcu_txd->ext_cid || (cmd & MCU_CMD_FIELD_CE)) { > + if (cmd & MCU_CMD_FIELD_QUERY) > + mcu_txd->set_query = MCU_Q_QUERY; > + else > + mcu_txd->set_query = MCU_Q_SET; > + mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid; > + } else { > + mcu_txd->set_query = MCU_Q_NA; > + } > + } > + > + if (seqp != NULL) > + *seqp = seq; > + q = &sc->sc_txmcuq; > +enqueue: > + s = splnet(); > + while (1) { > + rv = mwx_dma_tx_enqueue(sc, q, m, 0); > + if (rv != EBUSY) > + break; > + q->mq_wakeme = 1; > + tsleep_nsec(q, 0, "mwxq", MSEC_TO_NSEC(100)); > + } > + splx(s); > + return rv; > +} > + > +int > +mwx_mcu_send_wait(struct mwx_softc *sc, uint32_t cmd, void *data, size_t len) > +{ > + int rv, seq; > + > + rv = mwx_mcu_send_msg(sc, cmd, data, len, &seq); > + if (rv != 0) > + return rv; > + return mwx_mcu_wait_resp_int(sc, cmd, seq, NULL); > +} > + > +void > +mwx_mcu_rx_event(struct mwx_softc *sc, struct mbuf *m) > +{ > + struct mt7921_mcu_rxd *rxd; > + uint32_t cmd, mcu_int = 0; > + int len; > + > + if ((m = m_pullup(m, sizeof(*rxd))) == NULL) > + return; > + rxd = mtod(m, struct mt7921_mcu_rxd *); > + > + if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT) { > + printf("%s: MCU_EXT_EVENT_RATE_REPORT COMMAND\n", DEVNAME(sc)); > + m_freem(m); > + return; > + } > + > + len = sizeof(*rxd) - sizeof(rxd->rxd) + le16toh(rxd->len); > + /* make sure all the data is in one mbuf */ > + if ((m = m_pullup(m, len)) == NULL) { > + printf("%s: mwx_mcu_rx_event m_pullup failed\n", DEVNAME(sc)); > + return; > + } > + /* refetch after pullup */ > + rxd = mtod(m, struct mt7921_mcu_rxd *); > + m_adj(m, sizeof(*rxd)); > + > + switch (rxd->eid) { > + case MCU_EVENT_SCHED_SCAN_DONE: > + case MCU_EVENT_SCAN_DONE: > + mt7921_mcu_scan_event(sc, m); > + return; > +#if 0 > + case MCU_EVENT_BSS_BEACON_LOSS: > + mt7921_mcu_connection_loss_event(dev, skb); > + break; > + case MCU_EVENT_BSS_ABSENCE: > + mt7921_mcu_bss_event(dev, skb); > + break; > + case MCU_EVENT_DBG_MSG: > + mt7921_mcu_debug_msg_event(dev, skb); > + break; > +#endif > + case MCU_EVENT_COREDUMP: > + /* it makes little sense to write the coredump down */ > + if (!sc->sc_resetting) > + printf("%s: coredump event\n", DEVNAME(sc)); > + mwx_reset(sc); > + return; > + case MCU_EVENT_LP_INFO: > + mt7921_mcu_low_power_event(sc, m); > + break; > + case MCU_EVENT_TX_DONE: > + mt7921_mcu_tx_done_event(sc, m); > + break; > + case 0x6: > + printf("%s: MAGIC COMMAND\n", DEVNAME(sc)); > + default: > + if (rxd->seq == 0 || rxd->seq >= nitems(sc->sc_mcu_wait)) { > + printf("%s: mcu rx bad seq %x\n", DEVNAME(sc), > + rxd->seq); > + m_freem(m); > + break; > + } > + > + cmd = sc->sc_mcu_wait[rxd->seq].mcu_cmd; > + > + if (cmd == MCU_CMD_PATCH_SEM_CONTROL) { > + /* XXX this is a terrible abuse */ > + m = m_prepend(m, sizeof(uint32_t), M_DONTWAIT); > + mcu_int = *mtod(m, uint8_t *); > + } else if (cmd == MCU_EXT_CMD_THERMAL_CTRL) { > + if (m->m_len < sizeof(uint32_t) * 2) > + return; > + mcu_int = le32toh(mtod(m, uint32_t *)[1]); > + } else if (cmd == MCU_EXT_CMD_EFUSE_ACCESS) { > + //ret = mt7921_mcu_parse_eeprom(sc, m); > + printf("%s: mcu resp no handled yet\n", DEVNAME(sc)); > + } else if (cmd == MCU_UNI_CMD_DEV_INFO_UPDATE || > + cmd == MCU_UNI_CMD_BSS_INFO_UPDATE || > + cmd == MCU_UNI_CMD_STA_REC_UPDATE || > + cmd == MCU_UNI_CMD_HIF_CTRL || > + cmd == MCU_UNI_CMD_OFFLOAD || > + cmd == MCU_UNI_CMD_SUSPEND) { > + struct mt7921_mcu_uni_event *event; > + > + if (m->m_len < sizeof(*event)) > + return; > + event = mtod(m, struct mt7921_mcu_uni_event *); > + mcu_int = le32toh(event->status); > + } else if (cmd == MCU_CE_QUERY_REG_READ) { > + struct mt7921_mcu_reg_event *event; > + > + if (m->m_len < sizeof(*event)) > + return; > + event = mtod(m, struct mt7921_mcu_reg_event *); > + mcu_int = le32toh(event->val); > + } > + > + sc->sc_mcu_wait[rxd->seq].mcu_int = mcu_int; > + sc->sc_mcu_wait[rxd->seq].mcu_m = m; > + wakeup(&sc->sc_mcu_wait[rxd->seq]); > + break; > + } > +} > + > +int > +mwx_mcu_wait_resp_int(struct mwx_softc *sc, uint32_t cmd, int seq, > + uint32_t *val) > +{ > + int rv; > + > + 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); > + mwx_reset(sc); > + return rv; > + } > + > + if (sc->sc_mcu_wait[seq].mcu_m != NULL) { > + m_freem(sc->sc_mcu_wait[seq].mcu_m); > + sc->sc_mcu_wait[seq].mcu_m = NULL; > + } > + if (val != NULL) > + *val = sc->sc_mcu_wait[seq].mcu_int; > + return 0; > +} > + > +int > +mwx_mcu_wait_resp_msg(struct mwx_softc *sc, uint32_t cmd, int seq, > + struct mbuf **mp) > +{ > + int rv; > + > + 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); > + mwx_reset(sc); > + return rv; > + } > + if (sc->sc_mcu_wait[seq].mcu_m == NULL) { > + printf("%s: command respone missing\n", DEVNAME(sc)); > + return ENOENT; > + } > + if (mp != NULL) > + *mp = sc->sc_mcu_wait[seq].mcu_m; > + else > + m_freem(sc->sc_mcu_wait[seq].mcu_m); > + sc->sc_mcu_wait[seq].mcu_m = NULL; > + return 0; > +} > + > +int > +mt7921_dma_disable(struct mwx_softc *sc, int force) > +{ > + /* disable WFDMA0 */ > + mwx_clear(sc, MT_WFDMA0_GLO_CFG, > + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | > + MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | > + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | > + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | > + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); > + > + if (force) { > + /* reset */ > + mwx_clear(sc, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | > + MT_WFDMA0_RST_LOGIC_RST); > + mwx_set(sc, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | > + MT_WFDMA0_RST_LOGIC_RST); > + } > + > + /* disable dmashdl */ > + mwx_clear(sc, MT_WFDMA0_GLO_CFG_EXT0, MT_WFDMA0_CSR_TX_DMASHDL_ENABLE); > + mwx_set(sc, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS); > + > + return mwx_poll(sc, MT_WFDMA0_GLO_CFG, 0, > + MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, > + 1000); > +} > + > +void > +mt7921_dma_enable(struct mwx_softc *sc) > +{ > +#define PREFETCH(base, depth) ((base) << 16 | (depth)) > + /* configure perfetch settings */ > + mwx_write(sc, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); > + mwx_write(sc, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x40, 0x4)); > + mwx_write(sc, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x80, 0x4)); > + mwx_write(sc, MT_WFDMA0_RX_RING4_EXT_CTRL, PREFETCH(0xc0, 0x4)); > + mwx_write(sc, MT_WFDMA0_RX_RING5_EXT_CTRL, PREFETCH(0x100, 0x4)); > + > + mwx_write(sc, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x140, 0x4)); > + mwx_write(sc, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x180, 0x4)); > + mwx_write(sc, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x1c0, 0x4)); > + mwx_write(sc, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x200, 0x4)); > + mwx_write(sc, MT_WFDMA0_TX_RING4_EXT_CTRL, PREFETCH(0x240, 0x4)); > + mwx_write(sc, MT_WFDMA0_TX_RING5_EXT_CTRL, PREFETCH(0x280, 0x4)); > + mwx_write(sc, MT_WFDMA0_TX_RING6_EXT_CTRL, PREFETCH(0x2c0, 0x4)); > + mwx_write(sc, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x340, 0x4)); > + mwx_write(sc, MT_WFDMA0_TX_RING17_EXT_CTRL, PREFETCH(0x380, 0x4)); > + > + /* reset dma idx */ > + mwx_write(sc, MT_WFDMA0_RST_DTX_PTR, ~0); > + > + /* configure delay interrupt */ > + mwx_write(sc, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); > + > + mwx_set(sc, MT_WFDMA0_GLO_CFG, > + MT_WFDMA0_GLO_CFG_TX_WB_DDONE | > + MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | > + MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | > + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | > + MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | > + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); > + > + mwx_barrier(sc); > + mwx_set(sc, MT_WFDMA0_GLO_CFG, > + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); > + > + mwx_set(sc, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); > + > + /* enable interrupts for TX/RX rings */ > + mwx_write(sc, MT_WFDMA0_HOST_INT_ENA, MT_INT_RX_DONE_ALL | > + MT_INT_TX_DONE_ALL | MT_INT_MCU_CMD); > + mwx_set(sc, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); > + mwx_write(sc, MT_PCIE_MAC_INT_ENABLE, 0xff); > +} > + > +int > +mt7921_wfsys_reset(struct mwx_softc *sc) > +{ > + DPRINTF("%s: WFSYS reset\n", DEVNAME(sc)); > + > + mwx_clear(sc, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B); > + delay(50 * 1000); > + mwx_set(sc, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B); > + > + return mwx_poll(sc, MT_WFSYS_SW_RST_B, WFSYS_SW_INIT_DONE, > + WFSYS_SW_INIT_DONE, 500); > +} > + > +/* > + * To be honest this is ridiculous. > + */ > +uint32_t > +mt7921_reg_addr(struct mwx_softc *sc, uint32_t reg) > +{ > + static const struct { > + uint32_t phys; > + uint32_t mapped; > + uint32_t size; > + } fixed_map[] = { > + { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ > + { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ > + { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ > + { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ > + { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ > + { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ > + { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ > + { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ > + { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ > + { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (conf register) */ > + { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */ > + { 0x54000000, 0x02000, 0x1000 }, /* WFDMA PCIE0 MCU DMA0 */ > + { 0x55000000, 0x03000, 0x1000 }, /* WFDMA PCIE0 MCU DMA1 */ > + { 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ > + { 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */ > + { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ > + { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */ > + { 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */ > + { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ > + { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ > + { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */ > + { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */ > + { 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */ > + { 0x820cd000, 0x0f000, 0x1000 }, /* WF_MDP_TOP */ > + { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */ > + { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */ > + { 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ > + { 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ > + { 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ > + { 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ > + { 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ > + { 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ > + { 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ > + { 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ > + { 0x820f3000, 0xa0c00, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ > + { 0x820f4000, 0xa1000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ > + { 0x820f5000, 0xa1400, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ > + { 0x820f7000, 0xa1e00, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ > + { 0x820f9000, 0xa3400, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ > + { 0x820fa000, 0xa4000, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ > + { 0x820fb000, 0xa4200, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ > + { 0x820fc000, 0xa4600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ > + { 0x820fd000, 0xa4800, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ > + }; > + int i; > + > + if (reg < 0x100000) > + return reg; > + > + for (i = 0; i < nitems(fixed_map); i++) { > + uint32_t ofs; > + > + if (reg < fixed_map[i].phys) > + continue; > + > + ofs = reg - fixed_map[i].phys; > + if (ofs > fixed_map[i].size) > + continue; > + > + return fixed_map[i].mapped + ofs; > + } > + > + if ((reg >= 0x18000000 && reg < 0x18c00000) || > + (reg >= 0x70000000 && reg < 0x78000000) || > + (reg >= 0x7c000000 && reg < 0x7c400000)) > + return mwx_map_reg_l1(sc, reg); > + > + panic("%s: Access to currently unsupported address %08x\n", > + DEVNAME(sc), reg); > +} > + > +int > +mt7921_init_hardware(struct mwx_softc *sc) > +{ > + int rv; > + > + /* reset dma */ > + rv = mwx_dma_reset(sc, 1); > + if (rv != 0) > + return rv; > + > + /* > + * force firmware operation mode into normal state, > + * which should be set before firmware download stage. > + */ > + mwx_write(sc, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE); > + mwx_barrier(sc); > + > + rv = mt7921_mcu_init(sc); > + if (rv != 0) > + goto fail; > + /* TODO override eeprom for systems with FDT */ > + rv = mt7921_mcu_set_eeprom(sc); > + if (rv != 0) > + goto fail; > + rv = mt7921_mac_init(sc); > + if (rv != 0) > + goto fail; > + > + /* MAYBE alloc beacon and mgmt frame wcid 0 here */ > + > + return 0; > + > + fail: > + /* reset dma */ > + rv = mwx_dma_reset(sc, 1); > + if (rv != 0) > + return rv; > + return EAGAIN; > +} > + > +int > +mt7921_mcu_init(struct mwx_softc *sc) > +{ > + int rv; > + > + /* this read is needed to make interrupts work */ > + (void) mwx_read(sc, MT_TOP_LPCR_HOST_BAND0); > + mwx_write(sc, MT_TOP_LPCR_HOST_BAND0, MT_TOP_LPCR_HOST_DRV_OWN); > + if (mwx_poll(sc, MT_TOP_LPCR_HOST_BAND0, 0, MT_TOP_LPCR_HOST_FW_OWN, > + 5000) != 0) { > + printf("%s: timeout for driver own\n", DEVNAME(sc)); > + return EIO; > + } > + > + if ((rv = mt7921_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; > + > + /* TODO mark MCU running */ > + > + return 0; > +} > + > +static inline uint32_t > +mt7921_get_data_mode(struct mwx_softc *sc, uint32_t info) > +{ > + uint32_t mode = DL_MODE_NEED_RSP; > + > + if (info == PATCH_SEC_NOT_SUPPORT) > + return mode; > + switch (info & PATCH_SEC_ENC_TYPE_MASK) { > + case PATCH_SEC_ENC_TYPE_PLAIN: > + break; > + case PATCH_SEC_ENC_TYPE_AES: > + mode |= DL_MODE_ENCRYPT; > + mode |= (info << DL_MODE_KEY_IDX_SHIFT) & DL_MODE_KEY_IDX_MASK; > + mode |= DL_MODE_RESET_SEC_IV; > + break; > + case PATCH_SEC_ENC_TYPE_SCRAMBLE: > + mode |= DL_MODE_ENCRYPT; > + mode |= DL_CONFIG_ENCRY_MODE_SEL; > + mode |= DL_MODE_RESET_SEC_IV; > + break; > + default: > + printf("%s: encryption type not supported\n", DEVNAME(sc)); > + } > + return mode; > +} > + > +static inline uint32_t > +mt7921_mcu_gen_dl_mode(uint8_t feature_set) > +{ > + uint32_t ret = DL_MODE_NEED_RSP; > + > + if (feature_set & FW_FEATURE_SET_ENCRYPT) > + ret |= (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV); > + if (feature_set & FW_FEATURE_ENCRY_MODE) > + ret |= DL_CONFIG_ENCRY_MODE_SEL; > + > + /* FW_FEATURE_SET_KEY_IDX_MASK == DL_MODE_KEY_IDX_MASK */ > + ret |= feature_set & FW_FEATURE_SET_KEY_IDX_MASK; > + > + return ret; > +} > + > + > +int > +mt7921_load_firmware(struct mwx_softc *sc) > +{ > + struct mt7921_patch_hdr *hdr; > + struct mt7921_fw_trailer *fwhdr; > + u_char *buf, *fwbuf, *dl; > + size_t buflen, fwlen, offset = 0; > + uint32_t reg, override = 0, option = 0; > + int i, rv, sem; > + > + reg = mwx_read(sc, MT_CONN_ON_MISC) & MT_TOP_MISC2_FW_N9_RDY; > + if (reg != 0) { > + DPRINTF("%s: firmware already downloaded\n", DEVNAME(sc)); > + return 0; > + } > + > + if ((rv = loadfirmware(MT7921_ROM_PATCH, &buf, &buflen)) != 0 || > + (rv = loadfirmware(MT7921_FIRMWARE_WM, &fwbuf, &fwlen)) != 0) { > + printf("%s: loadfirmware error %d\n", DEVNAME(sc), rv); > + return rv; > + } > + > + rv = mt7921_mcu_patch_sem_ctrl(sc, 1); > + if (rv != 0) > + return rv; > + > + if (buflen < sizeof(*hdr)) { > + DPRINTF("%s: invalid firmware\n", DEVNAME(sc)); > + rv = EINVAL; > + goto out; > + } > + hdr = (struct mt7921_patch_hdr *)buf; > + printf("%s: HW/SW version: 0x%x, build time: %.15s\n", > + DEVNAME(sc), be32toh(hdr->hw_sw_ver), hdr->build_date); > + > + for (i = 0; i < be32toh(hdr->desc.n_region); i++) { > + struct mt7921_patch_sec *sec; > + uint32_t len, addr, mode, sec_info; > + > + sec = (struct mt7921_patch_sec *)(buf + sizeof(*hdr) + > + i * sizeof(*sec)); > + if ((be32toh(sec->type) & PATCH_SEC_TYPE_MASK) != > + PATCH_SEC_TYPE_INFO) { > + DPRINTF("%s: invalid firmware sector\n", DEVNAME(sc)); > + rv = EINVAL; > + goto out; > + } > + > + addr = be32toh(sec->info.addr); > + len = be32toh(sec->info.len); > + dl = buf + be32toh(sec->offs); > + sec_info = be32toh(sec->info.sec_key_idx); > + mode = mt7921_get_data_mode(sc, sec_info); > + > + rv = mt7921_mcu_init_download(sc, addr, len, mode); > + if (rv != 0) { > + DPRINTF("%s: download request failed\n", DEVNAME(sc)); > + goto out; > + } > + rv = mt7921_mcu_send_firmware(sc, MCU_CMD_FW_SCATTER, > + dl, len, 4096); > + if (rv != 0) { > + DPRINTF("%s: failed to send patch\n", DEVNAME(sc)); > + goto out; > + } > + } > + > + rv = mt7921_mcu_start_patch(sc); > + if (rv != 0) { > + printf("%s: patch start failed\n", DEVNAME(sc)); > + goto fail; > + } > + > +out: > + sem = mt7921_mcu_patch_sem_ctrl(sc, 0); > + if (sem != 0) > + rv = sem; > + if (rv != 0) > + goto fail; > + > + fwhdr = (struct mt7921_fw_trailer *)(fwbuf + fwlen - sizeof(*fwhdr)); > + printf("%s: WM firmware version: %.10s, build time: %.15s\n", > + DEVNAME(sc), fwhdr->fw_ver, fwhdr->build_date); > + > + for (i = 0; i < fwhdr->n_region; i++) { > + struct mt7921_fw_region *region; > + uint32_t len, addr, mode; > + > + region = (struct mt7921_fw_region *)((u_char *)fwhdr - > + (fwhdr->n_region - i) * sizeof(*region)); > + > + addr = le32toh(region->addr); > + len = le32toh(region->len); > + mode = mt7921_mcu_gen_dl_mode(region->feature_set); > + > + if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) > + override = addr; > + > + rv = mt7921_mcu_init_download(sc, addr, len, mode); > + if (rv != 0) { > + DPRINTF("%s: download request failed\n", DEVNAME(sc)); > + goto fail; > + } > + > + rv = mt7921_mcu_send_firmware(sc, MCU_CMD_FW_SCATTER, > + fwbuf + offset, len, 4096); > + if (rv != 0) { > + DPRINTF("%s: failed to send firmware\n", DEVNAME(sc)); > + goto fail; > + } > + offset += len; > + } > + > + if (override != 0) > + option |= FW_START_OVERRIDE; > + > + rv = mt7921_mcu_start_firmware(sc, override, option); > + if (rv != 0) { > + DPRINTF("%s: firmware start failed\n", DEVNAME(sc)); > + goto fail; > + } > + > + /* XXX should not busy poll here */ > + if (mwx_poll(sc, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, > + MT_TOP_MISC2_FW_N9_RDY, 1500) != 0) { > + DPRINTF("%s: Timeout initializing firmware\n", DEVNAME(sc)); > + return EIO; > + } > + > + DPRINTF("%s: firmware loaded\n", DEVNAME(sc)); > + rv = 0; > + > +fail: > + free(buf, M_DEVBUF, buflen); > + free(fwbuf, M_DEVBUF, fwlen); > + return rv; > +} > + > +int > +mt7921_mac_wtbl_update(struct mwx_softc *sc, int idx) > +{ > + mwx_rmw(sc, MT_WTBL_UPDATE, > + (idx & MT_WTBL_UPDATE_WLAN_IDX) | MT_WTBL_UPDATE_ADM_COUNT_CLEAR, > + MT_WTBL_UPDATE_WLAN_IDX); > + > + return mwx_poll(sc, MT_WTBL_UPDATE, 0, MT_WTBL_UPDATE_BUSY, 5000); > +} > + > +void > +mt7921_mac_init_band(struct mwx_softc *sc, uint32_t band) > +{ > + mwx_rmw(sc, MT_TMAC_CTCR0(band), 0x3f, MT_TMAC_CTCR0_INS_DDLMT_REFTIME); > + mwx_set(sc, MT_TMAC_CTCR0(band), > + MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | > + MT_TMAC_CTCR0_INS_DDLMT_EN); > + > + mwx_set(sc, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); > + mwx_set(sc, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); > + > + /* enable MIB tx-rx time reporting */ > + mwx_set(sc, MT_MIB_SCR1(band), MT_MIB_TXDUR_EN); > + mwx_set(sc, MT_MIB_SCR1(band), MT_MIB_RXDUR_EN); > + > + mwx_rmw(sc, MT_DMA_DCR0(band), > + 1536 << MT_DMA_DCR0_MAX_RX_LEN_SHIFT, MT_DMA_DCR0_MAX_RX_LEN_MASK); > + /* disable rx rate report by default due to hw issues */ > + mwx_clear(sc, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); > +} > + > +int > +mt7921_mac_init(struct mwx_softc *sc) > +{ > + int i; > + > + mwx_rmw(sc, MT_MDP_DCR1, 1536 << MT_MDP_DCR1_MAX_RX_LEN_SHIFT, > + MT_MDP_DCR1_MAX_RX_LEN_MASK); > + > + /* enable hardware de-agg */ > + mwx_set(sc, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); > +#if 0 > + /* not enabled since our stack does not handle 802.3 frames */ > + /* enable hardware rx header translation */ > + mwx_set(sc, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); > +#endif > + > + for (i = 0; i < MT7921_WTBL_SIZE; i++) > + mt7921_mac_wtbl_update(sc, i); > + > + mt7921_mac_init_band(sc, 0); > + mt7921_mac_init_band(sc, 1); > + > + sc->sc_rxfilter = mwx_read(sc, MT_WF_RFCR(0)); > + return mt7921_mcu_set_rts_thresh(sc, 0x92b, 0); > +} > + > +int > +mt7921_mcu_patch_sem_ctrl(struct mwx_softc *sc, int semget) > +{ > +#define PATCH_SEM_RELEASE 0 > +#define PATCH_SEM_GET 1 > +#define PATCH_NOT_DL_SEM_FAIL 0 > +#define PATCH_IS_DL 1 > +#define PATCH_NOT_DL_SEM_SUCCESS 2 > +#define PATCH_REL_SEM_SUCCESS 3 > + > + uint32_t op = semget ? PATCH_SEM_GET : PATCH_SEM_RELEASE; > + struct { > + uint32_t op; > + } req = { > + .op = htole32(op), > + }; > + int rv, seq, sem; > + > + rv = mwx_mcu_send_msg(sc, MCU_CMD_PATCH_SEM_CONTROL, > + &req, sizeof(req), &seq); > + if (rv != 0) > + return rv; > + > + rv = mwx_mcu_wait_resp_int(sc, MCU_CMD_PATCH_SEM_CONTROL, seq, &sem); > + if (rv != 0) > + return rv; > + > + if (semget) { > + switch (sem) { > + case PATCH_IS_DL: > + return -1; > + case PATCH_NOT_DL_SEM_SUCCESS: > + return 0; > + default: > + DPRINTF("%s: failed to %s patch semaphore\n", > + DEVNAME(sc), "get"); > + return EAGAIN; > + } > + } else { > + switch (sem) { > + case PATCH_REL_SEM_SUCCESS: > + return 0; > + default: > + DPRINTF("%s: failed to %s patch semaphore\n", > + DEVNAME(sc), "release"); > + return EAGAIN; > + } > + } > +} > + > +int > +mt7921_mcu_init_download(struct mwx_softc *sc, uint32_t addr, > + uint32_t len, uint32_t mode) > +{ > + struct { > + uint32_t addr; > + uint32_t len; > + uint32_t mode; > + } req = { > + .addr = htole32(addr), > + .len = htole32(len), > + .mode = htole32(mode), > + }; > + int cmd; > + > + if (addr == 0x200000 || addr == 0x900000) > + cmd = MCU_CMD_PATCH_START_REQ; > + else > + cmd = MCU_CMD_TARGET_ADDRESS_LEN_REQ; > + > + return mwx_mcu_send_wait(sc, cmd, &req, sizeof(req)); > +} > + > +int > +mt7921_mcu_send_firmware(struct mwx_softc *sc, int cmd, u_char *data, > + size_t len, size_t max_len) > +{ > + size_t cur_len; > + int rv; > + > + while (len > 0) { > + cur_len = len; > + if (cur_len > max_len) > + cur_len = max_len; > + > + rv = mwx_mcu_send_msg(sc, cmd, data, cur_len, NULL); > + if (rv != 0) > + return rv; > + > + data += cur_len; > + len -= cur_len; > + > + mwx_dma_tx_cleanup(sc, &sc->sc_txfwdlq); > + } > + > + return 0; > +} > + > +int > +mt7921_mcu_start_patch(struct mwx_softc *sc) > +{ > + struct { > + uint8_t check_crc; > + uint8_t reserved[3]; > + } req = { > + .check_crc = 0, > + }; > + > + return mwx_mcu_send_wait(sc, MCU_CMD_PATCH_FINISH_REQ, &req, > + sizeof(req)); > +} > + > +int > +mt7921_mcu_start_firmware(struct mwx_softc *sc, uint32_t addr, uint32_t > option) > +{ > + struct { > + uint32_t option; > + uint32_t addr; > + } req = { > + .option = htole32(option), > + .addr = htole32(addr), > + }; > + > + return mwx_mcu_send_wait(sc, MCU_CMD_FW_START_REQ, &req, sizeof(req)); > +} > + > +int > +mt7921_mcu_get_nic_capability(struct mwx_softc *sc) > +{ > + struct mt76_connac_cap_hdr { > + uint16_t n_elements; > + uint16_t pad; > + } __packed *hdr; > + struct tlv_hdr { > + 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 mbuf *m; > + int rv, seq, count, i; > + > + rv = mwx_mcu_send_msg(sc, MCU_CE_CMD_GET_NIC_CAPAB, NULL, 0, &seq); > + if (rv != 0) > + return rv; > + > + rv = mwx_mcu_wait_resp_msg(sc, MCU_CE_CMD_GET_NIC_CAPAB, seq, &m); > + if (rv != 0) > + return rv; > + > + /* the message was allready pulled up by mwx_mcu_rx_event() */ > + if (m->m_len < sizeof(*hdr)) { > + printf("%s: GET_NIC_CAPAB response size error\n", DEVNAME(sc)); > + 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++) { > + uint32_t type, len; > + > + if (m->m_len < sizeof(*tlv)) { > + printf("%s: GET_NIC_CAPAB tlv size error\n", > + DEVNAME(sc)); > + return EINVAL; > + } > + > + tlv = mtod(m, struct tlv_hdr *); > + type = le32toh(tlv->type); > + len = le32toh(tlv->len); > + m_adj(m, sizeof(*tlv)); > + > + if (m->m_len < len) > + break; > + switch (type) { > + case MT_NIC_CAP_6G: > + sc->sc_capa.has_6ghz = 1; > + 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 mt76_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; > + case MT_NIC_CAP_TX_RESOURCE: > + /* unused on PCIe devices */ > + 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) > +{ > + struct { > + uint8_t ctrl; > + uint8_t pad[3]; > + } req = { > + .ctrl = ctrl, > + }; > + > + return mwx_mcu_send_msg(sc, MCU_CE_CMD_FWLOG_2_HOST, &req, > + sizeof(req), NULL); > +} > + > +int > +mt7921_mcu_set_eeprom(struct mwx_softc *sc) > +{ > + struct req_hdr { > + uint8_t buffer_mode; > + uint8_t format; > + uint8_t pad[2]; > + } req = { > + .buffer_mode = EE_MODE_EFUSE, > + .format = EE_FORMAT_WHOLE, > + }; > + > + return mwx_mcu_send_wait(sc, MCU_EXT_CMD_EFUSE_BUFFER_MODE, &req, > + sizeof(req)); > +} > + > +int > +mt7921_mcu_set_rts_thresh(struct mwx_softc *sc, uint32_t val, uint8_t band) > +{ > + struct { > + uint8_t prot_idx; > + uint8_t band; > + uint8_t rsv[2]; > + uint32_t len_thresh; > + uint32_t pkt_thresh; > + } __packed req = { > + .prot_idx = 1, > + .band = band, > + .len_thresh = htole32(val), > + .pkt_thresh = htole32(0x2), > + }; > + > + return mwx_mcu_send_wait(sc, MCU_EXT_CMD_PROTECT_CTRL, &req, > + sizeof(req)); > +} > + > +int > +mt7921_mcu_set_deep_sleep(struct mwx_softc *sc, int ena) > +{ > + struct mt76_connac_config req = { > + .resp_type = 0, > + }; > + > + DPRINTF("%s: %s deep sleep\n", DEVNAME(sc), ena ? "enable" : "disable"); > + snprintf(req.data, sizeof(req.data), "KeepFullPwr %d", !ena); > + return mwx_mcu_send_msg(sc, MCU_CE_CMD_CHIP_CONFIG, &req, > + sizeof(req), NULL); > +} > + > +#ifdef NOTYET > +int > +mt7921_sta_state_dp(struct mwx_softc *sc, enum ieee80211_state old_state, > + enum ieee80211_state new_state) > +{ > + if ((old_state == IEEE80211_STA_ASSOC && > + new_state == IEEE80211_STA_AUTHORIZED) || > + (old_state == IEEE80211_STA_NONE && > + new_state == IEEE80211_STA_NOTEXIST)) > + mt7921_mcu_set_deep_sleep(dev, 1); > + if ((old_state == IEEE80211_STA_NOTEXIST && > + new_state == IEEE80211_STA_NONE) || > + (old_state == IEEE80211_STA_AUTHORIZED && > + new_state == IEEE80211_STA_ASSOC)) > + mt7921_mcu_set_deep_sleep(dev, 0); > + return 0; > +} > +#endif > + > +void > +mt7921_mcu_low_power_event(struct mwx_softc *sc, struct mbuf *m) > +{ > + struct mt7921_mcu_lp_event { > + uint8_t state; > + uint8_t reserved[3]; > + } __packed *event; > + > + if (m->m_len < sizeof(*event)) > + return; > + event = mtod(m, struct mt7921_mcu_lp_event *); > + DPRINTF("%s: low power event state %d\n", DEVNAME(sc), event->state); > +} > + > +void > +mt7921_mcu_tx_done_event(struct mwx_softc *sc, struct mbuf *m) > +{ > + struct mt7921_mcu_tx_done_event { > + uint8_t pid; > + uint8_t status; > + uint16_t seq; > + uint8_t wlan_idx; > + uint8_t tx_cnt; > + uint16_t tx_rate; > + uint8_t flag; > + uint8_t tid; > + uint8_t rsp_rate; > + uint8_t mcs; > + uint8_t bw; > + uint8_t tx_pwr; > + uint8_t reason; > + uint8_t rsv0[1]; > + uint32_t delay; > + uint32_t timestamp; > + uint32_t applied_flag; > + uint8_t txs[28]; > + uint8_t rsv1[32]; > + } __packed *event; > + > + if (m->m_len < sizeof(*event)) > + return; > + event = mtod(m, struct mt7921_mcu_tx_done_event *); > + // TODO mt7921_mac_add_txs(dev, event->txs); > +} > + > +void > +mt7921_mcu_scan_event(struct mwx_softc *sc, struct mbuf *m) > +{ > + struct ieee80211com *ic = &sc->sc_ic; > + > + if ((sc->sc_flags & (MWX_FLAG_SCANNING | MWX_FLAG_BGSCAN)) == 0) > + return; > + > + sc->sc_flags &= ~(MWX_FLAG_SCANNING | MWX_FLAG_BGSCAN); > + ieee80211_end_scan(&ic->ic_if); > +} > + > +int > +mt7921_hw_scan(struct mwx_softc *sc, int bgscan) > +{ > + struct mt76_connac_hw_scan_req *req; > + int n_ssids = 0; > + int rv; > + > + req = malloc(sizeof(*req), M_DEVBUF, M_NOWAIT | M_ZERO); > + if (req == NULL) > + return ENOMEM; > + > + sc->sc_flags |= MWX_FLAG_SCANNING; > + > + sc->sc_scan_seq_num = (sc->sc_scan_seq_num + 1) & 0x7f; > + > + req->seq_num = sc->sc_scan_seq_num /* | sc->sc_band_idx << 7 */; > + req->bss_idx = /* mvif->idx */ 0; > + req->scan_type = /* sreq->n_ssids ? 1 : */ 0; > + req->probe_req_num = /* sreq->n_ssids ? 2 : */ 0; > + req->version = 1; > + > +#ifdef NOTYET > + for (i = 0; i < sreq->n_ssids; i++) { > + if (!sreq->ssids[i].ssid_len) > + continue; > + req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); > + memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid, > + sreq->ssids[i].ssid_len); > + n_ssids++; > + } > +#endif > + > + req->ssid_type = n_ssids ? 0x4 : 0x1; > + req->ssid_type_ext = n_ssids ? 1 : 0; > + req->ssids_num = n_ssids; > + > +#ifdef NOTYET > + if (sreq->n_channels <= 32) { > + req->channels_num = sreq->n_channels; > + } else { > + req->channels_num = 32 > + if (sreq->n_channels - 32 <= 32) > + req->ext_channels_num = sreq->n_channels - 32; > + else > + req->ext_channels_num = 32; > + } > + for (i = 0; i < req->channels_num + req->ext_channels_num; i++) { > + struct mt76_connac_mcu_scan_channel *chan; > + > + if (i >= 32) > + chan = &req->ext_channels[i - 32]; > + else > + chan = &req->channels[i]; > + switch (scan_list[i]->band) { > + case NL80211_BAND_2GHZ: > + chan->band = 1; > + break; > + case NL80211_BAND_6GHZ: > + chan->band = 3; > + break; > + default: > + chan->band = 2; > + break; > + } > + chan->channel_num = scan_list[i]->hw_value; > + } > +#endif > + req->channel_type = /* sreq->n_channels ? 4 : */ 0; > + > + > +#ifdef NOTYET > + if (sreq->ie_len > 0) { > + memcpy(req->ies, sreq->ie, sreq->ie_len); > + req->ies_len = cpu_to_le16(sreq->ie_len); > + } > +#endif > + > + req->scan_func |= SCAN_FUNC_SPLIT_SCAN; > + > + /* wildcard BSSID */ > + memset(req->bssid, 0xff, ETHER_ADDR_LEN); > +#ifdef NOTYET > + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { > + get_random_mask_addr(req->random_mac, sreq->mac_addr, > + sreq->mac_addr_mask); > + req->scan_func |= SCAN_FUNC_RANDOM_MAC; > + } > +#endif > + > + rv = mwx_mcu_send_msg(sc, MCU_CE_CMD_START_HW_SCAN, req, > + sizeof(*req), NULL); > + > + if (rv != 0) > + sc->sc_flags &= ~(MWX_FLAG_SCANNING | MWX_FLAG_BGSCAN); > + > + free(req, M_DEVBUF, sizeof(*req)); > + return rv; > +} > + > +int > +mt7921_hw_scan_cancel(struct mwx_softc *sc) > +{ > + struct { > + uint8_t seq_num; > + uint8_t is_ext_channel; > + uint8_t rsv[2]; > + } __packed req = { > + .seq_num = sc->sc_scan_seq_num, > + }; > + int rv; > + > + rv = mwx_mcu_send_msg(sc, MCU_CE_CMD_CANCEL_HW_SCAN, &req, > + sizeof(req), NULL); > + if (rv == 0) > + sc->sc_flags &= ~(MWX_FLAG_SCANNING | MWX_FLAG_BGSCAN); > + return rv; > +} > + > +int > +mt7921_mcu_set_mac_enable(struct mwx_softc *sc, int band, int enable) > +{ > + struct { > + uint8_t enable; > + uint8_t band; > + uint8_t rsv[2]; > + } __packed req = { > + .enable = enable, > + .band = band, > + }; > + > + return mwx_mcu_send_wait(sc, MCU_EXT_CMD_MAC_INIT_CTRL, &req, > + sizeof(req)); > +} > + > +int > +mt7921_mcu_set_channel_domain(struct mwx_softc *sc) > +{ > + struct { > + uint8_t alpha2[4]; /* regulatory_request.alpha2 */ > + uint8_t bw_2g; /* BW_20_40M 0 > + * BW_20M 1 > + * BW_20_40_80M 2 > + * BW_20_40_80_160M 3 > + * BW_20_40_80_8080M 4 > + */ > + uint8_t bw_5g; > + uint8_t bw_6g; > + uint8_t pad; > + uint8_t n_2ch; > + uint8_t n_5ch; > + uint8_t n_6ch; > + uint8_t pad2; > + } __packed *hdr; > + struct { > + uint16_t hw_value; > + uint16_t pad; > + uint16_t flags; > + } __packed *channel; > + struct ieee80211com *ic = &sc->sc_ic; > + struct ieee80211_channel *chan; > + int i, len, rv; > + int n_2ch = 0, n_5ch = 0, n_6ch = 0; > + > + len = sizeof(*hdr) + IEEE80211_CHAN_MAX * sizeof(channel); > + hdr = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); > + if (hdr == NULL) > + return ENOMEM; > + > + hdr->bw_2g = 0; /* BW_20_40M */ > + hdr->bw_5g = 3; /* BW_20_40_80_160M */ > + hdr->bw_6g = 3; /* BW_20_40_80_160M */ > + > + channel = (void *)(hdr + 1); > + > + for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { > + chan = &ic->ic_channels[i]; > + if (!IEEE80211_IS_CHAN_2GHZ(chan)) > + continue; > + > + channel->hw_value = htole16(ieee80211_chan2ieee(ic, chan)); > + channel->flags = htole32(0); /* XXX */ > + > + channel++; > + n_2ch++; > + } > + for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { > + chan = &ic->ic_channels[i]; > + if (!IEEE80211_IS_CHAN_5GHZ(chan)) > + continue; > + > + channel->hw_value = htole16(ieee80211_chan2ieee(ic, chan)); > + channel->flags = htole32(0); /* XXX */ > + > + channel++; > + n_5ch++; > + } > +#ifdef NOTYET > + /* 6GHz handling */ > + for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { > + chan = &ic->ic_channels[i]; > + if (!IEEE80211_IS_CHAN_6GHZ(chan)) > + continue; > + > + channel->hw_value = htole16(ieee80211_chan2ieee(ic, chan)); > + channel->flags = htole32(0); /* XXX */ > + > + channel++; > + n_6ch++; > + } > +#endif > + > + memcpy(hdr->alpha2, sc->sc_alpha2, sizeof(hdr->alpha2)); > + hdr->n_2ch = n_2ch; > + hdr->n_5ch = n_5ch; > + hdr->n_6ch = n_6ch; > + > + i = (caddr_t)channel - (caddr_t)hdr; > + rv = mwx_mcu_send_msg(sc, MCU_CE_CMD_SET_CHAN_DOMAIN, hdr, i, NULL); > + free(hdr, M_DEVBUF, len); > + return rv; > +} > + > +uint8_t > +mt7921_mcu_chan_bw(struct ieee80211_channel *channel) > +{ > + /* > + * following modes are not yet supported > + * CMD_CBW_5MHZ, CMD_CBW_10MHZ, CMD_CBW_8080MHZ > + */ > + if (channel->ic_xflags & IEEE80211_CHANX_160MHZ) > + return CMD_CBW_160MHZ; > + if (channel->ic_xflags & IEEE80211_CHANX_80MHZ) > + return CMD_CBW_80MHZ; > + if (channel->ic_flags & IEEE80211_CHAN_40MHZ) > + return CMD_CBW_40MHZ; > + return CMD_CBW_20MHZ; > +} > + > +int > +mt7921_mcu_set_chan_info(struct mwx_softc *sc, int cmd) > +{ > + struct ieee80211_channel *channel = sc->sc_ic.ic_ibss_chan; > + struct { > + uint8_t control_ch; > + uint8_t center_ch; > + uint8_t bw; > + uint8_t tx_streams_num; > + uint8_t rx_streams; /* mask or num */ > + uint8_t switch_reason; > + uint8_t band_idx; > + uint8_t center_ch2; /* for 80+80 only */ > + uint16_t cac_case; > + uint8_t channel_band; > + uint8_t rsv0; > + uint32_t outband_freq; > + uint8_t txpower_drop; > + uint8_t ap_bw; > + uint8_t ap_center_ch; > + uint8_t rsv1[57]; > + } __packed req = { > + .control_ch = ieee80211_mhz2ieee(channel->ic_freq, > + channel->ic_flags), > + .center_ch = ieee80211_mhz2ieee(channel->ic_freq, > + channel->ic_flags), > + .tx_streams_num = sc->sc_capa.num_streams, > + .rx_streams = sc->sc_capa.antenna_mask, > + .band_idx = 0, /* XXX 0 or 1 */ > + }; > + > + req.bw = mt7921_mcu_chan_bw(channel); > + > +#ifdef NOTYET > + if (channel->ic_flags & IEEE80211_CHAN_6GHZ) > + req.channel_band = 2; > + else > +#endif > + if (channel->ic_flags & IEEE80211_CHAN_5GHZ) > + req.channel_band = 1; > + else > + req.channel_band = 0; > + > +#ifdef NOTYET > + if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) > + req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; > + else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && > + chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) > + req.switch_reason = CH_SWITCH_DFS; > + else > +#endif > + req.switch_reason = CH_SWITCH_NORMAL; > + > + if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) > + req.rx_streams = sc->sc_capa.num_streams; > + > +#ifdef NOTYET > + if (chandef->width == NL80211_CHAN_WIDTH_80P80) { > + int freq2 = chandef->center_freq2; > + req.center_ch2 = ieee80211_frequency_to_channel(freq2); > + } > +#endif > + > + return mwx_mcu_send_wait(sc, cmd, &req, sizeof(req)); > +} > + > +void > +mt7921_mac_reset_counters(struct mwx_softc *sc) > +{ > + int i; > + > + for (i = 0; i < 4; i++) { > + mwx_read(sc, MT_TX_AGG_CNT(0, i)); > + mwx_read(sc, MT_TX_AGG_CNT2(0, i)); > + } > + > + /* XXX TODO stats in softc */ > + > + /* reset airtime counters */ > + mwx_read(sc, MT_MIB_SDR9(0)); > + mwx_read(sc, MT_MIB_SDR36(0)); > + mwx_read(sc, MT_MIB_SDR37(0)); > + mwx_set(sc, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); > + mwx_set(sc, MT_WF_RMAC_MIB_AIRTIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); > +} > + > +int > +mt7921_mcu_uni_add_dev(struct mwx_softc *sc, struct mwx_vif *mvif, > + struct mwx_node *mn, int enable) > +{ > + struct { > + struct { > + uint8_t omac_idx; > + uint8_t band_idx; > + uint16_t pad; > + } __packed hdr; > + struct req_tlv { > + uint16_t tag; > + uint16_t len; > + uint8_t active; > + uint8_t pad; > + uint8_t omac_addr[ETHER_ADDR_LEN]; > + } __packed tlv; > + } dev_req = { > + .hdr = { > + .omac_idx = mvif->omac_idx, > + .band_idx = mvif->band_idx, > + }, > + .tlv = { > + .tag = htole16(DEV_INFO_ACTIVE), > + .len = htole16(sizeof(struct req_tlv)), > + .active = enable, > + }, > + }; > + struct { > + struct { > + uint8_t bss_idx; > + uint8_t pad[3]; > + } __packed hdr; > + struct mt76_connac_bss_basic_tlv basic; > + } basic_req = { > + .hdr = { > + .bss_idx = mvif->idx, > + }, > + .basic = { > + .tag = htole16(UNI_BSS_INFO_BASIC), > + .len = htole16(sizeof(struct > mt76_connac_bss_basic_tlv)), > + .omac_idx = mvif->omac_idx, > + .band_idx = mvif->band_idx, > + .wmm_idx = mvif->wmm_idx, > + .active = enable, > + .bmc_tx_wlan_idx = htole16(mn->wcid), > + .sta_idx = htole16(mn->wcid), > + .conn_state = 1, > + }, > + }; > + int rv, idx, cmd, len; > + void *data; > + > + switch (sc->sc_ic.ic_opmode) { > + case IEEE80211_M_MONITOR: > + case IEEE80211_M_HOSTAP: > + basic_req.basic.conn_type = htole32(CONNECTION_INFRA_AP); > + break; > + case IEEE80211_M_STA: > + basic_req.basic.conn_type = htole32(CONNECTION_INFRA_STA); > + break; > + case IEEE80211_M_IBSS: > + basic_req.basic.conn_type = htole32(CONNECTION_IBSS_ADHOC); > + break; > + default: > + panic("%s: unknown operation mode", DEVNAME(sc)); > + } > + > + idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; > + basic_req.basic.hw_bss_idx = idx; > + > + memcpy(dev_req.tlv.omac_addr, sc->sc_lladdr, ETHER_ADDR_LEN); > + > + if (enable) { > + cmd = MCU_UNI_CMD_DEV_INFO_UPDATE; > + data = &dev_req; > + len = sizeof(dev_req); > + } else { > + cmd = MCU_UNI_CMD_BSS_INFO_UPDATE; > + data = &basic_req; > + len = sizeof(basic_req); > + } > + > +printf("%s: %s cmd %x mvif idx %d omac %d band %d wmm %d\n", DEVNAME(sc), > __func__, cmd, mvif->idx, mvif->omac_idx, mvif->band_idx, mvif->wmm_idx); > + rv = mwx_mcu_send_wait(sc, cmd, data, len); > + if (rv < 0) > + return rv; > + > + if (enable) { > + cmd = MCU_UNI_CMD_BSS_INFO_UPDATE; > + data = &basic_req; > + len = sizeof(basic_req); > + } else { > + cmd = MCU_UNI_CMD_DEV_INFO_UPDATE; > + data = &dev_req; > + len = sizeof(dev_req); > + } > + > +printf("%s: %s cmd %x wcid %d\n", DEVNAME(sc), __func__, cmd, mn->wcid); > + return mwx_mcu_send_wait(sc, cmd, data, len); > +} > + > +int > +mt7921_mcu_set_sniffer(struct mwx_softc *sc, int enable) > +{ > + struct { > + uint8_t band_idx; > + uint8_t pad[3]; > + struct sniffer_enable_tlv { > + uint16_t tag; > + uint16_t len; > + uint8_t enable; > + uint8_t pad[3]; > + } enable; > + } req = { > + .band_idx = 0, > + .enable = { > + .tag = htole16(0), > + .len = htole16(sizeof(struct sniffer_enable_tlv)), > + .enable = enable, > + }, > + }; > + > + return mwx_mcu_send_wait(sc, MCU_UNI_CMD_SNIFFER, &req, sizeof(req)); > +} > + > +int > +mt7921_mcu_set_beacon_filter(struct mwx_softc *sc, int enable) > +{ > +#ifdef NOTYET > + int rv; > + > + if (enable) { > + rv = mt7921_mcu_uni_bss_bcnft(dev, vif, true); > + if (rv) > + return rv; > + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; > + ieee80211_hw_set(hw, CONNECTION_MONITOR); > + mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); > + return 0; > + } > + > + rv = mt7921_mcu_set_bss_pm(dev, vif, false); > + if (rv) > + return rv; > + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; > + __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); > + mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); > +#endif > + return 0; > +} > + > +int > +mt7921_mac_fill_rx(struct mwx_softc *sc, struct mbuf *m, > + struct ieee80211_rxinfo *rxi) > +{ > + struct ieee80211com *ic = &sc->sc_ic; > + uint32_t *rxd, rxd0, rxd1, rxd2, rxd3, rxd4; > +// uint32_t mode = 0; > + uint16_t hdr_gap /*, seq_ctrl = 0, fc = 0 */; > + uint8_t chfreq, remove_pad /*, qos_ctl = 0, amsdu_info */; > + int idx, unicast, num_rxd = 6; > +// bool insert_ccmp_hdr = false; > + > + if (m->m_len < num_rxd * sizeof(uint32_t)) > + return -1; > + > + rxd = mtod(m, uint32_t *); > + rxd0 = le32toh(rxd[0]); > + rxd1 = le32toh(rxd[1]); > + rxd2 = le32toh(rxd[2]); > + rxd3 = le32toh(rxd[3]); > + rxd4 = le32toh(rxd[4]); > + > + if (rxd1 & MT_RXD1_NORMAL_BAND_IDX) > + return -1; > + > + if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) > + return -1; > + > + if (rxd2 & MT_RXD2_NORMAL_HDR_TRANS) > + return -1; > + > + /* ICV error or CCMP/BIP/WPI MIC error */ > + if (rxd1 & MT_RXD1_NORMAL_ICV_ERR) { > + ic->ic_stats.is_rx_decryptcrc++; > + return -1; > + } > + > + if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) > + return -1; > + > + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) { > + /* report MIC failures to net80211 for TKIP */ > + ic->ic_stats.is_rx_locmicfail++; > + ieee80211_michael_mic_failure(ic, 0/* XXX */); > + return -1; > + } > + > + > + chfreq = (rxd3 & MT_RXD3_NORMAL_CH_FREQ_MASK) >> > + MT_RXD3_NORMAL_CH_FREQ_SHIFT; > + unicast = (rxd3 & MT_RXD3_NORMAL_ADDR_TYPE_MASK) == MT_RXD3_NORMAL_U2M; > + idx = rxd1 & MT_RXD1_NORMAL_WLAN_IDX_MASK; > + > +#if 0 > + status->wcid = mt7921_rx_get_wcid(dev, idx, unicast); > + if (status->wcid) { > + struct mt7921_sta *msta; > + > + msta = container_of(status->wcid, struct mt7921_sta, wcid); > + spin_lock_bh(&dev->sta_poll_lock); > + if (list_empty(&msta->poll_list)) > + list_add_tail(&msta->poll_list, &dev->sta_poll_list); > + spin_unlock_bh(&dev->sta_poll_lock); > + } > +#endif > + > +#if NOTYET > + if ((rxd0 & (MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM)) == > + (MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM)) { > + m->m_pkthdr.csum_flags = M_IPV4_CSUM_IN_OK | > + M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK; > + } > +#endif > + > + if ((rxd1 & MT_RXD1_NORMAL_SEC_MODE_MASK) != 0 && > + !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { > + rxi->rxi_flags |= IEEE80211_RXI_HWDEC | > + IEEE80211_RXI_HWDEC_IV_STRIPPED; > + } > + > + remove_pad = (rxd2 & MT_RXD2_NORMAL_HDR_OFFSET_MASK) >> > + MT_RXD2_NORMAL_HDR_OFFSET_SHIFT; > + > + if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) > + return -EINVAL; > + > + rxd += 6; > + > + if (rxd1 & MT_RXD1_NORMAL_GROUP_4) > + num_rxd += 4; > + if (rxd1 & MT_RXD1_NORMAL_GROUP_1) > + num_rxd += 4; > + if (rxd1 & MT_RXD1_NORMAL_GROUP_2) > + num_rxd += 2; > + if (rxd1 & MT_RXD1_NORMAL_GROUP_3) > + num_rxd += 2; > + if (rxd1 & MT_RXD1_NORMAL_GROUP_5) > + num_rxd += 18; > + > + if (m->m_len < num_rxd * sizeof(uint32_t)) > + return -1; > + > +#if 0 > + if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { > + uint32_t v0 = le32toh(rxd[0]); > + uint32_t v2 = le32toh(rxd[2]); > + > + fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0)); > + seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2); > + qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2); > + > + rxd += 4; > + } > + > + if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { > + u8 *data = (u8 *)rxd; > + > + if (status->flag & RX_FLAG_DECRYPTED) { > + switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) { > + case MT_CIPHER_AES_CCMP: > + case MT_CIPHER_CCMP_CCX: > + case MT_CIPHER_CCMP_256: > + insert_ccmp_hdr = > + (rxd2 & MT_RXD2_NORMAL_FRAG); > + /* FALLTHROUGH */ > + case MT_CIPHER_TKIP: > + case MT_CIPHER_TKIP_NO_MIC: > + case MT_CIPHER_GCMP: > + case MT_CIPHER_GCMP_256: > + status->iv[0] = data[5]; > + status->iv[1] = data[4]; > + status->iv[2] = data[3]; > + status->iv[3] = data[2]; > + status->iv[4] = data[1]; > + status->iv[5] = data[0]; > + break; > + default: > + break; > + } > + } > + rxd += 4; > + } > + > + if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { > + status->timestamp = le32_to_cpu(rxd[0]); > + status->flag |= RX_FLAG_MACTIME_START; > + > + if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { > + status->flag |= RX_FLAG_AMPDU_DETAILS; > + > + /* all subframes of an A-MPDU have the same timestamp */ > + if (phy->rx_ampdu_ts != status->timestamp) { > + if (!++phy->ampdu_ref) > + phy->ampdu_ref++; > + } > + phy->rx_ampdu_ts = status->timestamp; > + > + status->ampdu_ref = phy->ampdu_ref; > + } > + > + rxd += 2; > + } > + > + /* RXD Group 3 - P-RXV */ > + if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { > + u8 stbc, gi; > + u32 v0, v1; > + bool cck; > + > + rxv = rxd; > + rxd += 2; > + > + v0 = le32_to_cpu(rxv[0]); > + v1 = le32_to_cpu(rxv[1]); > + > + if (v0 & MT_PRXV_HT_AD_CODE) > + status->enc_flags |= RX_ENC_FLAG_LDPC; > + > + status->chains = mphy->antenna_mask; > + status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1); > + status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); > + status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); > + status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1); > + status->signal = -128; > + for (i = 0; i < hweight8(mphy->antenna_mask); i++) { > + if (!(status->chains & BIT(i)) || > + status->chain_signal[i] >= 0) > + continue; > + > + status->signal = max(status->signal, > + status->chain_signal[i]); > + } > + > + stbc = FIELD_GET(MT_PRXV_STBC, v0); > + gi = FIELD_GET(MT_PRXV_SGI, v0); > + cck = false; > + > + idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); > + mode = FIELD_GET(MT_PRXV_TX_MODE, v0); > + > + switch (mode) { > + case MT_PHY_TYPE_CCK: > + cck = true; > + fallthrough; > + case MT_PHY_TYPE_OFDM: > + i = mt76_get_rate(&dev->mt76, sband, i, cck); > + break; > + case MT_PHY_TYPE_HT_GF: > + case MT_PHY_TYPE_HT: > + status->encoding = RX_ENC_HT; > + if (i > 31) > + return -EINVAL; > + break; > + case MT_PHY_TYPE_VHT: > + status->nss = > + FIELD_GET(MT_PRXV_NSTS, v0) + 1; > + status->encoding = RX_ENC_VHT; > + if (i > 9) > + return -EINVAL; > + break; > + case MT_PHY_TYPE_HE_MU: > + case MT_PHY_TYPE_HE_SU: > + case MT_PHY_TYPE_HE_EXT_SU: > + case MT_PHY_TYPE_HE_TB: > + status->nss = > + FIELD_GET(MT_PRXV_NSTS, v0) + 1; > + status->encoding = RX_ENC_HE; > + i &= GENMASK(3, 0); > + > + if (gi <= NL80211_RATE_INFO_HE_GI_3_2) > + status->he_gi = gi; > + > + status->he_dcm = !!(idx & MT_PRXV_TX_DCM); > + break; > + default: > + return -EINVAL; > + } > + > + status->rate_idx = i; > + > + switch (FIELD_GET(MT_PRXV_FRAME_MODE, v0)) { > + case IEEE80211_STA_RX_BW_20: > + break; > + case IEEE80211_STA_RX_BW_40: > + if (mode & MT_PHY_TYPE_HE_EXT_SU && > + (idx & MT_PRXV_TX_ER_SU_106T)) { > + status->bw = RATE_INFO_BW_HE_RU; > + status->he_ru = > + NL80211_RATE_INFO_HE_RU_ALLOC_106; > + } else { > + status->bw = RATE_INFO_BW_40; > + } > + break; > + case IEEE80211_STA_RX_BW_80: > + status->bw = RATE_INFO_BW_80; > + break; > + case IEEE80211_STA_RX_BW_160: > + status->bw = RATE_INFO_BW_160; > + break; > + default: > + return -EINVAL; > + } > + > + status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; > + if (mode < MT_PHY_TYPE_HE_SU && gi) > + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; > + > + if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { > + rxd += 18; > + } > + } > + > + amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); > + status->amsdu = !!amsdu_info; > + if (status->amsdu) { > + status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; > + status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; > + } > +#endif > + > + hdr_gap = num_rxd * sizeof(uint32_t) + 2 * remove_pad; > + m_adj(m, hdr_gap); > +#if 0 > + if (status->amsdu) { > + memmove(skb->data + 2, skb->data, > + ieee80211_get_hdrlen_from_skb(skb)); > + skb_pull(skb, 2); > + } > + > + struct ieee80211_hdr *hdr; > + > + if (insert_ccmp_hdr) { > + u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); > + > + mt76_insert_ccmp_hdr(skb, key_id); > + } > + > + hdr = mt76_skb_get_hdr(skb); > + fc = hdr->frame_control; > + if (ieee80211_is_data_qos(fc)) { > + seq_ctrl = le16_to_cpu(hdr->seq_ctrl); > + qos_ctl = *ieee80211_get_qos_ctl(hdr); > + } > + > + if (!status->wcid || !ieee80211_is_data_qos(fc)) > + return 0; > + > + status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc); > + status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); > + status->qos_ctl = qos_ctl; > +#endif > + rxi->rxi_chan = chfreq; > + > + return 0; > +} > Index: if_mwxreg.h > =================================================================== > RCS file: if_mwxreg.h > diff -N if_mwxreg.h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ if_mwxreg.h 9 Dec 2022 17:09:39 -0000 > @@ -0,0 +1,1076 @@ > +/* > + * Copyright (c) 2022 Claudio Jeker <clau...@openbsd.org> > + * Copyright (C) 2021 MediaTek Inc. > + * Copyright (C) 2016 Felix Fietkau <n...@nbd.name> > + * > + * Permission to use, copy, modify, and/or distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +/* MCU WFDMA1 */ > +#define MT_MCU_WFDMA1_BASE 0x3000 > + > +#define MT_MDP_BASE 0x820cd000 > +#define MT_MDP_DCR0 0x820cd000 > +#define MT_MDP_DCR0_DAMSDU_EN (1U << 15) > +#define MT_MDP_DCR0_RX_HDR_TRANS_EN (1U << 19) > + > +#define MT_MDP_DCR1 0x820cd004 > +#define MT_MDP_DCR1_MAX_RX_LEN_MASK 0x0000fff8 > +#define MT_MDP_DCR1_MAX_RX_LEN_SHIFT 3 > + > +/* TMAC: band 0 (0x21000), band 1 (0xa1000) */ > +#define MT_BAND_BASE0 0x820f0000 > +#define MT_BAND_BASE1 0x820e0000 > +#define MT_BAND_OFF (MT_BAND_BASE0 - MT_BAND_BASE1) > +#define MT_BAND_ADDR(_band, ofs) \ > + (MT_BAND_BASE0 - (_band) * MT_BAND_OFF + (ofs)) > + > +#define MT_TMAC_TCR0(_band) MT_BAND_ADDR(_band, 0x4000) > +#define MT_TMAC_TCR0_TBTT_STOP_CTRL (1U << 25) > + > +#define MT_TMAC_CDTR(_band) MT_BAND_ADDR(_band, 0x4090) > +#define MT_TMAC_ODTR(_band) MT_BAND_ADDR(_band, 0x4094) > +#define MT_TIMEOUT_VAL_PLCP 0x0000ffff > +#define MT_TIMEOUT_VAL_CCA 0xffff0000 > + > +#define MT_TMAC_ICR0(_band) MT_BAND_ADDR(_band, 0x40a4) > +#define MT_IFS_EIFS GENMASK(8, 0) > +#define MT_IFS_RIFS GENMASK(14, 10) > +#define MT_IFS_SIFS GENMASK(22, 16) > +#define MT_IFS_SLOT GENMASK(30, 24) > + > +#define MT_TMAC_CTCR0(_band) MT_BAND_ADDR(_band, > 0x40f4) > +#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME 0x0000003f > +#define MT_TMAC_CTCR0_INS_DDLMT_EN (1U << 17) > +#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN (1U << 18) > + > +#define MT_TMAC_TRCR0(_band) MT_BAND_ADDR(_band, 0x409c) > +#define MT_TMAC_TFCR0(_band) MT_BAND_ADDR(_band, 0x41e0) > + > +#define MT_DMA_DCR0(_band) MT_BAND_ADDR(_band, 0x7000) > +#define MT_DMA_DCR0_MAX_RX_LEN_MASK 0x0000fff8 > +#define MT_DMA_DCR0_MAX_RX_LEN_SHIFT 3 > +#define MT_DMA_DCR0_RXD_G5_EN (1U << 23) > + > +/* MIB: band 0(0x24800), band 1(0xa4800) */ > +#define MT_MIB_SCR1(_band) MT_BAND_ADDR(_band, 0xd004) > +#define MT_MIB_TXDUR_EN 0x0100 > +#define MT_MIB_RXDUR_EN 0x0200 > + > +#define MT_MIB_SDR9(_band) MT_BAND_ADDR(_band, 0xd02c) > +#define MT_MIB_SDR9_BUSY_MASK 0x00ffffff > + > +#define MT_MIB_SDR36(_band) MT_BAND_ADDR(_band, 0xd054) > +#define MT_MIB_SDR36_TXTIME_MASK 0x00ffffff > +#define MT_MIB_SDR37(_band) MT_BAND_ADDR(_band, 0xd058) > +#define MT_MIB_SDR37_RXTIME_MASK 0x00ffffff > + > +#define MT_TX_AGG_CNT(_band, n) MT_BAND_ADDR(_band, 0xd7dc + > ((n) << 2)) > +#define MT_TX_AGG_CNT2(_band, n) MT_BAND_ADDR(_band, 0xd7ec + > ((n) << 2)) > + > +#define MT_WTBLON_TOP_BASE 0x820d4000 > +#define MT_WTBLON_TOP_WDUCR 0x820d4200 > +#define MT_WTBLON_TOP_WDUCR_GROUP 0x0007 > + > +#define MT_WTBL_UPDATE 0x820d4230 > +#define MT_WTBL_UPDATE_WLAN_IDX 0x000003ff > +#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR (1U << 12) > +#define MT_WTBL_UPDATE_BUSY (1U << 31) > + > +#define MT_WTBL_BASE 0x820d8000 > +#define MT_WTBL_LMAC_ID GENMASK(14, 8) > +#define MT_WTBL_LMAC_DW GENMASK(7, 2) > +#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \ > + FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \ > + FIELD_PREP(MT_WTBL_LMAC_DW, _dw)) > + > +/* RMAC: band 0 (0x21400), band 1 (0xa1400) */ > +#define MT_WF_RFCR(_base) MT_BAND_ADDR(_base, 0x5000) > +#define MT_WF_RFCR_DROP_STBC_MULTI 0x00000001 > +#define MT_WF_RFCR_DROP_FCSFAIL 0x00000002 > +#define MT_WF_RFCR_DROP_VERSION 0x00000008 > +#define MT_WF_RFCR_DROP_PROBEREQ 0x00000010 > +#define MT_WF_RFCR_DROP_MCAST 0x00000020 > +#define MT_WF_RFCR_DROP_BCAST 0x00000040 > +#define MT_WF_RFCR_DROP_MCAST_FILTERED 0x00000080 > +#define MT_WF_RFCR_DROP_A3_MAC 0x00000100 > +#define MT_WF_RFCR_DROP_A3_BSSID 0x00000200 > +#define MT_WF_RFCR_DROP_A2_BSSID 0x00000400 > +#define MT_WF_RFCR_DROP_OTHER_BEACON 0x00000800 > +#define MT_WF_RFCR_DROP_FRAME_REPORT 0x00001000 > +#define MT_WF_RFCR_DROP_CTL_RSV 0x00002000 > +#define MT_WF_RFCR_DROP_CTS 0x00004000 > +#define MT_WF_RFCR_DROP_RTS 0x00008000 > +#define MT_WF_RFCR_DROP_DUPLICATE 0x00010000 > +#define MT_WF_RFCR_DROP_OTHER_BSS 0x00020000 > +#define MT_WF_RFCR_DROP_OTHER_UC 0x00040000 > +#define MT_WF_RFCR_DROP_OTHER_TIM 0x00080000 > +#define MT_WF_RFCR_DROP_NDPA 0x00100000 > +#define MT_WF_RFCR_DROP_UNWANTED_CTL 0x00200000 > + > +#define MT_WF_RFCR1(_band) MT_BAND_ADDR(_band, 0x5004) > +#define MT_WF_RFCR1_DROP_ACK (1U << 4) > +#define MT_WF_RFCR1_DROP_BF_POLL (1U << 5) > +#define MT_WF_RFCR1_DROP_BA (1U << 6) > +#define MT_WF_RFCR1_DROP_CFEND (1U << 7) > +#define MT_WF_RFCR1_DROP_CFACK (1U << 8) > + > +#define MT_WF_RMAC_MIB_TIME0(_band) MT_BAND_ADDR(_band, 0x53c4) > +#define MT_WF_RMAC_MIB_RXTIME_CLR (1U << 31) > +#define MT_WF_RMAC_MIB_RXTIME_EN (1U << 30) > + > +#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_BAND_ADDR(_band, 0x53b8) > +#define MT_MIB_OBSSTIME_MASK 0x00ffffff > +#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_BAND_ADDR(_band, 0x5380) > + > +/* WFDMA0 */ > +#define MT_WFDMA0_BASE 0xd4000 > + > +#define MT_WFDMA0_RST 0xd4100 > +#define MT_WFDMA0_RST_LOGIC_RST (1U << 4) > +#define MT_WFDMA0_RST_DMASHDL_ALL_RST (1U << 5) > + > +#define MT_MCU_CMD 0xd41f0 > +#define MT_MCU_CMD_WAKE_RX_PCIE (1U << 0) > +#define MT_MCU_CMD_STOP_DMA_FW_RELOAD (1U << 1) > +#define MT_MCU_CMD_STOP_DMA (1U << 2) > +#define MT_MCU_CMD_RESET_DONE (1U << 3) > +#define MT_MCU_CMD_RECOVERY_DONE (1U << 4) > +#define MT_MCU_CMD_NORMAL_STATE (1U << 5) > +#define MT_MCU_CMD_ERROR_MASK 0x003e > + > +#define MT_MCU2HOST_SW_INT_ENA 0xd41f4 > + > +#define MT_WFDMA0_HOST_INT_STA 0xd4200 > +#define HOST_RX_DONE_INT_STS0 (1U << 0) /* Rx mcu */ > +#define HOST_RX_DONE_INT_STS2 (1U << 2) /* Rx data */ > +#define HOST_RX_DONE_INT_STS4 (1U << 22) /* Rx mcu after > fw downloaded */ > +#define HOST_TX_DONE_INT_STS16 (1U << 26) > +#define HOST_TX_DONE_INT_STS17 (1U << 27) /* MCU tx done*/ > + > +#define MT_WFDMA0_HOST_INT_ENA 0xd4204 > +#define HOST_RX_DONE_INT_ENA0 (1U << 0) > +#define HOST_RX_DONE_INT_ENA1 (1U << 1) > +#define HOST_RX_DONE_INT_ENA2 (1U << 2) > +#define HOST_RX_DONE_INT_ENA3 (1U << 3) > +#define HOST_TX_DONE_INT_ENA0 (1U << 4) > +#define HOST_TX_DONE_INT_ENA1 (1U << 5) > +#define HOST_TX_DONE_INT_ENA2 (1U << 6) > +#define HOST_TX_DONE_INT_ENA3 (1U << 7) > +#define HOST_TX_DONE_INT_ENA4 (1U << 8) > +#define HOST_TX_DONE_INT_ENA5 (1U << 9) > +#define HOST_TX_DONE_INT_ENA6 (1U << 10) > +#define HOST_TX_DONE_INT_ENA7 (1U << 11) > +#define HOST_TX_DONE_INT_ENA8 (1U << 12) > +#define HOST_TX_DONE_INT_ENA9 (1U << 13) > +#define HOST_TX_DONE_INT_ENA10 (1U << 14) > +#define HOST_TX_DONE_INT_ENA11 (1U << 15) > +#define HOST_TX_DONE_INT_ENA12 (1U << 16) > +#define HOST_TX_DONE_INT_ENA13 (1U << 17) > +#define HOST_TX_DONE_INT_ENA14 (1U << 18) > +#define HOST_RX_COHERENT_EN (1U << 20) > +#define HOST_TX_COHERENT_EN (1U << 21) > +#define HOST_RX_DONE_INT_ENA4 (1U << 22) > +#define HOST_RX_DONE_INT_ENA5 (1U << 23) > +#define HOST_TX_DONE_INT_ENA16 (1U << 26) > +#define HOST_TX_DONE_INT_ENA17 (1U << 27) > +#define MCU2HOST_SW_INT_ENA (1U << 29) > +#define HOST_TX_DONE_INT_ENA18 (1U << 30) > + > +#define MT_PCIE_MAC_BASE 0x10000 > +#define MT_PCIE_MAC_INT_ENABLE 0x10188 > + > +/* WFDMA interrupt */ > +#define MT_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA2 > +#define MT_INT_RX_DONE_WM HOST_RX_DONE_INT_ENA0 > +#define MT_INT_RX_DONE_WM2 HOST_RX_DONE_INT_ENA4 > +#define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_DATA | \ > + MT_INT_RX_DONE_WM | \ > + MT_INT_RX_DONE_WM2) > + > +#define MT_INT_TX_DONE_MCU_WM HOST_TX_DONE_INT_ENA17 > +#define MT_INT_TX_DONE_FWDL HOST_TX_DONE_INT_ENA16 > +#define MT_INT_TX_DONE_BAND0 HOST_TX_DONE_INT_ENA0 > +#define MT_INT_MCU_CMD MCU2HOST_SW_INT_ENA > +#define MT_INT_TX0_TO_TX14 0x7fff0 > + > +#define MT_INT_TX_DONE_MCU (MT_INT_TX_DONE_MCU_WM | > \ > + MT_INT_TX_DONE_FWDL) > + > +#define MT_INT_TX_DONE_ALL (MT_INT_TX_DONE_MCU | > \ > + MT_INT_TX0_TO_TX14) > + > +#define MT_WFDMA0_GLO_CFG 0xd4208 > +#define MT_WFDMA0_GLO_CFG_TX_DMA_EN (1U << 0) > +#define MT_WFDMA0_GLO_CFG_TX_DMA_BUSY (1U << 1) > +#define MT_WFDMA0_GLO_CFG_RX_DMA_EN (1U << 2) > +#define MT_WFDMA0_GLO_CFG_RX_DMA_BUSY (1U << 3) > +#define MT_WFDMA0_GLO_CFG_TX_WB_DDONE (1U << 6) > +#define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN (1U << 12) > +#define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN (1U << 15) > +#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 (1U << 21) > +#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO (1U << 27) > +#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO (1U << 28) > +#define MT_WFDMA0_GLO_CFG_CLK_GAT_DIS (1U << 30) > + > +#define MT_WFDMA0_RST_DTX_PTR 0xd420c > +#define MT_WFDMA0_GLO_CFG_EXT0 0xd42b0 > +#define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE (1U << 6) > +#define MT_WFDMA0_PRI_DLY_INT_CFG0 0xd42f0 > + > +#define MT_WFDMA0_TX_RING0_EXT_CTRL 0xd4600 > +#define MT_WFDMA0_TX_RING1_EXT_CTRL 0xd4604 > +#define MT_WFDMA0_TX_RING2_EXT_CTRL 0xd4608 > +#define MT_WFDMA0_TX_RING3_EXT_CTRL 0xd460c > +#define MT_WFDMA0_TX_RING4_EXT_CTRL 0xd4610 > +#define MT_WFDMA0_TX_RING5_EXT_CTRL 0xd4614 > +#define MT_WFDMA0_TX_RING6_EXT_CTRL 0xd4618 > +#define MT_WFDMA0_TX_RING16_EXT_CTRL 0xd4640 > +#define MT_WFDMA0_TX_RING17_EXT_CTRL 0xd4644 > + > +#define MT_WFDMA0_RX_RING0_EXT_CTRL 0xd4680 > +#define MT_WFDMA0_RX_RING1_EXT_CTRL 0xd4684 > +#define MT_WFDMA0_RX_RING2_EXT_CTRL 0xd4688 > +#define MT_WFDMA0_RX_RING3_EXT_CTRL 0xd468c > +#define MT_WFDMA0_RX_RING4_EXT_CTRL 0xd4690 > +#define MT_WFDMA0_RX_RING5_EXT_CTRL 0xd4694 > + > +#define MT_TX_DATA_RING_BASE 0xd4300 > +#define MT_TX_FWDL_RING_BASE 0xd4400 > +#define MT_TX_MCU_RING_BASE 0xd4410 > +#define MT_RX_DATA_RING_BASE 0xd4520 > +#define MT_RX_MCU_RING_BASE 0xd4540 > +#define MT_RX_FWDL_RING_BASE 0xd4500 > + > +#define MT_PCIE_MAC_BASE 0x10000 > +#define MT_PCIE_MAC_INT_ENABLE 0x10188 > + > +#define MT_INFRA_CFG_BASE 0xfe000 > +#define MT_HIF_REMAP_L1 0xfe24c > +#define MT_HIF_REMAP_L1_MASK 0x0000ffff > +#define MT_HIF_REMAP_L1_GET_OFFSET(x) ((x) & 0xffff) > +#define MT_HIF_REMAP_L1_GET_BASE(x) ((x >> 16) & 0xffff) > +#define MT_HIF_REMAP_BASE_L1 0x40000 > + > +#define MT_SWDEF_BASE 0x41f200 > +#define MT_SWDEF_MODE 0x41f23c > +#define MT_SWDEF_NORMAL_MODE 0 > +#define MT_SWDEF_ICAP_MODE 1 > +#define MT_SWDEF_SPECTRUM_MODE 2 > + > +#define MT_DMASHDL_SW_CONTROL 0xd6004 > +#define MT_DMASHDL_DMASHDL_BYPASS (1U << 28) > +#define MT_DMASHDL_OPTIONAL 0xd6008 > +#define MT_DMASHDL_PAGE 0xd600c > +#define MT_DMASHDL_REFILL 0xd6010 > +#define MT_DMASHDL_PKT_MAX_SIZE 0xd601c > +#define MT_DMASHDL_PKT_MAX_SIZE_PLE 0x00000fff > +#define MT_DMASHDL_PKT_MAX_SIZE_PSE 0x0fff0000 > + > +#define MT_CONN_ON_MISC 0x7c0600f0 > +#define MT_TOP_MISC2_FW_N9_RDY 0x3 > + > +#define MT_WFSYS_SW_RST_B 0x18000140 > +#define WFSYS_SW_RST_B (1U << 0) > +#define WFSYS_SW_INIT_DONE (1U << 4) > + > +#define MT_TOP_BASE 0x18060000 > +#define MT_TOP_LPCR_HOST_BAND0 0x18060010 > +#define MT_TOP_LPCR_HOST_FW_OWN 0x0001 > +#define MT_TOP_LPCR_HOST_DRV_OWN 0x0002 > + > +#define MT_MCU_WPDMA0_BASE 0x54000000 > +#define MT_WFDMA_DUMMY_CR 0x54000120 > +#define MT_WFDMA_NEED_REINIT (1U << 1) > + > +#define MT_HW_CHIPID 0x70010200 > +#define MT_HW_REV 0x70010204 > + > +#define MT_DMA_DESC_BASE 0 > +#define MT_DMA_RING_SIZE 4 > +#define MT_DMA_CPU_IDX 8 > +#define MT_DMA_DMA_IDX 12 > + > +#define MT_DMA_CTL_SD_LEN_MASK 0x00003fff > +#define MT_DMA_CTL_SD_LEN0_SHIFT 16 > +#define MT_DMA_CTL_LAST_SEC1 (1U << 14) > +#define MT_DMA_CTL_BURST (1U << 15) > +#define MT_DMA_CTL_LAST_SEC0 (1U << 30) > +#define MT_DMA_CTL_DMA_DONE (1U << 31) > +#define MT_DMA_CTL_SD_LEN1(x) ((x) & MT_DMA_CTL_SD_LEN_MASK) > +#define MT_DMA_CTL_SD_LEN0(x) \ > + (((x) & MT_DMA_CTL_SD_LEN_MASK) << MT_DMA_CTL_SD_LEN0_SHIFT) > +#define MT_DMA_CTL_SD_GET_LEN1(c) ((c) & MT_DMA_CTL_SD_LEN_MASK) > +#define MT_DNA_CTL_SD_GET_LEN0(c) \ > + (((c) >> MT_DMA_CTL_SD_LEN0_SHIFT) & MT_DMA_CTL_SD_LEN_MASK) > + > +#define MT7921_MCU_INIT_RETRY_COUNT 10 > + > +/* it seems most of the txqueues are unused, actually all but 0 */ > +enum mt76_txq_id { > + MT_TXQ_VO, > + MT_TXQ_VI, > + MT_TXQ_BE, > + MT_TXQ_BK, > + MT_TXQ_PSD, > + MT_TXQ_BEACON, > + MT_TXQ_CAB, > + __MT_TXQ_MAX > +}; > + > +enum mt76_mcuq_id { > + MT_MCUQ_WM, > + MT_MCUQ_WA, > + MT_MCUQ_FWDL, > + __MT_MCUQ_MAX > +}; > + > +enum mt76_rxq_id { > + MT_RXQ_MAIN, > + MT_RXQ_MCU, > + MT_RXQ_MCU_WA, > + MT_RXQ_EXT, > + MT_RXQ_EXT_WA, > + __MT_RXQ_MAX > +}; > + > +#define MT7921_MAX_INTERFACES 4 > +#define MT7921_MAX_WMM_SETS 4 > +#define MT7921_WTBL_SIZE 20 > +#define MT7921_WTBL_RESERVED (MT7921_WTBL_SIZE - 1) > +#define MT7921_WTBL_STA (MT7921_WTBL_RESERVED - > MT7921_MAX_INTERFACES) > + > +#define MT_RX_BUF_SIZE 2048 > +#define MT_MAX_SCATTER 32 > +#define MT_MAX_SIZE MT_DMA_CTL_SD_LEN_MASK > + > +#define MWX_WCID_MAX 288 > + > +struct mt76_desc { > + volatile uint32_t buf0; > + volatile uint32_t ctrl; > + volatile uint32_t buf1; > + volatile uint32_t info; > +} __packed __aligned(4); > + > +#define MCU_Q_QUERY 0 > +#define MCU_Q_SET 1 > +#define MCU_Q_RESERVED 2 > +#define MCU_Q_NA 3 > + > +#define CMD_S2D_IDX_H2N 0 > +#define CMD_S2D_IDX_C2N 1 > +#define CMD_S2D_IDX_H2C 2 > +#define CMD_S2D_IDX_H2N_AND_H2C 3 > + > +#define MCU_CMD_ACK 0x01 > +#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_FIELD_ID_MASK 0x000000ff > +#define MCU_CMD_FIELD_EXT_ID_MASK 0x0000ff00 > + > +#define MCU_CMD_FIELD_QUERY (1U << 16) > +#define MCU_CMD_FIELD_UNI (1U << 17) > +#define MCU_CMD_FIELD_CE (1U << 18) > +#define MCU_CMD_FIELD_WA (1U << 19) > + > +#define MCU_CMD_TARGET_ADDRESS_LEN_REQ 0x00000001 > +#define MCU_CMD_FW_START_REQ 0x00000002 > +#define MCU_CMD_INIT_ACCESS_REG 0x00000003 > +#define MCU_CMD_NIC_POWER_CTRL 0x00000004 > +#define MCU_CMD_PATCH_START_REQ 0x00000005 > +#define MCU_CMD_PATCH_FINISH_REQ 0x00000007 > +#define MCU_CMD_PATCH_SEM_CONTROL 0x00000010 > +#define MCU_CMD_WA_PARAM 0x000000c4 > +#define MCU_CMD_EXT_CID 0x000000ed > +#define MCU_CMD_FW_SCATTER 0x000000ee > +#define MCU_CMD_RESTART_DL_REQ 0x000000ef > + > +/* MCU_EXT_CMD use MCU_CMD_EXT_CID as FIELD_ID plus FIELD_EXT_ID */ > +#define MCU_EXT_CMD_EFUSE_ACCESS 0x000001ed > +#define MCU_EXT_CMD_RF_REG_ACCESS 0x000002ed > +#define MCU_EXT_CMD_RF_TEST 0x000004ed > +#define MCU_EXT_CMD_PM_STATE_CTRL 0x000007ed > +#define MCU_EXT_CMD_CHANNEL_SWITCH 0x000008ed > +#define MCU_EXT_CMD_SET_TX_POWER_CTRL 0x000011ed > +#define MCU_EXT_CMD_FW_LOG_2_HOST 0x000013ed > +#define MCU_EXT_CMD_TXBF_ACTION 0x00001eed > +#define MCU_EXT_CMD_EFUSE_BUFFER_MODE 0x000021ed > +#define MCU_EXT_CMD_THERMAL_PROT 0x000023ed > +#define MCU_EXT_CMD_STA_REC_UPDATE 0x000025ed > +#define MCU_EXT_CMD_BSS_INFO_UPDATE 0x000026ed > +#define MCU_EXT_CMD_EDCA_UPDATE 0x000027ed > +#define MCU_EXT_CMD_DEV_INFO_UPDATE 0x00002Aed > +#define MCU_EXT_CMD_THERMAL_CTRL 0x00002ced > +#define MCU_EXT_CMD_WTBL_UPDATE 0x000032ed > +#define MCU_EXT_CMD_SET_DRR_CTRL 0x000036ed > +#define MCU_EXT_CMD_SET_RDD_CTRL 0x00003aed > +#define MCU_EXT_CMD_ATE_CTRL 0x00003ded > +#define MCU_EXT_CMD_PROTECT_CTRL 0x00003eed > +#define MCU_EXT_CMD_DBDC_CTRL 0x000045ed > +#define MCU_EXT_CMD_MAC_INIT_CTRL 0x000046ed > +#define MCU_EXT_CMD_RX_HDR_TRANS 0x000047ed > +#define MCU_EXT_CMD_MUAR_UPDATE 0x000048ed > +#define MCU_EXT_CMD_BCN_OFFLOAD 0x000049ed > +#define MCU_EXT_CMD_RX_AIRTIME_CTRL 0x00004aed > +#define MCU_EXT_CMD_SET_RX_PATH 0x00004eed > +#define MCU_EXT_CMD_EFUSE_FREE_BLOCK 0x00004fed > +#define MCU_EXT_CMD_TX_POWER_FEATURE_CTRL 0x000058ed > +#define MCU_EXT_CMD_RXDCOC_CAL 0x000059ed > +#define MCU_EXT_CMD_GET_MIB_INFO 0x00005aed > +#define MCU_EXT_CMD_TXDPD_CAL 0x000060ed > +#define MCU_EXT_CMD_CAL_CACHE 0x000067ed > +#define MCU_EXT_CMD_SET_RADAR_TH 0x00007ced > +#define MCU_EXT_CMD_SET_RDD_PATTERN 0x00007ded > +#define MCU_EXT_CMD_MWDS_SUPPORT 0x000080ed > +#define MCU_EXT_CMD_SET_SER_TRIGGER 0x000081ed > +#define MCU_EXT_CMD_SCS_CTRL 0x000082ed > +#define MCU_EXT_CMD_TWT_AGRT_UPDATE 0x000094ed > +#define MCU_EXT_CMD_FW_DBG_CTRL 0x000095ed > +#define MCU_EXT_CMD_SET_RDD_TH 0x00009ded > +#define MCU_EXT_CMD_MURU_CTRL 0x00009fed > +#define MCU_EXT_CMD_SET_SPR 0x0000a8ed > +#define MCU_EXT_CMD_GROUP_PRE_CAL_INFO 0x0000abed > +#define MCU_EXT_CMD_DPD_PRE_CAL_INFO 0x0000aced > +#define MCU_EXT_CMD_PHY_STAT_INFO 0x0000aded > + > +#define MCU_GET_EXT_CMD(x) (((x) & > MCU_CMD_FIELD_EXT_ID_MASK) >> 8) > + > +#define MCU_UNI_CMD_DEV_INFO_UPDATE 0x00020001 > +#define MCU_UNI_CMD_BSS_INFO_UPDATE 0x00020002 > +#define MCU_UNI_CMD_STA_REC_UPDATE 0x00020003 > +#define MCU_UNI_CMD_SUSPEND 0x00020005 > +#define MCU_UNI_CMD_OFFLOAD 0x00020006 > +#define MCU_UNI_CMD_HIF_CTRL 0x00020007 > +#define MCU_UNI_CMD_SNIFFER 0x00020024 > + > +#define UNI_BSS_INFO_BASIC 0 > +#define UNI_BSS_INFO_RLM 2 > +#define UNI_BSS_INFO_BSS_COLOR 4 > +#define UNI_BSS_INFO_HE_BASIC 5 > +#define UNI_BSS_INFO_BCN_CONTENT 7 > +#define UNI_BSS_INFO_QBSS 15 > +#define UNI_BSS_INFO_UAPSD 19 > +#define UNI_BSS_INFO_PS 21 > +#define UNI_BSS_INFO_BCNFT 22 > + > +/* offload mcu commands */ > +#define MCU_CE_CMD_TEST_CTRL 0x00040001 > +#define MCU_CE_CMD_START_HW_SCAN 0x00040003 > +#define MCU_CE_CMD_SET_PS_PROFILE 0x00040005 > +#define MCU_CE_CMD_SET_CHAN_DOMAIN 0x0004000f > +#define MCU_CE_CMD_SET_BSS_CONNECTED 0x00040016 > +#define MCU_CE_CMD_SET_BSS_ABORT 0x00040017 > +#define MCU_CE_CMD_CANCEL_HW_SCAN 0x0004001b > +#define MCU_CE_CMD_SET_ROC 0x0004001d > +#define MCU_CE_CMD_SET_P2P_OPPPS 0x00040033 > +#define MCU_CE_CMD_SET_RATE_TX_POWER 0x0004005d > +#define MCU_CE_CMD_SCHED_SCAN_ENABLE 0x00040061 > +#define MCU_CE_CMD_SCHED_SCAN_REQ 0x00040062 > +#define MCU_CE_CMD_GET_NIC_CAPAB 0x0004008a > +#define MCU_CE_CMD_SET_MU_EDCA_PARMS 0x000400b0 > +#define MCU_CE_CMD_REG_WRITE 0x000400c0 > +#define MCU_CE_CMD_REG_READ 0x000400c0 > +#define MCU_CE_CMD_CHIP_CONFIG 0x000400ca > +#define MCU_CE_CMD_FWLOG_2_HOST 0x000400c5 > +#define MCU_CE_CMD_GET_WTBL 0x000400cd > +#define MCU_CE_CMD_GET_TXPWR 0x000400d0 > +#define MCU_CE_QUERY_REG_READ (MCU_CE_CMD_REG_READ | > MCU_CMD_FIELD_QUERY) > + > +/* event commands */ > +#define MCU_EVENT_TARGET_ADDRESS_LEN 0x01 > +#define MCU_EVENT_FW_START 0x01 > +#define MCU_EVENT_GENERIC 0x01 > +#define MCU_EVENT_ACCESS_REG 0x02 > +#define MCU_EVENT_MT_PATCH_SEM 0x04 > +#define MCU_EVENT_REG_ACCESS 0x05 > +#define MCU_EVENT_LP_INFO 0x07 > +#define MCU_EVENT_SCAN_DONE 0x0d > +#define MCU_EVENT_TX_DONE 0x0f > +#define MCU_EVENT_ROC 0x10 > +#define MCU_EVENT_BSS_ABSENCE 0x11 > +#define MCU_EVENT_BSS_BEACON_LOSS 0x13 > +#define MCU_EVENT_CH_PRIVILEGE 0x18 > +#define MCU_EVENT_SCHED_SCAN_DONE 0x23 > +#define MCU_EVENT_DBG_MSG 0x27 > +#define MCU_EVENT_TXPWR 0xd0 > +#define MCU_EVENT_EXT 0xed > +#define MCU_EVENT_RESTART_DL 0xef > +#define MCU_EVENT_COREDUMP 0xf0 > + > +/* extended event commands */ > +#define MCU_EXT_EVENT_PS_SYNC 0x5 > +#define MCU_EXT_EVENT_FW_LOG_2_HOST 0x13 > +#define MCU_EXT_EVENT_THERMAL_PROTECT 0x22 > +#define MCU_EXT_EVENT_ASSERT_DUMP 0x23 > +#define MCU_EXT_EVENT_RDD_REPORT 0x3a > +#define MCU_EXT_EVENT_CSA_NOTIFY 0x4f > +#define MCU_EXT_EVENT_BCC_NOTIFY 0x75 > +#define MCU_EXT_EVENT_RATE_REPORT 0x87 > +#define MCU_EXT_EVENT_MURU_CTRL 0x9f > + > +#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << > 10)) > +#define MCU_PKT_ID 0xa0 > + > +/* values for MT_TXD0_PKT_FMT */ > +#define MT_TX_TYPE_CT (0 << 23) > +#define MT_TX_TYPE_SF (1 << 23) > +#define MT_TX_TYPE_CMD (2 << 23) > +#define MT_TX_TYPE_FW (3 << 23) > + > +/* values for port idx */ > +#define MT_TX_PORT_IDX_LMAC 0 > +#define MT_TX_PORT_IDX_MCU 1 > + > +/* valus for EEPROM command */ > +#define EE_MODE_EFUSE 0 > +#define EE_MODE_BUFFER 1 > + > +#define EE_FORMAT_BIN 0 > +#define EE_FORMAT_WHOLE 1 > +#define EE_FORMAT_MULTIPLE 2 > + > + > +/* values for MT_TXD0_Q_IDX */ > +#define MT_TX_MCU_PORT_RX_Q0 0x20 > +#define MT_TX_MCU_PORT_RX_Q1 0x21 > +#define MT_TX_MCU_PORT_RX_Q2 0x22 > +#define MT_TX_MCU_PORT_RX_Q3 0x23 > +#define MT_TX_MCU_PORT_RX_FWDL 0x3e > + > +#define MT_TXD0_Q_IDX_MASK 0xfe000000 > +#define MT_TXD0_Q_IDX(x) (((x) << 25) & > MT_TXD0_Q_IDX_MASK) > +#define MT_TXD0_PKT_FMT 0x01800000 > +#define MT_TXD0_ETH_TYPE_OFFSET 0x007f0000 > +#define MT_TXD0_TX_BYTES_MASK 0x0000ffff > + > +/* values for MT_TXD1_HDR_FORMAT */ > +#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) > + > +#define MT_TXD1_LONG_FORMAT (1U << 31) > +#define MT_TXD1_TGID (1U << 30) > +#define MT_TXD1_OWN_MAC GENMASK(29, 24) > +#define MT_TXD1_AMSDU (1U << 23) > +#define MT_TXD1_TID GENMASK(22, 20) > +#define MT_TXD1_HDR_PAD GENMASK(19, 18) > +#define MT_TXD1_HDR_FORMAT 0x00030000 > +#define MT_TXD1_HDR_INFO GENMASK(15, 11) > +#define MT_TXD1_ETH_802_3 (1U << 15) > +#define MT_TXD1_VTA (1U << 10) > +#define MT_TXD1_WLAN_IDX_MASK GENMASK(9, 0) > + > +#define MT_RXD0_LENGTH_MASK 0x0000ffff > +#define MT_RXD0_PKT_FLAG_MASK 0x000f0000 > +#define MT_RXD0_PKT_FLAG_SHIFT 16 > +#define MT_RXD0_NORMAL_ETH_TYPE_OFS 0x007f0000 > +#define MT_RXD0_NORMAL_IP_SUM (1U << 23) > +#define MT_RXD0_NORMAL_UDP_TCP_SUM (1U << 24) > +#define MT_RXD0_PKT_TYPE_MASK 0xf8000000 > +#define MT_RXD0_PKT_TYPE_SHIFT 27 > +#define MT_RXD0_PKT_TYPE_GET(x) \ > + (((x) & MT_RXD0_PKT_TYPE_MASK) >> MT_RXD0_PKT_TYPE_SHIFT) > + > +/* RXD DW1 */ > +#define MT_RXD1_NORMAL_WLAN_IDX_MASK 0x000003ff > +#define MT_RXD1_NORMAL_GROUP_1 (1U << 11) > +#define MT_RXD1_NORMAL_GROUP_2 (1U << 12) > +#define MT_RXD1_NORMAL_GROUP_3 (1U << 13) > +#define MT_RXD1_NORMAL_GROUP_4 (1U << 14) > +#define MT_RXD1_NORMAL_GROUP_5 (1U << 15) > +#define MT_RXD1_NORMAL_SEC_MODE_MASK 0x001f0000 > +#define MT_RXD1_NORMAL_SEC_MODE_SHIFT 16 > +#define MT_RXD1_NORMAL_KEY_ID_MASK 0x00600000 > +#define MT_RXD1_NORMAL_CM (1U << 23) > +#define MT_RXD1_NORMAL_CLM (1U << 24) > +#define MT_RXD1_NORMAL_ICV_ERR (1U << 25) > +#define MT_RXD1_NORMAL_TKIP_MIC_ERR (1U << 26) > +#define MT_RXD1_NORMAL_FCS_ERR (1U << 27) > +#define MT_RXD1_NORMAL_BAND_IDX (1U << 28) > +#define MT_RXD1_NORMAL_SPP_EN (1U << 29) > +#define MT_RXD1_NORMAL_ADD_OM (1U << 30) > +#define MT_RXD1_NORMAL_SEC_DONE (1U << 31) > + > +/* RXD DW2 */ > +#define MT_RXD2_NORMAL_BSSID 0x0000003f > +#define MT_RXD2_NORMAL_CO_ANT (1U << 6) > +#define MT_RXD2_NORMAL_BF_CQI (1U << 7) > +#define MT_RXD2_NORMAL_MAC_HDR_LEN 0x00001f00 > +#define MT_RXD2_NORMAL_HDR_TRANS (1U << 13) > +#define MT_RXD2_NORMAL_HDR_OFFSET_MASK 0x0000c000 > +#define MT_RXD2_NORMAL_HDR_OFFSET_SHIFT 14 > +#define MT_RXD2_NORMAL_TID 0x000f0000 > +#define MT_RXD2_NORMAL_MU_BAR (1U << 21) > +#define MT_RXD2_NORMAL_SW_BIT (1U << 22) > +#define MT_RXD2_NORMAL_AMSDU_ERR (1U << 23) > +#define MT_RXD2_NORMAL_MAX_LEN_ERROR (1U << 24) > +#define MT_RXD2_NORMAL_HDR_TRANS_ERROR (1U << 25) > +#define MT_RXD2_NORMAL_INT_FRAME (1U << 26) > +#define MT_RXD2_NORMAL_FRAG (1U << 27) > +#define MT_RXD2_NORMAL_NULL_FRAME (1U << 28) > +#define MT_RXD2_NORMAL_NDATA (1U << 29) > +#define MT_RXD2_NORMAL_NON_AMPDU (1U << 30) > +#define MT_RXD2_NORMAL_BF_REPORT (1U << 31) > + > +/* RXD DW3 */ > +#define MT_RXD3_NORMAL_RXV_SEQ_MASK 0x000000ff > +#define MT_RXD3_NORMAL_CH_FREQ_MASK 0x0000ff00 > +#define MT_RXD3_NORMAL_CH_FREQ_SHIFT 8 > +#define MT_RXD3_NORMAL_ADDR_TYPE_MASK 0x00030000 > +#define MT_RXD3_NORMAL_U2M (1U << 16) > +#define MT_RXD3_NORMAL_HTC_VLD (1U << 0) > +#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS (1U << 19) > +#define MT_RXD3_NORMAL_BEACON_MC (1U << 20) > +#define MT_RXD3_NORMAL_BEACON_UC (1U << 21) > +#define MT_RXD3_NORMAL_AMSDU (1U << 22) > +#define MT_RXD3_NORMAL_MESH (1U << 23) > +#define MT_RXD3_NORMAL_MHCP (1U << 24) > +#define MT_RXD3_NORMAL_NO_INFO_WB (1U << 25) > +#define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS (1U << 26) > +#define MT_RXD3_NORMAL_POWER_SAVE_STAT (1U << 27) > +#define MT_RXD3_NORMAL_MORE (1U << 28) > +#define MT_RXD3_NORMAL_UNWANT (1U << 29) > +#define MT_RXD3_NORMAL_RX_DROP (1U << 30) > +#define MT_RXD3_NORMAL_VLAN2ETH (1U << 31) > + > +/* RXD DW4 */ > +#define MT_RXD4_NORMAL_PAYLOAD_FORMAT 0x00000003 > +#define MT_RXD4_FIRST_AMSDU_FRAME 0x3 > +#define MT_RXD4_MID_AMSDU_FRAME 0x2 > +#define MT_RXD4_LAST_AMSDU_FRAME 0x1 > +#define MT_RXD4_NORMAL_PATTERN_DROP (1U << 9) > +#define MT_RXD4_NORMAL_CLS (1U << 10) > +#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) > +#define MT_RXD4_NORMAL_MAGIC_PKT (1U << 13) > +#define MT_RXD4_NORMAL_WOL GENMASK(18, 14) > +#define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19) > +#define MT_RXD3_NORMAL_PF_MODE (1U << 99) > +#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) > + > +#define PKT_TYPE_TXS 0 > +#define PKT_TYPE_TXRXV 1 > +#define PKT_TYPE_NORMAL 2 > +#define PKT_TYPE_RX_DUP_RFB 3 > +#define PKT_TYPE_RX_TMR 4 > +#define PKT_TYPE_RETRIEVE 5 > +#define PKT_TYPE_TXRX_NOTIFY 6 > +#define PKT_TYPE_RX_EVENT 7 > +#define PKT_TYPE_NORMAL_MCU 8 > + > +struct mt7921_mcu_txd { > + uint32_t txd[8]; > + > + uint16_t len; > + uint16_t pq_id; > + > + uint8_t cid; > + uint8_t pkt_type; > + uint8_t set_query; /* FW don't care */ > + uint8_t seq; > + > + uint8_t uc_d2b0_rev; > + uint8_t ext_cid; > + uint8_t s2d_index; > + uint8_t ext_cid_ack; > + > + uint32_t reserved[5]; > +} __packed __aligned(4); > + > +/** > + * struct mt7921_uni_txd - mcu command descriptor for firmware v3 > + * @txd: hardware descriptor > + * @len: total length not including txd > + * @cid: command identifier > + * @pkt_type: must be 0xa0 (cmd packet by long format) > + * @frag_n: fragment number > + * @seq: sequence number > + * @checksum: 0 mean there is no checksum > + * @s2d_index: index for command source and destination > + * Definition | value | note > + * CMD_S2D_IDX_H2N | 0x00 | command from HOST to WM > + * CMD_S2D_IDX_C2N | 0x01 | command from WA to WM > + * CMD_S2D_IDX_H2C | 0x02 | command from HOST to WA > + * CMD_S2D_IDX_H2N_AND_H2C | 0x03 | command from HOST to WA and WM > + * > + * @option: command option > + * BIT[0]: UNI_CMD_OPT_BIT_ACK > + * set to 1 to request a fw reply > + * if UNI_CMD_OPT_BIT_0_ACK is set and UNI_CMD_OPT_BIT_2_SET_QUERY > + * is set, mcu firmware will send response event EID = 0x01 > + * (UNI_EVENT_ID_CMD_RESULT) to the host. > + * BIT[1]: UNI_CMD_OPT_BIT_UNI_CMD > + * 0: original command > + * 1: unified command > + * BIT[2]: UNI_CMD_OPT_BIT_SET_QUERY > + * 0: QUERY command > + * 1: SET command > + */ > +struct mt7921_uni_txd { > + uint32_t txd[8]; > + > + /* DW1 */ > + uint16_t len; > + uint16_t cid; > + > + /* DW2 */ > + uint8_t reserved; > + uint8_t pkt_type; > + uint8_t frag_n; > + uint8_t seq; > + > + /* DW3 */ > + uint16_t checksum; > + uint8_t s2d_index; > + uint8_t option; > + > + /* DW4 */ > + uint8_t reserved2[4]; > +} __packed __aligned(4); > + > + > +struct mt7921_mcu_rxd { > + uint32_t rxd[6]; > + uint16_t len; /* includes hdr but without rxd[6] */ > + uint16_t pkt_type_id; > + uint8_t eid; > + uint8_t seq; > + uint16_t pad0; > + uint8_t ext_eid; > + uint8_t pad1[2]; > + uint8_t s2d_index; > +} __packed; > + > +struct mt7921_mcu_uni_event { > + uint8_t cid; > + uint8_t pad[3]; > + uint32_t status; /* 0: success, others: fail */ > +} __packed; > + > +struct mt7921_mcu_reg_event { > + uint32_t reg; > + uint32_t val; > +} __packed; > + > +struct mt76_connac_config { > + uint16_t id; > + uint8_t type; > + uint8_t resp_type; > + uint16_t data_size; > + uint16_t resv; > + uint8_t data[320]; > +}; > + > +struct mt76_connac_bss_basic_tlv { > + uint16_t tag; > + uint16_t len; > + uint8_t active; > + uint8_t omac_idx; > + uint8_t hw_bss_idx; > + uint8_t band_idx; > + uint32_t conn_type; > + uint8_t conn_state; > + uint8_t wmm_idx; > + uint8_t bssid[ETHER_ADDR_LEN]; > + uint16_t bmc_tx_wlan_idx; > + uint16_t bcn_interval; > + uint8_t dtim_period; > + uint8_t phymode; /* bit(0): A > + * bit(1): B > + * bit(2): G > + * bit(3): GN > + * bit(4): AN > + * bit(5): AC > + * bit(6): AX2 > + * bit(7): AX5 > + * bit(8): AX6 > + */ > + uint16_t sta_idx; > + uint16_t nonht_basic_phy; > + uint8_t phymode_ext; /* bit(0) AX_6G */ > + uint8_t pad[1]; > +} __packed; > + > +struct mt76_connac_mcu_scan_ssid { > + uint32_t ssid_len; > + uint8_t ssid[IEEE80211_NWID_LEN]; > +} __packed; > + > +struct mt76_connac_mcu_scan_channel { > + uint8_t band; /* 1: 2.4GHz > + * 2: 5.0GHz > + * Others: Reserved > + */ > + uint8_t channel_num; > +} __packed; > + > +struct mt76_connac_mcu_scan_match { > + uint32_t rssi_th; > + uint8_t ssid[IEEE80211_NWID_LEN]; > + uint8_t ssid_len; > + uint8_t rsv[3]; > +} __packed; > + > +#define SCAN_FUNC_RANDOM_MAC 0x1 > +#define SCAN_FUNC_SPLIT_SCAN 0x20 > +#define MT76_HW_SCAN_IE_LEN 600 > + > +struct mt76_connac_hw_scan_req { > + uint8_t seq_num; > + uint8_t bss_idx; > + uint8_t scan_type; /* 0: PASSIVE SCAN > + * 1: ACTIVE SCAN > + */ > + uint8_t ssid_type; /* 0x1 wildcard SSID > + * 0x2 P2P wildcard SSID > + * 0x4 specified SSID + wildcard SSID > + * 0x4 + ssid_type_ext 0x1 > + * specified SSID only > + */ > + uint8_t ssids_num; > + uint8_t probe_req_num; /* Number of probe request per SSID */ > + uint8_t scan_func; /* 0x1 Enable random MAC scan > + * 0x2 Disable DBDC scan type 1~3. > + * 0x4 Use DBDC scan type 3 > + * (dedicated one RF to scan). > + */ > + uint8_t version; /* 0: Not support fields after ies. > + * 1: Support fields after ies. > + */ > + struct mt76_connac_mcu_scan_ssid ssids[4]; > + uint16_t probe_delay_time; > + uint16_t channel_dwell_time; /* channel Dwell interval */ > + uint16_t timeout_value; > + uint8_t channel_type; /* 0: Full channels > + * 1: Only 2.4GHz channels > + * 2: Only 5GHz channels > + * 3: P2P social channels only > + * (channel #1, #6 and #11) > + * 4: Specified channels > + * Others: Reserved > + */ > + uint8_t channels_num; /* valid when channel_type is 4 */ > + /* valid when channels_num is set */ > + struct mt76_connac_mcu_scan_channel channels[32]; > + uint16_t ies_len; > + uint8_t ies[MT76_HW_SCAN_IE_LEN]; > + /* following fields are valid if version > 0 */ > + uint8_t ext_channels_num; > + uint8_t ext_ssids_num; > + uint16_t channel_min_dwell_time; > + struct mt76_connac_mcu_scan_channel ext_channels[32]; > + struct mt76_connac_mcu_scan_ssid ext_ssids[6]; > + uint8_t bssid[ETHER_ADDR_LEN]; > + /* valid when BIT(1) in scan_func is set. */ > + uint8_t random_mac[ETHER_ADDR_LEN]; > + uint8_t pad[63]; > + uint8_t ssid_type_ext; > +} __packed; > + > +#define MT76_HW_SCAN_DONE_MAX_CHANNEL_NUM 64 > + > +struct mt76_connac_hw_scan_done { > + uint8_t seq_num; > + uint8_t sparse_channel_num; > + struct mt76_connac_mcu_scan_channel sparse_channel; > + uint8_t complete_channel_num; > + uint8_t current_state; > + uint8_t version; > + uint8_t pad; > + uint32_t beacon_scan_num; > + uint8_t pno_enabled; > + uint8_t pad2[3]; > + uint8_t sparse_channel_valid_num; > + uint8_t pad3[3]; > + uint8_t channel_num[MT76_HW_SCAN_DONE_MAX_CHANNEL_NUM]; > + /* idle format for channel_idle_time > + * 0: first bytes: idle time(ms) 2nd byte: dwell time(ms) > + * 1: first bytes: idle time(8ms) 2nd byte: dwell time(8ms) > + * 2: dwell time (16us) > + */ > + uint16_t channel_idle_time[MT76_HW_SCAN_DONE_MAX_CHANNEL_NUM]; > + /* beacon and probe response count */ > + uint8_t beacon_probe_num[MT76_HW_SCAN_DONE_MAX_CHANNEL_NUM]; > + uint8_t mdrdy_count[MT76_HW_SCAN_DONE_MAX_CHANNEL_NUM]; > + uint32_t beacon_2g_num; > + uint32_t beacon_5g_num; > +} __packed; > + > +struct mt7921_patch_hdr { > + char build_date[16]; > + char platform[4]; > + uint32_t hw_sw_ver; > + uint32_t patch_ver; > + uint16_t checksum; > + uint16_t reserved; > + struct { > + uint32_t patch_ver; > + uint32_t subsys; > + uint32_t feature; > + uint32_t n_region; > + uint32_t crc; > + uint32_t reserved[11]; > + } desc; > +} __packed; > + > +struct mt7921_patch_sec { > + uint32_t type; > + uint32_t offs; > + uint32_t size; > + union { > + uint32_t spec[13]; > + struct { > + uint32_t addr; > + uint32_t len; > + uint32_t sec_key_idx; > + uint32_t align_len; > + uint32_t reserved[9]; > + } info; > + }; > +} __packed; > + > +struct mt7921_fw_trailer { > + uint8_t chip_id; > + uint8_t eco_code; > + uint8_t n_region; > + uint8_t format_ver; > + uint8_t format_flag; > + uint8_t reserved[2]; > + char fw_ver[10]; > + char build_date[15]; > + uint32_t crc; > +} __packed; > + > +struct mt7921_fw_region { > + uint32_t decomp_crc; > + uint32_t decomp_len; > + uint32_t decomp_blk_sz; > + uint8_t reserved[4]; > + uint32_t addr; > + uint32_t len; > + uint8_t feature_set; > + uint8_t reserved1[15]; > +} __packed; > + > +#define FW_START_OVERRIDE 0x01 > +#define FW_START_WORKING_PDA_CR4 0x02 > + > +#define FW_FEATURE_SET_ENCRYPT 0x1 > +#define FW_FEATURE_SET_KEY_IDX_MASK 0x06 > +#define FW_FEATURE_ENCRY_MODE 0x10 > +#define FW_FEATURE_OVERRIDE_ADDR 0x20 > + > +#define PATCH_SEC_NOT_SUPPORT 0xffffffff > +#define PATCH_SEC_TYPE_MASK 0x0000ffff > +#define PATCH_SEC_TYPE_INFO 0x2 > + > +#define PATCH_SEC_ENC_TYPE_MASK 0xff000000 > +#define PATCH_SEC_ENC_TYPE_SHIFT 24 > +#define PATCH_SEC_ENC_TYPE_PLAIN (0x00 << > PATCH_SEC_ENC_TYPE_SHIFT) > +#define PATCH_SEC_ENC_TYPE_AES (0x01 << > PATCH_SEC_ENC_TYPE_SHIFT) > +#define PATCH_SEC_ENC_TYPE_SCRAMBLE (0x02 << > PATCH_SEC_ENC_TYPE_SHIFT) > +#define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK 0xffff > +#define PATCH_SEC_ENC_AES_KEY_MASK 0xff > + > +#define DL_MODE_ENCRYPT 0x01 > +#define DL_MODE_KEY_IDX_MASK 0x06 > +#define DL_MODE_KEY_IDX_SHIFT 1 > +#define DL_MODE_RESET_SEC_IV 0x08 > +#define DL_MODE_WORKING_PDA_CR4 0x10 > +#define DL_CONFIG_ENCRY_MODE_SEL 0x40 > +#define DL_MODE_NEED_RSP 0x80000000 > + > +/* defines for mt7921_mcu_get_nic_capability */ > +enum { > + MT_NIC_CAP_TX_RESOURCE, > + MT_NIC_CAP_TX_EFUSE_ADDR, > + MT_NIC_CAP_COEX, > + MT_NIC_CAP_SINGLE_SKU, > + MT_NIC_CAP_CSUM_OFFLOAD, > + MT_NIC_CAP_HW_VER, > + MT_NIC_CAP_SW_VER, > + MT_NIC_CAP_MAC_ADDR, > + MT_NIC_CAP_PHY, > + MT_NIC_CAP_MAC, > + MT_NIC_CAP_FRAME_BUF, > + MT_NIC_CAP_BEAM_FORM, > + MT_NIC_CAP_LOCATION, > + MT_NIC_CAP_MUMIMO, > + MT_NIC_CAP_BUFFER_MODE_INFO, > + MT_NIC_CAP_HW_ADIE_VERSION = 0x14, > + MT_NIC_CAP_ANTSWP = 0x16, > + MT_NIC_CAP_WFDMA_REALLOC, > + MT_NIC_CAP_6G, > +}; > + > +/* defines for channel bandwidth */ > +enum { > + CMD_CBW_20MHZ, > + CMD_CBW_40MHZ, > + CMD_CBW_80MHZ, > + CMD_CBW_160MHZ, > + CMD_CBW_10MHZ, > + CMD_CBW_5MHZ, > + CMD_CBW_8080MHZ, > +}; > + > +/* defines for channel switch reason */ > +enum { > + CH_SWITCH_NORMAL = 0, > + CH_SWITCH_SCAN = 3, > + CH_SWITCH_MCC = 4, > + CH_SWITCH_DFS = 5, > + CH_SWITCH_BACKGROUND_SCAN_START = 6, > + CH_SWITCH_BACKGROUND_SCAN_RUNNING = 7, > + CH_SWITCH_BACKGROUND_SCAN_STOP = 8, > + CH_SWITCH_SCAN_BYPASS_DPD = 9 > +}; > + > +enum { > + HW_BSSID_0 = 0x0, > + HW_BSSID_1, > + HW_BSSID_2, > + HW_BSSID_3, > + HW_BSSID_MAX = HW_BSSID_3, > + EXT_BSSID_START = 0x10, > + EXT_BSSID_1, > + EXT_BSSID_15 = 0x1f, > + EXT_BSSID_MAX = EXT_BSSID_15, > + REPEATER_BSSID_START = 0x20, > + REPEATER_BSSID_MAX = 0x3f, > +}; > + > + > +#define STA_TYPE_STA (1U << 0) > +#define STA_TYPE_AP (1U << 1) > +#define STA_TYPE_ADHOC (1U << 2) > +#define STA_TYPE_WDS (1U << 4) > +#define STA_TYPE_BC (1U << 5) > + > +#define NETWORK_INFRA (1U << 16) > +#define NETWORK_P2P (1U << 17) > +#define NETWORK_IBSS (1U << 18) > +#define NETWORK_WDS (1U << 21) > + > +#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) > +#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA) > +#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P) > +#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P) > +#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) > +#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) > +#define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA) > + > +#define DEV_INFO_ACTIVE 0 >