From 5f8da13f08c7715881e71cf02221c6d43af1663c Mon Sep 17 00:00:00 2001 From: purplerain Date: Wed, 21 Feb 2024 20:26:06 +0000 Subject: [PATCH] sync with OpenBSD -current --- distrib/sets/lists/comp/mi | 1 + sys/arch/amd64/amd64/trap.c | 4 +- sys/arch/arm64/arm64/trap.c | 4 +- sys/dev/ic/qwxreg.h | 7 +- sys/dev/pci/files.pci | 7 +- sys/dev/pci/if_mwx.c | 5106 ++++++++++++++++++++++++++++++++ sys/dev/pci/if_mwxreg.h | 1401 +++++++++ sys/kern/uipc_mbuf.c | 13 +- sys/sys/mbuf.h | 4 +- sys/sys/siginfo.h | 5 +- sys/uvm/uvm_map.c | 15 +- usr.bin/ctfconv/dw.c | 7 +- usr.bin/ctfconv/dwarf.h | 4 +- usr.bin/ctfconv/parse.c | 19 +- usr.bin/ssh/clientloop.c | 4 +- usr.bin/ssh/ssh_config.5 | 6 +- usr.bin/ssh/sshd_config.5 | 17 +- usr.sbin/ntpd/ntp.c | 4 +- usr.sbin/rpki-client/aspa.c | 88 +- usr.sbin/rpki-client/extern.h | 31 +- usr.sbin/rpki-client/gbr.c | 41 +- usr.sbin/rpki-client/geofeed.c | 49 +- usr.sbin/rpki-client/main.c | 27 +- usr.sbin/rpki-client/mft.c | 115 +- usr.sbin/rpki-client/roa.c | 96 +- usr.sbin/rpki-client/rsc.c | 131 +- usr.sbin/rpki-client/tak.c | 65 +- 27 files changed, 6870 insertions(+), 401 deletions(-) create mode 100644 sys/dev/pci/if_mwx.c create mode 100644 sys/dev/pci/if_mwxreg.h diff --git a/distrib/sets/lists/comp/mi b/distrib/sets/lists/comp/mi index 091778b1d..a54f944c1 100644 --- a/distrib/sets/lists/comp/mi +++ b/distrib/sets/lists/comp/mi @@ -581,6 +581,7 @@ ./usr/include/dev/pci/if_lgereg.h ./usr/include/dev/pci/if_liireg.h ./usr/include/dev/pci/if_mskvar.h +./usr/include/dev/pci/if_mwxreg.h ./usr/include/dev/pci/if_myxreg.h ./usr/include/dev/pci/if_nfereg.h ./usr/include/dev/pci/if_nfevar.h diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c index 4df17486b..a40de9202 100644 --- a/sys/arch/amd64/amd64/trap.c +++ b/sys/arch/amd64/amd64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.104 2024/01/31 06:06:28 guenther Exp $ */ +/* $OpenBSD: trap.c,v 1.105 2024/02/21 15:53:07 deraadt Exp $ */ /* $NetBSD: trap.c,v 1.2 2003/05/04 23:51:56 fvdl Exp $ */ /*- @@ -424,7 +424,7 @@ usertrap(struct trapframe *frame) break; case T_CP: sig = SIGILL; - code = (frame->tf_err & 0x7fff) < 4 ? ILL_ILLOPC + code = (frame->tf_err & 0x7fff) < 4 ? ILL_BTCFI : ILL_BADSTK; break; diff --git a/sys/arch/arm64/arm64/trap.c b/sys/arch/arm64/arm64/trap.c index bbe6b04c5..c420b7477 100644 --- a/sys/arch/arm64/arm64/trap.c +++ b/sys/arch/arm64/arm64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.47 2023/12/26 09:19:15 kettenis Exp $ */ +/* $OpenBSD: trap.c,v 1.48 2024/02/21 15:53:07 deraadt Exp $ */ /*- * Copyright (c) 2014 Andrew Turner * All rights reserved. @@ -286,7 +286,7 @@ do_el0_sync(struct trapframe *frame) case EXCP_BRANCH_TGT: curcpu()->ci_flush_bp(); sv.sival_ptr = (void *)frame->tf_elr; - trapsignal(p, SIGILL, esr, ILL_ILLOPC, sv); + trapsignal(p, SIGILL, esr, ILL_BTCFI, sv); break; case EXCP_FPAC: curcpu()->ci_flush_bp(); diff --git a/sys/dev/ic/qwxreg.h b/sys/dev/ic/qwxreg.h index 2e4db5501..b746ad888 100644 --- a/sys/dev/ic/qwxreg.h +++ b/sys/dev/ic/qwxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: qwxreg.h,v 1.6 2024/02/03 10:03:18 stsp Exp $ */ +/* $OpenBSD: qwxreg.h,v 1.7 2024/02/21 14:40:50 kevlo Exp $ */ /* * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. @@ -6927,11 +6927,6 @@ enum ath11k_qmi_bdf_type { #define HAL_SHADOW_REG(sc, x) (HAL_SHADOW_BASE_ADDR(sc) + (4 * (x))) -/* SRNG registers are split into two groups R0 and R2 */ -#define HAL_SRNG_REG_GRP_R0 0 -#define HAL_SRNG_REG_GRP_R2 1 -#define HAL_SRNG_NUM_REG_GRP 2 - enum hal_srng_ring_id { HAL_SRNG_RING_ID_REO2SW1 = 0, HAL_SRNG_RING_ID_REO2SW2, diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 3078e353e..4709015e6 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.363 2023/12/28 17:36:29 stsp Exp $ +# $OpenBSD: files.pci,v 1.364 2024/02/21 10:48:10 claudio Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config file and device description for machine-independent PCI code. @@ -867,5 +867,10 @@ file dev/pci/if_ngbe.c ngbe attach com at pci with com_pci file dev/pci/com_pci.c com_pci +# MediaTek MT7921 / MT7922 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" diff --git a/sys/dev/pci/if_mwx.c b/sys/dev/pci/if_mwx.c new file mode 100644 index 000000000..698b83d95 --- /dev/null +++ b/sys/dev/pci/if_mwx.c @@ -0,0 +1,5106 @@ +/* $OpenBSD: if_mwx.c,v 1.2 2024/02/21 12:08:05 jsg Exp $ */ +/* + * Copyright (c) 2022 Claudio Jeker + * Copyright (c) 2021 MediaTek Inc. + * Copyright (c) 2021 Lorenzo Bianconi + * Copyright (c) 2017 Stefan Sperling + * Copyright (c) 2016 Felix Fietkau + * Copyright (c) 2007-2010 Damien Bergamini + * + * 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +#if NBPFILTER > 0 +#include +#endif +#include +#include +#include + +#include +#include + +#include +#include + +#include + +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 "mwx-mt7961_patch_mcu_1_2_hdr" +#define MT7921_FIRMWARE_WM "mwx-mt7961_ram_code_1" +#define MT7922_ROM_PATCH "mwx-mt7922_patch_mcu_1_1_hdr" +#define MT7922_FIRMWARE_WM "mwx-mt7922_ram_code_1" + +#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_txwi { + struct mt76_txwi *mt_desc; + struct mbuf *mt_mbuf; + bus_dmamap_t mt_map; + LIST_ENTRY(mwx_txwi) mt_entry; + u_int32_t mt_addr; + u_int mt_idx; +}; + +struct mwx_txwi_desc { + struct mt76_txwi *mt_desc; + struct mwx_txwi *mt_data; + + u_int mt_count; + bus_dmamap_t mt_map; + bus_dma_segment_t mt_seg; + LIST_HEAD(, mwx_txwi) mt_freelist; +}; + +struct mwx_queue_data { + struct mbuf *md_mbuf; + struct mwx_txwi *md_txwi; + 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_queue_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; + + struct mwx_txwi_desc sc_txwi; + + 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_scan_task; + 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 + + struct mwx_vif sc_vif; + + /* mcu */ + uint32_t sc_mcu_seq; + struct { + struct mbuf *mcu_m; + uint32_t mcu_cmd; + uint32_t mcu_int; + } sc_mcu_wait[16]; + 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 */ + + int16_t sc_coverage_class; + uint8_t sc_slottime; + + /* 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 +}; + +const struct mwx_rate { + uint16_t rate; + uint16_t hw_value; +} mt76_rates[] = { + { 2, (MT_PHY_TYPE_CCK << 8) | 0 }, + { 4, (MT_PHY_TYPE_CCK << 8) | 1 }, + { 11, (MT_PHY_TYPE_CCK << 8) | 2 }, + { 22, (MT_PHY_TYPE_CCK << 8) | 3 }, + { 12, (MT_PHY_TYPE_OFDM << 8) | 11 }, + { 18, (MT_PHY_TYPE_OFDM << 8) | 15 }, + { 24, (MT_PHY_TYPE_OFDM << 8) | 10 }, + { 36, (MT_PHY_TYPE_OFDM << 8) | 14 }, + { 48, (MT_PHY_TYPE_OFDM << 8) | 9 }, + { 72, (MT_PHY_TYPE_OFDM << 8) | 13 }, + { 96, (MT_PHY_TYPE_OFDM << 8) | 8 }, + { 108, (MT_PHY_TYPE_OFDM << 8) | 12 }, +}; + + +#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 + +static void +pkt_hex_dump(struct mbuf *m) +{ + int len, rowsize = 16; + int i, l, linelen; + uint8_t *data; + + printf("Packet hex dump:\n"); + data = mtod(m, uint8_t *); + len = m->m_len; + + for (i = 0; i < len; i += linelen) { + printf("%04x\t", i); + linelen = len - i; + if (len - i > rowsize) + linelen = rowsize; + for (l = 0; l < linelen; l++) + printf("%02X ", (uint32_t)data[l]); + data += linelen; + printf("\n"); + } +} + +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_newstate(struct ieee80211com *, enum ieee80211_state, int); +void mwx_newstate_task(void *); + +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_txwi_alloc(struct mwx_softc *, int); +void mwx_txwi_free(struct mwx_softc *); +struct mwx_txwi *mwx_txwi_get(struct mwx_softc *); +void mwx_txwi_put(struct mwx_softc *, struct mwx_txwi *); +int mwx_txwi_enqueue(struct mwx_softc *, struct mwx_txwi *, struct mbuf *); +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_queue_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 *); +int mwx_dma_txwi_enqueue(struct mwx_softc *, struct mwx_queue *, + struct mwx_txwi *); +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 *); + +struct mbuf *mwx_mcu_alloc_msg(size_t); +void mwx_mcu_set_len(struct mbuf *, void *); +int mwx_mcu_send_mbuf(struct mwx_softc *, uint32_t, struct mbuf *, int *); +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); +int mwx_mcu_send_mbuf_wait(struct mwx_softc *, uint32_t, struct mbuf *); +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 mwx_end_scan_task(void *); +void mt7921_mcu_scan_event(struct mwx_softc *, struct mbuf *); +int mt7921_mcu_hw_scan(struct mwx_softc *, int); +int mt7921_mcu_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_mcu_build_sku(struct mwx_softc *, int, int8_t *); +int mt7921_mcu_rate_txpower_band(struct mwx_softc *, int, + const uint8_t *, int, int); +int mt7921_mcu_set_rate_txpower(struct mwx_softc *); +void mt7921_mac_reset_counters(struct mwx_softc *); +void mt7921_mac_set_timing(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_mcu_set_bss_pm(struct mwx_softc *, int); +int mt7921_mcu_set_tx(struct mwx_softc *, struct mwx_vif *); +int mt7921_mac_fill_rx(struct mwx_softc *, struct mbuf *, + struct ieee80211_rxinfo *); +uint32_t mt7921_mac_tx_rate_val(struct mwx_softc *); +void mt7921_mac_write_txwi_80211(struct mwx_softc *, struct mbuf *, + struct ieee80211_node *, struct mt76_txwi *); +void mt7921_mac_write_txwi(struct mwx_softc *, struct mbuf *, + struct ieee80211_node *, struct mt76_txwi *); +void mt7921_mac_tx_free(struct mwx_softc *, struct mbuf *); +int mt7921_set_channel(struct mwx_softc *); + +uint8_t mt7921_get_phy_mode_v2(struct mwx_softc *, + struct ieee80211_node *); +struct mbuf *mt7921_alloc_sta_tlv(int); +void *mt7921_append_tlv(struct mbuf *, uint16_t *, int, int); +void mt7921_mcu_add_basic_tlv(struct mbuf *, uint16_t *, + struct mwx_softc *, struct ieee80211_node *, int, int); +void mt7921_mcu_add_sta_tlv(struct mbuf *, uint16_t *, + struct mwx_softc *, struct ieee80211_node *, int, int); +int mt7921_mcu_wtbl_generic_tlv(struct mbuf *, uint16_t *, + struct mwx_softc *, struct ieee80211_node *); +int mt7921_mcu_wtbl_hdr_trans_tlv(struct mbuf *, uint16_t *, + struct mwx_softc *, struct ieee80211_node *); +int mt7921_mcu_wtbl_ht_tlv(struct mbuf *, uint16_t *, + struct mwx_softc *, struct ieee80211_node *); +int mt7921_mac_sta_update(struct mwx_softc *, + struct ieee80211_node *, int, int); + +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 milliseconds 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; + struct mwx_node *mn; + 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; + +#if 0 + /* XXX no channel available yet */ + rv = mt7921_mcu_set_chan_info(sc, MCU_EXT_CMD_SET_RX_PATH); + if (rv) + return rv; +#endif + + rv = mt7921_mcu_set_rate_txpower(sc); + if (rv) + return rv; + + mt7921_mac_reset_counters(sc); + + mn = (void *)ic->ic_bss; + + rv = mt7921_mcu_uni_add_dev(sc, &sc->sc_vif, mn, 1); + if (rv) + return rv; + + rv = mt7921_mcu_set_tx(sc, &sc->sc_vif); + if (rv) + return rv; + + mt7921_mac_wtbl_update(sc, mn->wcid); + + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + rv = mt7921_mcu_set_chan_info(sc, MCU_EXT_CMD_SET_RX_PATH); + if (rv) + return rv; + rv = mt7921_set_channel(sc); + if (rv) + return rv; + + mt7921_mcu_set_sniffer(sc, 1); + mt7921_mcu_set_beacon_filter(sc, 0); + sc->sc_rxfilter = 0; + 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); + + 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 mwx_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); + task_del(systq, &sc->sc_scan_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) +{ + /* XXX this is just wrong */ + static int wcid = 1; + struct mwx_softc *sc = ic->ic_softc; + struct mwx_node *mn; + + mn = malloc(sizeof(struct mwx_node), M_DEVBUF, M_NOWAIT | M_ZERO); + if (mn == NULL) + return NULL; + mn->wcid = wcid++; + + /* init WCID table entry */ + mt7921_mac_wtbl_update(sc, mn->wcid); + + return &mn->ni; +} + +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 = IEEE80211_AID(ni->ni_associd); + + } + printf("%s: new assoc isnew=%d addr=%s WCID=%d\n", DEVNAME(sc), + isnew, ether_sprintf(ni->ni_macaddr), mn->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_mcu_hw_scan_cancel(sc); + if (rv) { + printf("%s: could not abort background scan\n", + DEVNAME(sc)); + return rv; + } + } + + rv = mt7921_mcu_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; + + + switch (ostate) { + case IEEE80211_S_RUN: + if (nstate != ostate) + 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; + } + +printf("%s: %s %d -> %d\n", DEVNAME(sc), __func__, ostate, nstate); + + /* 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: + rv = mt7921_set_channel(sc); + if (rv) + return rv; + mt7921_mcu_set_deep_sleep(sc, 0); + mt7921_mac_sta_update(sc, sc->sc_ic.ic_bss, 1, 1); + break; + case IEEE80211_S_ASSOC: + mt7921_mcu_set_deep_sleep(sc, 1); + break; + case IEEE80211_S_RUN: + mt7921_mcu_hw_scan_cancel(sc); /* XXX */ + 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) +{ + struct mwx_node *mn = (void *)ni; + struct mwx_txwi *mt; + struct mt76_txwi *txp; + int rv; + + if ((mt = mwx_txwi_get(sc)) == NULL) + return ENOBUFS; + /* XXX DMA memory access without BUS_DMASYNC_PREWRITE */ + txp = mt->mt_desc; + memset(txp, 0, sizeof(*txp)); + mt7921_mac_write_txwi(sc, m, ni, txp); + + rv = mwx_txwi_enqueue(sc, mt, m); + if (rv != 0) + return rv; + +printf("%s: TX WCID %08x id %d pid %d\n", DEVNAME(sc), mn->wcid, 0, mt->mt_idx); +printf("%s: TX twxi %08x %08x %08x %08x %08x %08x %08x %08x\n", +DEVNAME(sc), txp->txwi[0], txp->txwi[1], +txp->txwi[2], txp->txwi[3], txp->txwi[4], txp->txwi[5], +txp->txwi[6], txp->txwi[7]); +printf("%s: TX hw txp %d %d %d %d %04x %04x %04x %04x\n", DEVNAME(sc), + txp->msdu_id[0], txp->msdu_id[1], txp->msdu_id[2], txp->msdu_id[3], + txp->ptr[0].len0, txp->ptr[0].len1, txp->ptr[1].len0, txp->ptr[1].len1); + + return mwx_dma_txwi_enqueue(sc, &sc->sc_txq, mt); +} + +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 interrupt %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_txwi_alloc(sc, MWX_TXWI_MAX)) != 0) { + printf("%s: failed to allocate DMA resources %d\n", + DEVNAME(sc), error); + goto fail; + } + + if ((error = mwx_dma_alloc(sc)) != 0) { + printf("%s: failed to allocate DMA resources %d\n", + DEVNAME(sc), error); + goto fail; + } + + /* set regulatory domain to '00' */ + sc->sc_alpha2[0] = '0'; + sc->sc_alpha2[1] = '0'; + + 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 = +#if NOTYET + IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU | /* A-MPDU */ + IEEE80211_C_ADDBA_OFFLOAD | /* device sends ADDBA/DELBA frames */ +#endif + 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 */ + +#if NOTYET + 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); +#endif + ic->ic_htxcaps = 0; + ic->ic_txbfcaps = 0; + ic->ic_aselcaps = 0; + ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_4 | 0x3 /* 64k */); + +#if NOTYET + ic->ic_vhtcaps = IEEE80211_VHTCAP_MAX_MPDU_LENGTH_11454 | + (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; +#endif + + /* 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); + task_set(&sc->sc_scan_task, mwx_end_scan_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_txwi_free(sc); + 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_txwi_alloc(struct mwx_softc *sc, int count) +{ + int error, nsegs, i; + struct mwx_txwi_desc *q = &sc->sc_txwi; + bus_size_t size = count * sizeof(*q->mt_desc); + uint32_t addr; + + LIST_INIT(&q->mt_freelist); + q->mt_count = count; + + error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, + BUS_DMA_NOWAIT, &q->mt_map); + if (error != 0) { + printf("%s: could not create desc TWXI map\n", DEVNAME(sc)); + goto fail; + } + + error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &q->mt_seg, + 1, &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO); + if (error != 0) { + printf("%s: could not allocate TWXI memory\n", DEVNAME(sc)); + goto fail; + } + + error = bus_dmamem_map(sc->sc_dmat, &q->mt_seg, nsegs, size, + (caddr_t *)&q->mt_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->mt_map, q->mt_desc, + size, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not load desc DMA map\n", DEVNAME(sc)); + goto fail; + } + + addr = q->mt_map->dm_segs[0].ds_addr; + + q->mt_data = mallocarray(count, sizeof(*q->mt_data), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (q->mt_data == NULL) { + printf("%s: could not allocate soft data\n", DEVNAME(sc)); + error = ENOMEM; + goto fail; + } + + for (i = 0; i < count; i++) { + q->mt_data[i].mt_idx = i; + q->mt_data[i].mt_desc = &q->mt_desc[i]; + q->mt_data[i].mt_addr = addr + i * sizeof(*q->mt_desc); + error = bus_dmamap_create(sc->sc_dmat, MT_TXD_LEN_MASK, + MT_MAX_SCATTER, MT_TXD_LEN_MASK, 0, BUS_DMA_NOWAIT, + &q->mt_data[i].mt_map); + if (error != 0) { + printf("%s: could not create data DMA map\n", + DEVNAME(sc)); + goto fail; + } + } + + for (i = count; i >= MT_PACKET_ID_FIRST; i--) + LIST_INSERT_HEAD(&q->mt_freelist, &q->mt_data[i], mt_entry); + + return 0; + +fail: + mwx_txwi_free(sc); + return error; +} + +void +mwx_txwi_free(struct mwx_softc *sc) +{ + struct mwx_txwi_desc *q = &sc->sc_txwi; + + if (q->mt_data != NULL) { + int i; + for (i = 0; i < q->mt_count; i++) { + struct mwx_txwi *mt = &q->mt_data[i]; + bus_dmamap_destroy(sc->sc_dmat, mt->mt_map); + m_freem(mt->mt_mbuf); + if (i >= MT_PACKET_ID_FIRST) + LIST_REMOVE(mt, mt_entry); + } + free(q->mt_data, M_DEVBUF, q->mt_count * sizeof(*q->mt_data)); + } + + if (q->mt_desc != NULL) { + bus_dmamap_sync(sc->sc_dmat, q->mt_map, 0, + q->mt_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, q->mt_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->mt_seg.ds_len != 0) + bus_dmamem_unmap(sc->sc_dmat, (caddr_t)q->mt_desc, + q->mt_count * sizeof(*q->mt_desc)); + if (q->mt_map != NULL) + bus_dmamem_free(sc->sc_dmat, &q->mt_seg, 1); + + memset(q, 0, sizeof(*q)); +} + +struct mwx_txwi * +mwx_txwi_get(struct mwx_softc *sc) +{ + struct mwx_txwi *mt; + + mt = LIST_FIRST(&sc->sc_txwi.mt_freelist); + if (mt == NULL) + return NULL; + LIST_REMOVE(mt, mt_entry); + return mt; +} + +void +mwx_txwi_put(struct mwx_softc *sc, struct mwx_txwi *mt) +{ + /* TODO more cleanup here probably */ + + if (mt->mt_idx < MT_PACKET_ID_FIRST) + return; + LIST_INSERT_HEAD(&sc->sc_txwi.mt_freelist, mt, mt_entry); +} + +int +mwx_txwi_enqueue(struct mwx_softc *sc, struct mwx_txwi *mt, struct mbuf *m) +{ + struct mwx_txwi_desc *q = &sc->sc_txwi; + struct mt76_txwi *txp = mt->mt_desc; + struct mt76_connac_txp_ptr *ptr = &txp->ptr[0]; + uint32_t addr; + uint16_t len; + int i, nsegs, rv; + + rv = bus_dmamap_load_mbuf(sc->sc_dmat, mt->mt_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, mt->mt_map, m, + BUS_DMA_WRITE | BUS_DMA_NOWAIT); + if (rv != 0) + return rv; + + nsegs = mt->mt_map->dm_nsegs; + + bus_dmamap_sync(sc->sc_dmat, mt->mt_map, 0, mt->mt_map->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + txp->msdu_id[0] = htole16(mt->mt_idx | MT_MSDU_ID_VALID); + mt->mt_mbuf = m; + + bus_dmamap_sync(sc->sc_dmat, q->mt_map, 0, q->mt_map->dm_mapsize, + BUS_DMASYNC_PREWRITE); + for (i = 0; i < nsegs; i++) { + KASSERT(mt->mt_map->dm_segs[i].ds_addr <= UINT32_MAX); + KASSERT(mt->mt_map->dm_segs[i].ds_len <= MT_TXD_LEN_MASK); + addr = mt->mt_map->dm_segs[i].ds_addr; + len = mt->mt_map->dm_segs[i].ds_len; + + if (i == nsegs - 1) + len |= MT_TXD_LEN_LAST; + + if ((i & 1) == 0) { + ptr->buf0 = htole32(addr); + ptr->len0 = htole16(len); + } else { + ptr->buf1 = htole32(addr); + ptr->len1 = htole16(len); + ptr++; + } + } + bus_dmamap_sync(sc->sc_dmat, q->mt_map, 0, q->mt_map->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + + return 0; +} + +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_queue_data *md = &q->mq_data[i]; + bus_dmamap_destroy(sc->sc_dmat, md->md_map); + m_freem(md->md_mbuf); + } + 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_queue_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_mbuf != 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_mbuf); + md->md_mbuf = NULL; + } + } +} + +int +mwx_buf_fill(struct mwx_softc *sc, struct mwx_queue_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_mbuf = 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) +{ + struct mwx_queue_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_mbuf = m; + md->md_txwi = NULL; + + 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 = 0; + 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; +} + +int +mwx_dma_txwi_enqueue(struct mwx_softc *sc, struct mwx_queue *q, + struct mwx_txwi *mt) +{ + struct mwx_queue_data *md; + struct mt76_desc *desc; + uint32_t buf0, len0, ctrl; + int idx; + + idx = q->mq_prod; + md = &q->mq_data[idx]; + desc = &q->mq_desc[idx]; + + /* check if there is enough space */ + if (1 > mwx_dma_free_slots(q)) { + bus_dmamap_unload(sc->sc_dmat, md->md_map); + return EBUSY; + } + + md->md_txwi = mt; + md->md_mbuf = NULL; + + bus_dmamap_sync(sc->sc_dmat, q->mq_map, 0, q->mq_map->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + buf0 = mt->mt_addr; + len0 = sizeof(mt->mt_desc); + 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); + + idx = (idx + 1) % q->mq_count; + KASSERT(idx != q->mq_cons); + + 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_queue_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_mbuf != 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_mbuf); + md->md_mbuf = NULL; + } + if (md->md_txwi != NULL) { + /* nothing here, cleanup via mt7921_mac_tx_free() */ + md->md_txwi = NULL; +printf("%s: %s txwi acked, idx %d\n", DEVNAME(sc), __func__, idx); + } + + /* 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; + case PKT_TYPE_TXRX_NOTIFY: + mt7921_mac_tx_free(sc, m); + break; +#if TODO + 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: received 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_queue_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_mbuf; + md->md_mbuf = 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); +} + +struct mbuf * +mwx_mcu_alloc_msg(size_t len) +{ + const int headspace = sizeof(struct mt7921_mcu_txd); + struct mbuf *m; + + /* Allocate mbuf with enough space */ + m = m_gethdr(MT_DATA, M_DONTWAIT); + if (m == NULL) + return NULL; + if (len + headspace > MHLEN) { + m_clget(m, M_DONTWAIT, len + headspace); + if (!ISSET(m->m_flags, M_EXT)) { + m_freem(m); + return NULL; + } + } + + m_align(m, len + headspace); + m->m_pkthdr.len = m->m_len = len + headspace; + m_adj(m, headspace); + + return m; +} + +void +mwx_mcu_set_len(struct mbuf *m, void *end) +{ + void *start = mtod(m, void *); + int len = m->m_pkthdr.len, adj; + + KASSERT(start <= end && end - start <= len); + adj = len - (end - start); + m_adj(m, -adj); +} + +int +mwx_mcu_send_mbuf(struct mwx_softc *sc, uint32_t cmd, struct mbuf *m, int *seqp) +{ + struct mt7921_uni_txd *uni_txd; + struct mt7921_mcu_txd *mcu_txd; + struct mwx_queue *q; + uint32_t *txd, val; + int s, rv, txd_len, mcu_cmd = cmd & MCU_CMD_FIELD_ID_MASK; + int len = m->m_pkthdr.len; + uint8_t seq; + + 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); + KASSERT(m_leadingspace(m) >= txd_len); + m = m_prepend(m, txd_len, M_DONTWAIT); + txd = mtod(m, uint32_t *); + memset(txd, 0, txd_len); + + val = (m->m_len & MT_TXD0_TX_BYTES_MASK) | + 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: + +if (cmd != MCU_CMD_FW_SCATTER) { +printf("%s: %s: cmd %08x\n", DEVNAME(sc), __func__, cmd); +pkt_hex_dump(m); +} + + s = splnet(); + while (1) { + rv = mwx_dma_tx_enqueue(sc, q, m); + 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_msg(struct mwx_softc *sc, uint32_t cmd, void *data, size_t len, + int *seqp) +{ + struct mbuf *m; + + m = mwx_mcu_alloc_msg(len); + if (m == NULL) + return ENOMEM; + + if (len != 0) + memcpy(mtod(m, caddr_t), data, len); + + return mwx_mcu_send_mbuf(sc, cmd, m, seqp); +} + +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); +} + +int +mwx_mcu_send_mbuf_wait(struct mwx_softc *sc, uint32_t cmd, struct mbuf *m) +{ + int rv, seq; + + rv = mwx_mcu_send_mbuf(sc, cmd, m, &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); + break; +#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); + break; + 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); + break; + } + + cmd = sc->sc_mcu_wait[rxd->seq].mcu_cmd; + + if (cmd == MCU_CMD_PATCH_SEM_CONTROL || + cmd == MCU_CMD_PATCH_FINISH_REQ) { + /* XXX this is a terrible abuse */ + KASSERT(m_leadingspace(m) >= sizeof(uint32_t)); + 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) + break; + 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)) + break; + 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)) + break; + 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]); + return; + } + + m_freem(m); +} + +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 response 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, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ + { 0x820e4000, 0x21000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ + { 0x820e7000, 0x21e00, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ + { 0x820eb000, 0x24200, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ + { 0x820e2000, 0x20800, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ + { 0x820e3000, 0x20c00, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ + { 0x820e5000, 0x21400, 0x00800 }, /* 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, 0x01000 }, /* WFDMA PCIE0 MCU DMA0 */ + { 0x55000000, 0x03000, 0x01000 }, /* WFDMA PCIE0 MCU DMA1 */ + { 0x58000000, 0x06000, 0x01000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ + { 0x59000000, 0x07000, 0x01000 }, /* 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, 0x04000 }, /* WF_UMAC_TOP (PLE) */ + { 0x820c8000, 0x0c000, 0x02000 }, /* WF_UMAC_TOP (PSE) */ + { 0x820cc000, 0x0e000, 0x01000 }, /* WF_UMAC_TOP (PP) */ + { 0x820cd000, 0x0f000, 0x01000 }, /* WF_MDP_TOP */ + { 0x820ce000, 0x21c00, 0x00200 }, /* WF_LMAC_TOP (WF_SEC) */ + { 0x820cf000, 0x22000, 0x01000 }, /* WF_LMAC_TOP (WF_PF) */ + { 0x820e0000, 0x20000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ + { 0x820e1000, 0x20400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ + { 0x820e9000, 0x23400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ + { 0x820ea000, 0x24000, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ + { 0x820ec000, 0x24600, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ + { 0x820f0000, 0xa0000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ + { 0x820f1000, 0xa0600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ + { 0x820f2000, 0xa0800, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ + { 0x820f3000, 0xa0c00, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ + { 0x820f4000, 0xa1000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ + { 0x820f5000, 0xa1400, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ + { 0x820f7000, 0xa1e00, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ + { 0x820f9000, 0xa3400, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ + { 0x820fa000, 0xa4000, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ + { 0x820fb000, 0xa4200, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ + { 0x820fc000, 0xa4600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ + { 0x820fd000, 0xa4800, 0x00800 }, /* 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; + } + + mwx_set(sc, MT_PCIE_MAC_PM, MT_PCIE_MAC_PM_L0S_DIS); + + 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 already pulled up by mwx_mcu_rx_event() */ + if (m->m_len < sizeof(*hdr)) { + printf("%s: GET_NIC_CAPAB response size error\n", DEVNAME(sc)); + m_freem(m); + return EINVAL; + } + hdr = mtod(m, struct mt76_connac_cap_hdr *); + count = le16toh(hdr->n_elements); + m_adj(m, sizeof(*hdr)); + + for (i = 0; i < count; i++) { + uint32_t type, len; + + if (m->m_len < sizeof(*tlv)) { + printf("%s: GET_NIC_CAPAB tlv size error\n", + DEVNAME(sc)); + m_freem(m); + return EINVAL; + } + + tlv = mtod(m, struct tlv_hdr *); + 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: + /* TODO 6GHZ SUPPORT */ + sc->sc_capa.has_6ghz = /* XXX 1 */ 0; + break; + case MT_NIC_CAP_MAC_ADDR: + if (len < ETHER_ADDR_LEN) + break; + memcpy(sc->sc_lladdr, mtod(m, caddr_t), ETHER_ADDR_LEN); + break; + case MT_NIC_CAP_PHY: + if (len < sizeof(*cap)) + break; + cap = mtod(m, struct 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); +} + +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); +} + +int +mt7921_mcu_hw_scan(struct mwx_softc *sc, int bgscan) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_channel *c; + struct mt76_connac_hw_scan_req *req; + struct mbuf *m; + int n_ssids = 0; + int rv; + uint8_t nchan; + + m = mwx_mcu_alloc_msg(sizeof(*req)); + if (m == NULL) + return ENOMEM; + req = mtod(m, struct mt76_connac_hw_scan_req *); + + 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 = htole32(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; + + for (nchan = 0, c = &ic->ic_channels[1]; + c <= &ic->ic_channels[IEEE80211_CHAN_MAX] && + nchan < 64; c++) { + struct mt76_connac_mcu_scan_channel *chan; + uint8_t channel_num; + + if (c->ic_flags == 0) + continue; + + if (nchan < 32) + chan = &req->channels[nchan]; + else + chan = &req->ext_channels[nchan - 32]; + + channel_num = ieee80211_mhz2ieee(c->ic_freq, 0); + /* TODO IEEE80211_IS_CHAN_6GHZ -> chan->band = 3*/ + if (IEEE80211_IS_CHAN_2GHZ(c)) { + chan->band = 1; + } else { + chan->band = 2; + } + chan->channel_num = channel_num; + nchan++; + } + + if (nchan <= 32) { + req->channels_num = nchan; + } else { + req->channels_num = 32; + req->ext_channels_num = nchan - 32; + } + + req->channel_type = nchan ? 4 : 0; + req->timeout_value = htole16(nchan * 120); + req->channel_min_dwell_time = htole16(120); + req->channel_dwell_time = htole16(120); + + +#ifdef NOTYET + if (sreq->ie_len > 0) { + memcpy(req->ies, sreq->ie, sreq->ie_len); + req->ies_len = htole16(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_mbuf(sc, MCU_CE_CMD_START_HW_SCAN, m, NULL); + if (rv != 0) + sc->sc_flags &= ~(MWX_FLAG_SCANNING | MWX_FLAG_BGSCAN); + + return rv; +} + +int +mt7921_mcu_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; +} + +void +mwx_end_scan_task(void *arg) +{ + struct mwx_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + int s; + + s = splnet(); + ieee80211_end_scan(&ic->ic_if); + splx(s); +} + +void +mt7921_mcu_scan_event(struct mwx_softc *sc, struct mbuf *m) +{ + if (mt7921_mcu_hw_scan_cancel(sc) != 0) + return; + task_add(systq, &sc->sc_scan_task); +} + +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; + uint32_t flags; + } __packed *channel; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_channel *chan; + struct mbuf *m; + int i, len, rv; + int n_2ch = 0, n_5ch = 0, n_6ch = 0; + + len = sizeof(*hdr) + IEEE80211_CHAN_MAX * sizeof(channel); + m = mwx_mcu_alloc_msg(len); + if (m == NULL) + return ENOMEM; + hdr = mtod(m, void *); + + hdr->alpha2[0] = '0'; + hdr->alpha2[1] = '0'; + + channel = (void *)(hdr + 1); + + hdr->bw_2g = 0; /* BW_20_40M */ + 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++; + } + hdr->bw_5g = 3; /* BW_20_40_80_160M */ + 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 */ + hdr->bw_6g = 3; /* BW_20_40_80_160M */ + 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(sc->sc_alpha2)); + hdr->n_2ch = n_2ch; + hdr->n_5ch = n_5ch; + hdr->n_6ch = n_6ch; + + mwx_mcu_set_len(m, channel); + rv = mwx_mcu_send_mbuf(sc, MCU_CE_CMD_SET_CHAN_DOMAIN, m, NULL); + 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; + 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 = { + .tx_streams_num = sc->sc_capa.num_streams, + .rx_streams = sc->sc_capa.antenna_mask, + .band_idx = 0, /* XXX 0 or 1 */ + }; + + if (sc->sc_ic.ic_opmode == IEEE80211_M_STA && sc->sc_ic.ic_bss != NULL) + channel = sc->sc_ic.ic_bss->ni_chan; + else + channel = sc->sc_ic.ic_ibss_chan; + + req.control_ch = ieee80211_mhz2ieee(channel->ic_freq, + channel->ic_flags); + req.center_ch = ieee80211_mhz2ieee(channel->ic_freq, + channel->ic_flags); + 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)); +} + +/* hardcoded version of what linux does */ +void +mt7921_mcu_build_sku(struct mwx_softc *sc, int band, int8_t *sku) +{ + int max_power = 127; + int i, offset = 4; + + memset(sku, max_power, MT_SKU_POWER_LIMIT); + + if (band == MT_TX_PWR_BAND_2GHZ) { + /* cck */ + memset(sku, 0x28, 4); + } + + /* ofdm */ + memset(sku + offset, 0x28, 8); + offset += 8; + + /* ht */ + for (i = 0; i < 2; i++) { + memset(sku + offset, 0x28, 8); + offset += 8; + } + sku[offset++] = 0x28; + + /* vht */ + for (i = 0; i < 4; i++) { + /* this only sets 10 out of 12 bytes on purpose */ + memset(sku + offset, 0x28, 10); + offset += 12; + } + + /* he */ + for (i = 0; i < 7; i++) { + memset(sku + offset, 0x28, 12); + offset += 12; + } +} + +int +mt7921_mcu_rate_txpower_band(struct mwx_softc *sc, int band, + const uint8_t *chans, int n_chans, int is_last) +{ + struct mt76_connac_sku_tlv *sku_tlv; + struct mt76_connac_tx_power_limit_tlv *tx_power_tlv; + struct mbuf *m; + int batch_size = 8; + const int len = sizeof(*tx_power_tlv) + batch_size * sizeof(*sku_tlv); + int rv = 0, idx, j; + + for (idx = 0; idx < n_chans; ) { + int num_ch = batch_size; + + m = mwx_mcu_alloc_msg(len); + if (m == NULL) + return ENOMEM; + tx_power_tlv = mtod(m, struct mt76_connac_tx_power_limit_tlv *); + tx_power_tlv->n_chan = num_ch; + tx_power_tlv->band = band; + memcpy(tx_power_tlv->alpha2, sc->sc_alpha2, + sizeof(sc->sc_alpha2)); + + if (n_chans - idx < batch_size) { + num_ch = n_chans - idx; + if (is_last) + tx_power_tlv->last_msg = 1; + } + + sku_tlv = (struct mt76_connac_sku_tlv *)(tx_power_tlv + 1); + + for (j = 0; j < num_ch; j++, idx++) { + sku_tlv->channel = chans[idx]; + mt7921_mcu_build_sku(sc, band, sku_tlv->pwr_limit); + sku_tlv++; + } + + mwx_mcu_set_len(m, sku_tlv); + rv = mwx_mcu_send_mbuf(sc, MCU_CE_CMD_SET_RATE_TX_POWER, m, + NULL); + if (rv != 0) + break; + } + + return rv; +} + +int +mt7921_mcu_set_rate_txpower(struct mwx_softc *sc) +{ + static const uint8_t chan_list_2ghz[] = { + 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14 + }; + static const uint8_t chan_list_5ghz[] = { + 36, 38, 40, 42, 44, 46, 48, + 50, 52, 54, 56, 58, 60, 62, + 64, 100, 102, 104, 106, 108, 110, + 112, 114, 116, 118, 120, 122, 124, + 126, 128, 132, 134, 136, 138, 140, + 142, 144, 149, 151, 153, 155, 157, + 159, 161, 165 + }; + static const uint8_t chan_list_6ghz[] = { + 1, 3, 5, 7, 9, 11, 13, + 15, 17, 19, 21, 23, 25, 27, + 29, 33, 35, 37, 39, 41, 43, + 45, 47, 49, 51, 53, 55, 57, + 59, 61, 65, 67, 69, 71, 73, + 75, 77, 79, 81, 83, 85, 87, + 89, 91, 93, 97, 99, 101, 103, + 105, 107, 109, 111, 113, 115, 117, + 119, 121, 123, 125, 129, 131, 133, + 135, 137, 139, 141, 143, 145, 147, + 149, 151, 153, 155, 157, 161, 163, + 165, 167, 169, 171, 173, 175, 177, + 179, 181, 183, 185, 187, 189, 193, + 195, 197, 199, 201, 203, 205, 207, + 209, 211, 213, 215, 217, 219, 221, + 225, 227, 229, 233 + }; + int rv = 0; + + if (sc->sc_capa.has_2ghz) + rv = mt7921_mcu_rate_txpower_band(sc, MT_TX_PWR_BAND_2GHZ, + chan_list_2ghz, nitems(chan_list_2ghz), + !(sc->sc_capa.has_5ghz || sc->sc_capa.has_6ghz)); + if (rv == 0 && sc->sc_capa.has_5ghz) + rv = mt7921_mcu_rate_txpower_band(sc, MT_TX_PWR_BAND_5GHZ, + chan_list_5ghz, nitems(chan_list_5ghz), + !sc->sc_capa.has_6ghz); + if (rv == 0 && sc->sc_capa.has_6ghz) + rv = mt7921_mcu_rate_txpower_band(sc, MT_TX_PWR_BAND_6GHZ, + chan_list_6ghz, nitems(chan_list_6ghz), 1); + return rv; +} + +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); +} + +void +mt7921_mac_set_timing(struct mwx_softc *sc) +{ + uint16_t coverage_class = 0; /* XXX */ + uint32_t val, reg_offset; + uint32_t cck = MT_TIMEOUT_CCK_DEF_VAL; + uint32_t ofdm = MT_TIMEOUT_OFDM_DEF_VAL; + uint32_t offset; + int is_2ghz = 1; /* XXX get from ic_bss node */ + uint32_t sifs = is_2ghz ? 10 : 16; + uint32_t slottime = IEEE80211_DUR_DS_SHSLOT; /* XXX get from stack */ + +#ifdef NOTYET + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; +#endif + + mwx_set(sc, MT_ARB_SCR(0), + MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); + delay(1); + + offset = 3 * coverage_class; + reg_offset = offset | (offset << 16); + + mwx_write(sc, MT_TMAC_CDTR(0), cck + reg_offset); + mwx_write(sc, MT_TMAC_ODTR(0), ofdm + reg_offset); + mwx_write(sc, MT_TMAC_ICR0(0), + MT_IFS_EIFS_DEF | MT_IFS_RIFS_DEF | + (sifs << MT_IFS_SIFS_SHIFT) | + (slottime << MT_IFS_SLOT_SHIFT)); + + if (slottime < 20 || !is_2ghz) + val = MT7921_CFEND_RATE_DEFAULT; + else + val = MT7921_CFEND_RATE_11B; + + mwx_rmw(sc, MT_AGG_ACR0(0), val, MT_AGG_ACR_CFEND_RATE_MASK); + mwx_clear(sc, MT_ARB_SCR(0), + MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); +} + +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(STA_TYPE_AP | NETWORK_INFRA); + break; + case IEEE80211_M_STA: + basic_req.basic.conn_type = + htole32(STA_TYPE_STA | NETWORK_INFRA); + break; + case IEEE80211_M_IBSS: + basic_req.basic.conn_type = + htole32(STA_TYPE_ADHOC | NETWORK_IBSS); + 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) +{ + int rv; + + if (enable) { +#ifdef NOTYET + rv = mt7921_mcu_uni_bss_bcnft(dev, vif, true); + if (rv) + return rv; +#endif + mwx_set(sc, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); + } else { + rv = mt7921_mcu_set_bss_pm(sc, 0); + if (rv) + return rv; + mwx_clear(sc, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); + } + return 0; +} + +int +mt7921_mcu_set_bss_pm(struct mwx_softc *sc, int enable) +{ +#ifdef NOTYET + struct { + uint8_t bss_idx; + uint8_t dtim_period; + uint16_t aid; + uint16_t bcn_interval; + uint16_t atim_window; + uint8_t uapsd; + uint8_t bmc_delivered_ac; + uint8_t bmc_triggered_ac; + uint8_t pad; + } req = { + .bss_idx = mvif->mt76.idx, + .aid = htole16(vif->cfg.aid), + .dtim_period = vif->bss_conf.dtim_period, + .bcn_interval = htole16(vif->bss_conf.beacon_int), + }; +#endif + struct { + uint8_t bss_idx; + uint8_t pad[3]; + } req_hdr = { + .bss_idx = /* mvif->mt76.idx XXX */ 0, + }; + int rv; + + rv = mwx_mcu_send_msg(sc, MCU_CE_CMD_SET_BSS_ABORT, + &req_hdr, sizeof(req_hdr), NULL); +#ifdef NOTYET + if (rv != 0 || !enable) + return rv; + rv = mwx_mcu_send_msg(sc, MCU_CE_CMD_SET_BSS_CONNECTED, + &req, sizeof(req), NULL); +#endif + return rv; +} + +#define IEEE80211_NUM_ACS 4 +int +mt7921_mcu_set_tx(struct mwx_softc *sc, struct mwx_vif *mvif) +{ + struct edca { + uint16_t cw_min; + uint16_t cw_max; + uint16_t txop; + uint16_t aifs; + uint8_t guardtime; + uint8_t acm; + } __packed; + struct mt7921_mcu_tx { + struct edca edca[IEEE80211_NUM_ACS]; + uint8_t bss_idx; + uint8_t qos; + uint8_t wmm_idx; + uint8_t pad; + } __packed req = { + .bss_idx = mvif->idx, + .qos = /* vif->bss_conf.qos */ 0, + .wmm_idx = mvif->wmm_idx, + }; +#ifdef NOTYET + struct mu_edca { + uint8_t cw_min; + uint8_t cw_max; + uint8_t aifsn; + uint8_t acm; + uint8_t timer; + uint8_t padding[3]; + }; + struct mt7921_mcu_mu_tx { + uint8_t ver; + uint8_t pad0; + uint16_t len; + uint8_t bss_idx; + uint8_t qos; + uint8_t wmm_idx; + uint8_t pad1; + struct mu_edca edca[IEEE80211_NUM_ACS]; + uint8_t pad3[32]; + } __packed req_mu = { + .bss_idx = mvif->mt76.idx, + .qos = vif->bss_conf.qos, + .wmm_idx = mvif->mt76.wmm_idx, + }; +#endif + static const int to_aci[] = { 1, 0, 2, 3 }; + int ac, rv; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + //struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; + struct edca *e = &req.edca[to_aci[ac]]; + + e->aifs = htole16(/* q->aifs */ 2); + e->txop = htole16(/* q->txop */ 0); + +#ifdef NOTYET + if (q->cw_min) + e->cw_min = htole16(q->cw_min); + else +#endif + e->cw_min = htole16(5); + +#ifdef NOTYET + if ( q->cw_max) + e->cw_max = htole16(q->cw_max); + else +#endif + e->cw_max = htole16(10); + } + + rv = mwx_mcu_send_msg(sc, MCU_CE_CMD_SET_EDCA_PARMS, &req, + sizeof(req), NULL); + +#ifdef NOTYET + if (rv) + return rv; + if (!vif->bss_conf.he_support) + return 0; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct ieee80211_he_mu_edca_param_ac_rec *q; + struct mu_edca *e; + + if (!mvif->queue_params[ac].mu_edca) + break; + + q = &mvif->queue_params[ac].mu_edca_param_rec; + e = &(req_mu.edca[to_aci[ac]]); + + e->cw_min = q->ecw_min_max & 0xf; + e->cw_max = (q->ecw_min_max & 0xf0) >> 4; + e->aifsn = q->aifsn; + e->timer = q->mu_edca_timer; + } + + rv = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_MU_EDCA_PARMS), + &req_mu, sizeof(req_mu), false); +#endif + return rv; +} + +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 chfnum, 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; + } + + + chfnum = (rxd3 & MT_RXD3_NORMAL_CH_NUM_MASK) >> + MT_RXD3_NORMAL_CH_NUM_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; + } + + 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; + } +#endif + + 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 = htole16(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 = chfnum; + + return 0; +} + +uint32_t +mt7921_mac_tx_rate_val(struct mwx_softc *sc) +{ + int rateidx = 0, offset = 4; + uint32_t rate, mode; + + /* XXX TODO basic_rates + rateidx = ffs(vif->bss_conf.basic_rates) - 1; + */ + + if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) + offset = 0; + /* pick the lowest rate for hidden nodes */ + if (rateidx < 0) + rateidx = 0; + + rateidx += offset; + + if (rateidx >= nitems(mt76_rates)) + rateidx = offset; + + rate = mt76_rates[rateidx].hw_value; + mode = (rate >> 8) << MT_TX_RATE_MODE_SHIFT; + rate &= 0xff; + + return (rate & MT_TX_RATE_IDX_MASK) | (mode & MT_TX_RATE_MODE_MASK); +} + +void +mt7921_mac_write_txwi_80211(struct mwx_softc *sc, struct mbuf *m, + struct ieee80211_node *ni, struct mt76_txwi *txp) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_frame *wh; + uint32_t val; + uint8_t type, subtype, tid = 0; + u_int hdrlen; + int multicast; + + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + type >>= IEEE80211_FC0_TYPE_SHIFT; + subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + subtype >>= IEEE80211_FC0_SUBTYPE_SHIFT; + multicast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + if (type == IEEE80211_FC0_TYPE_CTL) + hdrlen = sizeof(struct ieee80211_frame_min); + else + hdrlen = ieee80211_get_hdrlen(wh); + + /* Put QoS frames on the data queue which maps to their TID. */ + if (ieee80211_has_qos(wh)) { + uint16_t qos = ieee80211_get_qos(wh); + + tid = qos & IEEE80211_QOS_TID; + } + +#ifdef NOTYET + if (ieee80211_is_action(fc) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { + u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + + txp->txwi[5] |= htole32(MT_TXD5_ADD_BA); + tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK; + } else if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; + u16 control = le16_to_cpu(bar->control); + + tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control); + } +#endif + + val = MT_HDR_FORMAT_802_11 | MT_TXD1_HDR_INFO(hdrlen / 2) | + MT_TXD1_TID(tid); + txp->txwi[1] |= htole32(val); + + val = MT_TXD2_FRAME_TYPE(type) | MT_TXD2_SUB_TYPE(subtype); + if (multicast) + val |= MT_TXD2_MULTICAST; + +#ifdef NOTYET + if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && + key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + val |= MT_TXD2_BIP; + txp->txwi[3] &= ~htole32(MT_TXD3_PROTECT_FRAME); + } +#endif + + if (multicast || type != IEEE80211_FC0_TYPE_DATA) { + /* Fixed rata is available just for 802.11 txd */ + uint32_t rate, val6; + + val |= MT_TXD2_FIX_RATE; + /* hardware won't add HTC for mgmt/ctrl frame */ + val |= htole32(MT_TXD2_HTC_VLD); + + rate = mt7921_mac_tx_rate_val(sc); + + val6 = MT_TXD6_FIXED_BW; + val6 |= (rate << MT_TXD6_TX_RATE_SHIFT) & MT_TXD6_TX_RATE_MASK; + txp->txwi[6] |= htole32(val6); + txp->txwi[3] |= htole32(MT_TXD3_BA_DISABLE); + } + + txp->txwi[2] |= htole32(val); + +#ifdef NOTYET + if (ieee80211_is_beacon(fc)) { + txp->txwi[3] &= ~htole32(MT_TXD3_SW_POWER_MGMT); + txp->txwi[3] |= htole32(MT_TXD3_REM_TX_COUNT); + } + + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + u16 seqno = le16_to_cpu(hdr->seq_ctrl); + + if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno = le16_to_cpu(bar->start_seq_num); + } + + val = MT_TXD3_SN_VALID | + FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); + txp->txwi[3] |= htole32(val); + txp->txwi[7] &= ~htole32(MT_TXD7_HW_AMSDU); + } +#endif + + val = MT_TXD7_TYPE(type) | MT_TXD7_SUB_TYPE(subtype); + txp->txwi[7] |= htole32(val); + +#if NBPFILTER > 0 + if (__predict_false(sc->sc_drvbpf != NULL)) { + struct mwx_tx_radiotap_header *tap = &sc->sc_txtap; + uint16_t chan_flags; + + tap->wt_flags = 0; + tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); + chan_flags = ni->ni_chan->ic_flags; + if (ic->ic_curmode != IEEE80211_MODE_11N && + ic->ic_curmode != IEEE80211_MODE_11AC) { + chan_flags &= ~IEEE80211_CHAN_HT; + chan_flags &= ~IEEE80211_CHAN_40MHZ; + } + if (ic->ic_curmode != IEEE80211_MODE_11AC) + chan_flags &= ~IEEE80211_CHAN_VHT; + tap->wt_chan_flags = htole16(chan_flags); +#ifdef NOTYET + if ((ni->ni_flags & IEEE80211_NODE_HT) && + !IEEE80211_IS_MULTICAST(wh->i_addr1) && + type == IEEE80211_FC0_TYPE_DATA && + rinfo->ht_plcp != IWX_RATE_HT_SISO_MCS_INV_PLCP) { + tap->wt_rate = (0x80 | rinfo->ht_plcp); + } else + tap->wt_rate = rinfo->rate; +#endif + tap->wt_rate = 2; + if ((ic->ic_flags & IEEE80211_F_WEPON) && + (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) + tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; + + bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_txtap_len, + m, BPF_DIRECTION_OUT); + } +#endif + +} + +static inline uint8_t +mt7921_lmac_mapping(uint8_t ac) +{ + /* LMAC uses the reverse order of mac80211 AC indexes */ + return 3 - ac; +} + +void +mt7921_mac_write_txwi(struct mwx_softc *sc, struct mbuf *m, + struct ieee80211_node *ni, struct mt76_txwi *txp) +{ + struct mwx_node *mn = (void *)ni; + uint32_t val, p_fmt, omac_idx; + uint8_t q_idx, wmm_idx, band_idx; + uint8_t phy_idx = 0; + /* XXX hardcoded and wrong */ + int pid = MT_PACKET_ID_FIRST; + enum mt76_txq_id qid = MT_TXQ_BE; + + omac_idx = sc->sc_vif.omac_idx << MT_TXD1_OWN_MAC_SHIFT; + wmm_idx = sc->sc_vif.wmm_idx; + band_idx = sc->sc_vif.band_idx; + + if (qid >= MT_TXQ_PSD) { + p_fmt = MT_TX_TYPE_CT; + q_idx = MT_LMAC_ALTX0; + } else { + p_fmt = MT_TX_TYPE_CT; + q_idx = wmm_idx * MT7921_MAX_WMM_SETS + + mt7921_lmac_mapping(/* skb_get_queue_mapping(skb) */ 0); + +#ifdef NOTYET + /* counting non-offloading skbs */ + wcid->stats.tx_bytes += skb->len; + wcid->stats.tx_packets++; +#endif + } + + val = ((m->m_pkthdr.len + MT_TXD_SIZE) & MT_TXD0_TX_BYTES_MASK) | + p_fmt | MT_TXD0_Q_IDX(q_idx); + txp->txwi[0] = htole32(val); + + val = MT_TXD1_LONG_FORMAT | (mn->wcid & MT_TXD1_WLAN_IDX_MASK) | + (omac_idx & MT_TXD1_OWN_MAC_MASK); + if (phy_idx || band_idx) + val |= MT_TXD1_TGID; + txp->txwi[1] = htole32(val); + txp->txwi[2] = 0; + + val = 15 << MT_TXD3_REM_TX_COUNT_SHIFT; +#ifdef NOTYET + if (key) + val |= MT_TXD3_PROTECT_FRAME; + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + val |= MT_TXD3_NO_ACK; +#endif + txp->txwi[3] = htole32(val); + txp->txwi[4] = 0; + + val = pid & MT_TXD5_PID; + if (pid >= MT_PACKET_ID_FIRST) + val |= MT_TXD5_TX_STATUS_HOST; + txp->txwi[5] = htole32(val); + txp->txwi[6] = 0; + txp->txwi[7] = /* XXX wcid->amsdu ? htole32(MT_TXD7_HW_AMSDU) : */ 0; + +#ifdef NOTYET + if (is_8023) + mt76_connac2_mac_write_txwi_8023(txp, m, wcid); + else +#endif + mt7921_mac_write_txwi_80211(sc, m, ni, txp); +} + +void +mt7921_mac_tx_free(struct mwx_softc *sc, struct mbuf *m) +{ +#ifdef NOTYET + 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)); +#endif + printf("%s\n", __func__); + m_freem(m); +} + +int +mt7921_set_channel(struct mwx_softc *sc) +{ + int rv; + + /* stop queues, block other configs (MT76_RESET) */ + // XXX NOTYET mt76_set_channel(sc); + + rv = mt7921_mcu_set_chan_info(sc, MCU_EXT_CMD_CHANNEL_SWITCH); + if (rv) + return rv; + mt7921_mac_set_timing(sc); + mt7921_mac_reset_counters(sc); + + /* restart queues */ + return 0; +} + +uint8_t +mt7921_get_phy_mode_v2(struct mwx_softc *sc, struct ieee80211_node *ni) +{ + uint8_t mode = 0; + + if (ni == NULL) + ni = sc->sc_ic.ic_bss; + + if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { + mode |= PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP; + if (ieee80211_node_supports_ht(ni)) + mode |= PHY_TYPE_BIT_HT; +#ifdef NOTYET + if (ieee80211_node_supports_he(ni)) + mode |= PHY_TYPE_BIT_HE; +#endif + } else if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) /* || CHAN_6GHZ */) { + mode |= PHY_TYPE_BIT_OFDM; + if (ieee80211_node_supports_ht(ni)) + mode |= PHY_TYPE_BIT_HT; + if (ieee80211_node_supports_vht(ni)) + mode |= PHY_TYPE_BIT_VHT; +#ifdef NOTYET + if (ieee80211_node_supports_he(ni)) + mode |= PHY_TYPE_BIT_HE; +#endif + } + return mode; +} + +struct mbuf * +mt7921_alloc_sta_tlv(int len) +{ + struct mbuf *m; + + /* Allocate mbuf cluster with enough space */ + m = m_clget(NULL, M_DONTWAIT, MCLBYTES); + if (m == NULL) + return NULL; + + /* align to have space for the mcu header */ + m->m_data += sizeof(struct mt7921_mcu_txd) + len; + m->m_len = m->m_pkthdr.len = 0; + + return m; +} + +/* + * Reserve len bytes at the end of mbuf m, return to start of that area + * after initializing the data. It also sets the tag and len hdr. + */ +void * +mt7921_append_tlv(struct mbuf *m, uint16_t *tlvnum, int tag, int len) +{ + struct { + uint16_t tag; + uint16_t len; + } tlv = { + .tag = htole16(tag), + .len = htole16(len), + }; + caddr_t p; + + KASSERT(m_trailingspace(m) >= len); + + p = mtod(m, caddr_t) + m->m_len; + m->m_len += len; + m->m_pkthdr.len = m->m_len; + memset(p, 0, len); + memcpy(p, &tlv, sizeof(tlv)); + + *tlvnum += 1; + + return p; +} + +void +mt7921_mcu_add_basic_tlv(struct mbuf *m, uint16_t *tlvnum, struct mwx_softc *sc, + struct ieee80211_node *ni, int add, int new) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct sta_rec_basic *basic; + + basic = mt7921_append_tlv(m, tlvnum, STA_REC_BASIC, sizeof(*basic)); + + basic->extra_info = htole16(EXTRA_INFO_VER); + if (add) { + if (new) + basic->extra_info |= htole16(EXTRA_INFO_NEW); + basic->conn_state = CONN_STATE_PORT_SECURE; + } else { + basic->conn_state = CONN_STATE_DISCONNECT; + } + + if (ni == NULL) { + basic->conn_type = htole32(STA_TYPE_BC | NETWORK_INFRA); + memset(basic->peer_addr, 0xff, sizeof(basic->peer_addr)); + return; + } + + switch (ic->ic_opmode) { + case IEEE80211_M_HOSTAP: + basic->conn_type = htole32(STA_TYPE_STA | NETWORK_INFRA); + break; + case IEEE80211_M_STA: + basic->conn_type = htole32(STA_TYPE_AP | NETWORK_INFRA); + break; + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: + basic->conn_type = htole32(STA_TYPE_ADHOC | NETWORK_IBSS); + break; + case IEEE80211_M_MONITOR: + panic("mt7921_mcu_sta_basic_tlv unexpected operation mode"); + } + + basic->aid = htole16(IEEE80211_AID(ni->ni_associd)); + memcpy(basic->peer_addr, ni->ni_macaddr, IEEE80211_ADDR_LEN); + basic->qos = (ni->ni_flags & IEEE80211_NODE_QOS) != 0; +} + +void +mt7921_mcu_add_sta_tlv(struct mbuf *m, uint16_t *tlvnum, struct mwx_softc *sc, + struct ieee80211_node *ni, int add, int new) +{ + //struct ieee80211com *ic = &sc->sc_ic; + struct sta_rec_ra_info *ra_info; + struct sta_rec_state *state; + struct sta_rec_phy *phy; + uint16_t supp_rates; + +#ifdef NOTYET + /* sta rec ht */ + if (sta->deflink.ht_cap.ht_supported) { + struct sta_rec_ht *ht; + + ht = mt7921_append_tlv(m, tlvnum, STA_REC_HT, sizeof(*ht)); + ht->ht_cap = htole16(sta->deflink.ht_cap.cap); + } + + /* sta rec vht */ + if (sta->deflink.vht_cap.vht_supported) { + struct sta_rec_vht *vht; + + vht = mt7921_append_tlv(m, tlvnum, STA_REC_VHT, + sizeof(*vht)); + vht->vht_cap = htole32(sta->deflink.vht_cap.cap); + vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map; + vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map; + } + + /* sta rec uapsd */ + /* from function: + if (vif->type != NL80211_IFTYPE_AP || !sta->wme) + return; + */ + mt7921_mcu_sta_uapsd(m, tlvnum, vif, ni); +#endif + +#ifdef NOTYET + if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he) + mt76_connac_mcu_sta_amsdu_tlv(skb, sta, vif); + + /* sta rec he */ + if (sta->deflink.he_cap.has_he) { + mt76_connac_mcu_sta_he_tlv(skb, sta); + if (band == NL80211_BAND_6GHZ && + sta_state == MT76_STA_INFO_STATE_ASSOC) { + struct sta_rec_he_6g_capa *he_6g_capa; + + he_6g_capa = mt7921_append_tlv(m, tlvnum, + STA_REC_HE_6G, sizeof(*he_6g_capa)); + he_6g_capa->capa = sta->deflink.he_6ghz_capa.capa; + } + } +#endif + + phy = mt7921_append_tlv(m, tlvnum, STA_REC_PHY, sizeof(*phy)); + /* XXX basic_rates: bitmap of basic rates, each bit stands for an + * index into the rate table configured by the driver in + * the current band. + */ + phy->basic_rate = htole16(0x0150); /* XXX */ + phy->phy_type = mt7921_get_phy_mode_v2(sc, ni); +#ifdef NOTYET + phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, + sta->deflink.ht_cap.ampdu_factor) | + FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, + sta->deflink.ht_cap.ampdu_density); +#endif + // XXX phy->rcpi = rssi_to_rcpi(-ewma_rssi_read(&sc->sc_vif.rssi)); + phy->rcpi = 0xdc; /* XXX STOLEN FROM LINUX DUMP */ + +#ifdef HACK + supp_rates = sta->deflink.supp_rates[band]; + if (band == NL80211_BAND_2GHZ) + supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates >> 4) | + FIELD_PREP(RA_LEGACY_CCK, supp_rates & 0xf); + else + supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates); +#else + supp_rates = RA_LEGACY_OFDM; +#endif + + ra_info = mt7921_append_tlv(m, tlvnum, STA_REC_RA, + sizeof(*ra_info)); + ra_info->legacy = htole16(supp_rates); +#ifdef NOTYET + if (sta->deflink.ht_cap.ht_supported) + memcpy(ra_info->rx_mcs_bitmask, + sta->deflink.ht_cap.mcs.rx_mask, + HT_MCS_MASK_NUM); +#endif + + state = mt7921_append_tlv(m, tlvnum, STA_REC_STATE, sizeof(*state)); + state->state = /* XXX sta_state */ 0; +#ifdef NOTYET + if (sta->deflink.vht_cap.vht_supported) { + state->vht_opmode = sta->deflink.bandwidth; + state->vht_opmode |= (sta->deflink.rx_nss - 1) << + IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; + } +#endif +} + +int +mt7921_mcu_wtbl_generic_tlv(struct mbuf *m, uint16_t *tlvnum, + struct mwx_softc *sc, struct ieee80211_node *ni) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct wtbl_generic *generic; + struct wtbl_rx *rx; + + generic = mt7921_append_tlv(m, tlvnum, WTBL_GENERIC, + sizeof(*generic)); + + if (ni) { + generic->partial_aid = htole16(IEEE80211_AID(ni->ni_associd)); + memcpy(generic->peer_addr, ni->ni_macaddr, IEEE80211_ADDR_LEN); + generic->muar_idx = sc->sc_vif.omac_idx; + generic->qos = (ni->ni_flags & IEEE80211_NODE_QOS) != 0; + } else { + memset(generic->peer_addr, 0xff, IEEE80211_ADDR_LEN); + generic->muar_idx = 0xe; + } + + rx = mt7921_append_tlv(m, tlvnum, WTBL_RX, sizeof(*rx)); + rx->rca1 = ni ? ic->ic_opmode != IEEE80211_M_HOSTAP : 1; + rx->rca2 = 1; + rx->rv = 1; + + return sizeof(*generic) + sizeof(*rx); +} + +int +mt7921_mcu_wtbl_hdr_trans_tlv(struct mbuf *m, uint16_t *tlvnum, + struct mwx_softc *sc, struct ieee80211_node *ni) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct wtbl_hdr_trans *htr; + + htr = mt7921_append_tlv(m, tlvnum, WTBL_HDR_TRANS, sizeof(*htr)); + + /* no hdr decapsulation offload */ + htr->no_rx_trans = 1; + + if (ic->ic_opmode == IEEE80211_M_STA) + htr->to_ds = 1; + else + htr->from_ds = 1; + + return sizeof(*htr); +} + +int +mt7921_mcu_wtbl_ht_tlv(struct mbuf *m, uint16_t *tlvnum, + struct mwx_softc *sc, struct ieee80211_node *ni) +{ + struct wtbl_smps *smps; + + /* XXX lots missing here */ + + smps = mt7921_append_tlv(m, tlvnum, WTBL_SMPS, sizeof(*smps)); + /* spatial multiplexing power save mode, off for now */ + //smps->smps = (sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC); + + return sizeof(*smps); +} + +int +mt7921_mac_sta_update(struct mwx_softc *sc, struct ieee80211_node *ni, + int add, int new) +{ + struct mwx_node *mw = (struct mwx_node *)ni; + struct mwx_vif *mvif = &sc->sc_vif; + struct sta_req_hdr *hdr; + struct sta_rec_wtbl *wtbl; + struct mbuf *m = NULL; + uint16_t tlvnum = 0, wnum = 0; + int wlen = 0; + + m = mt7921_alloc_sta_tlv(sizeof(*hdr)); + if (m == NULL) + return ENOBUFS; + + if (ni != NULL) + mt7921_mcu_add_basic_tlv(m, &tlvnum, sc, ni, add, new); + + if (ni != NULL && add) + mt7921_mcu_add_sta_tlv(m, &tlvnum, sc, ni, add, new); + + wtbl = mt7921_append_tlv(m, &tlvnum, STA_REC_WTBL, + sizeof(*wtbl)); + wtbl->wlan_idx_lo = mw ? mw->wcid & 0xff : 0, + wtbl->wlan_idx_hi = mw ? mw->wcid >> 8 : 0, + wtbl->operation = WTBL_RESET_AND_SET; + + if (add) { + wlen += mt7921_mcu_wtbl_generic_tlv(m, &wnum, sc, ni); + wlen += mt7921_mcu_wtbl_hdr_trans_tlv(m, &wnum, sc, ni); + + if (ni) + wlen += mt7921_mcu_wtbl_ht_tlv(m, &wnum, sc, ni); + } + + wtbl->tlv_num = htole16(wnum); + wtbl->len = htole16(le16toh(wtbl->len) + wlen); + + KASSERT(m_leadingspace(m) >= sizeof(*hdr)); + m = m_prepend(m, sizeof(*hdr), M_DONTWAIT); + hdr = mtod(m, struct sta_req_hdr *); + memset(hdr, 0, sizeof(*hdr)); + hdr->bss_idx = mvif->idx, + hdr->wlan_idx_lo = mw ? mw->wcid & 0xff : 0, + hdr->wlan_idx_hi = mw ? mw->wcid >> 8 : 0, + hdr->muar_idx = ni ? mvif->omac_idx : 0, + hdr->is_tlv_append = 1, + hdr->tlv_num = htole16(tlvnum); + + return mwx_mcu_send_mbuf_wait(sc, MCU_UNI_CMD_STA_REC_UPDATE, m); +} + diff --git a/sys/dev/pci/if_mwxreg.h b/sys/dev/pci/if_mwxreg.h new file mode 100644 index 000000000..efa5e2d29 --- /dev/null +++ b/sys/dev/pci/if_mwxreg.h @@ -0,0 +1,1401 @@ +/* + * Copyright (c) 2022 Claudio Jeker + * Copyright (C) 2021 MediaTek Inc. + * Copyright (C) 2016 Felix Fietkau + * + * 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_TIMEOUT_CCK_DEF_VAL (231 | (41 << 16)) +#define MT_TIMEOUT_OFDM_DEF_VAL (60 | (28 << 16)) + +#define MT_TMAC_ICR0(_band) MT_BAND_ADDR(_band, 0x40a4) +#define MT_IFS_EIFS_MASK 0x0000001f +#define MT_IFS_EIFS_DEF 360 +#define MT_IFS_RIFS_MASK 0x00007c00 +#define MT_IFS_RIFS_DEF (2 << 10) +#define MT_IFS_SIFS_MASK 0x007f0000 +#define MT_IFS_SIFS_SHIFT 16 +#define MT_IFS_SLOT_MASK 0x7f000000 +#define MT_IFS_SLOT_SHIFT 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)) + +/* AGG: band 0(0x20800), band 1(0xa0800) */ +#define MT_AGG_ACR0(_band) MT_BAND_ADDR(_band, 0x2084) +#define MT_AGG_ACR_CFEND_RATE_MASK 0x00001fff +#define MT7921_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ +#define MT7921_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16) + +/* 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) + +/* ARB: band 0(0x20c00), band 1(0xa0c00) */ +#define MT_ARB_SCR(_band) MT_BAND_ADDR(_band, 0x3080) +#define MT_ARB_SCR_TX_DISABLE (1U << 8) +#define MT_ARB_SCR_RX_DISABLE (1U << 9) + +/* 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 +#define MT_PCIE_MAC_PM 0x10194 +#define MT_PCIE_MAC_PM_L0S_DIS (1U << 8) + +/* 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 + +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_BAND1, + MT_RXQ_BAND1_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 4 /* limit of MT_HW_TXP_MAX_BUF_NUM */ +#define MT_MAX_SIZE MT_DMA_CTL_SD_LEN_MASK + +#define MWX_WCID_MAX 288 +#define MWX_TXWI_MAX 512 /* HW limit is 8192 */ + +#define MT_PACKET_ID_MASK 0x7f +#define MT_PACKET_ID_NO_ACK 0 +#define MT_PACKET_ID_NO_SKB 1 +#define MT_PACKET_ID_WED 2 +#define MT_PACKET_ID_FIRST 3 +#define MT_PACKET_ID_HAS_RATE (1U << 7) + +struct mt76_desc { + volatile uint32_t buf0; + volatile uint32_t ctrl; + volatile uint32_t buf1; + volatile uint32_t info; +} __packed __aligned(4); + +struct mt76_connac_txp_ptr { + uint32_t buf0; + uint16_t len0; + uint16_t len1; + uint32_t buf1; +} __packed __aligned(4); + +#define MT_HW_TXP_MAX_MSDU_NUM 4 +#define MT_HW_TXP_MAX_BUF_NUM 4 +#define MT_TXD_SIZE (8 * sizeof(uint32_t)) + +#define MT_TXD_LEN_LAST (1U << 15) +#define MT_TXD_LEN_MASK 0x00000fff + +#define MT_MSDU_ID_VALID (1U << 15) + +struct mt76_txwi { + uint32_t txwi[8]; + + uint16_t msdu_id[MT_HW_TXP_MAX_MSDU_NUM]; + struct mt76_connac_txp_ptr ptr[MT_HW_TXP_MAX_BUF_NUM / 2]; +} __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 0x0004001c +#define MCU_CE_CMD_SET_EDCA_PARMS 0x0004001d +#define MCU_CE_CMD_SET_P2P_OPPPS 0x00040033 +#define MCU_CE_CMD_SET_CLC 0x0004005c +#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 + +/* values 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 + +#define MT_CTX0 0x0 +#define MT_HIF0 0x0 +#define MT_LMAC_AC00 0x0 +#define MT_LMAC_AC01 0x1 +#define MT_LMAC_AC02 0x2 +#define MT_LMAC_AC03 0x3 +#define MT_LMAC_ALTX0 0x10 +#define MT_LMAC_BMC0 0x11 +#define MT_LMAC_BCN0 0x12 +#define MT_LMAC_PSMP0 0x13 + +/* 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_MASK 0x3f000000 +#define MT_TXD1_OWN_MAC_SHIFT 24 +#define MT_TXD1_AMSDU (1U << 23) +#define MT_TXD1_TID_MASK 0x00700000 +#define MT_TXD1_TID(x) (((x) << 20) & MT_TXD1_TID_MASK) +#define MT_TXD1_HDR_PAD_MASK 0x000c0000 +#define MT_TXD1_HDR_PAD_SHIFT 18 +#define MT_TXD1_HDR_FORMAT_MASK 0x00030000 +#define MT_TXD1_HDR_FORMAT_SHIFT 16 +#define MT_TXD1_HDR_INFO_MASK 0x0000f800 +#define MT_TXD1_HDR_INFO(x) (((x) << 11) & MT_TXD1_HDR_INFO_MASK) +#define MT_TXD1_ETH_802_3 (1U << 15) +#define MT_TXD1_VTA (1U << 10) +#define MT_TXD1_WLAN_IDX_MASK 0x000003ff + +#define MT_TXD2_FIX_RATE (1U << 31) +#define MT_TXD2_FIXED_RATE (1U << 30) +#define MT_TXD2_POWER_OFFSET_MASK 0x3f000000 +#define MT_TXD2_POWER_OFFSET_SHIFT 24 +#define MT_TXD2_MAX_TX_TIME_MASK 0x00ff0000 +#define MT_TXD2_MAX_TX_TIME_SHIFT 16 +#define MT_TXD2_FRAG 0x0000c000 +#define MT_TXD2_HTC_VLD (1U << 13) +#define MT_TXD2_DURATION (1U << 12) +#define MT_TXD2_BIP (1U << 11) +#define MT_TXD2_MULTICAST (1U << 10) +#define MT_TXD2_RTS (1U << 9) +#define MT_TXD2_SOUNDING (1U << 8) +#define MT_TXD2_NDPA (1U << 7) +#define MT_TXD2_NDP (1U << 6) +#define MT_TXD2_FRAME_TYPE_MASK 0x00000030 +#define MT_TXD2_SUB_TYPE_MASK 0x0000000f +#define MT_TXD2_FRAME_TYPE(x) (((x) << 4) & MT_TXD2_FRAME_TYPE_MASK) +#define MT_TXD2_SUB_TYPE(x) ((x) & MT_TXD2_SUB_TYPE_MASK) + +#define MT_TXD3_SN_VALID (1U << 31) +#define MT_TXD3_PN_VALID (1U << 30) +#define MT_TXD3_SW_POWER_MGMT (1U << 29) +#define MT_TXD3_BA_DISABLE (1U << 28) +#define MT_TXD3_SEQ GENMASK(27, 16) +#define MT_TXD3_REM_TX_COUNT_MASK 0x0000f800 +#define MT_TXD3_REM_TX_COUNT_SHIFT 11 +#define MT_TXD3_TX_COUNT GENMASK(10, 6) +#define MT_TXD3_TIMING_MEASURE (1U << 5) +#define MT_TXD3_DAS (1U << 4) +#define MT_TXD3_EEOSP (1U << 3) +#define MT_TXD3_EMRD (1U << 2) +#define MT_TXD3_PROTECT_FRAME (1U << 1) +#define MT_TXD3_NO_ACK (1U << 0) + +#define MT_TXD4_PN_LOW_MASK 0xffffffff + +#define MT_TXD5_PN_HIGH 0xffff0000 +#define MT_TXD5_MD (1U << 15) +#define MT_TXD5_ADD_BA (1U << 14) +#define MT_TXD5_TX_STATUS_HOST (1U << 10) +#define MT_TXD5_TX_STATUS_MCU (1U << 9) +#define MT_TXD5_TX_STATUS_FMT (1U << 8) +#define MT_TXD5_PID 0x000000ff + +#define MT_TXD6_TX_IBF (1U << 31) +#define MT_TXD6_TX_EBF (1U << 30) +#define MT_TXD6_TX_RATE_MASK 0x3fff0000 +#define MT_TXD6_TX_RATE_SHIFT 16 +#define MT_TXD6_SGI 0x0000c000 +#define MT_TXD6_HELTF 0x00003000 +#define MT_TXD6_LDPC (1U << 11) +#define MT_TXD6_SPE_ID_IDX (1U << 10) +#define MT_TXD6_ANT_ID 0x000000f0 +#define MT_TXD6_DYN_BW (1U << 3) +#define MT_TXD6_FIXED_BW (1U << 2) +#define MT_TXD6_BW 0x00000003 + +#define MT_TXD7_TXD_LEN_MASK 0xc0000000 +#define MT_TXD7_UDP_TCP_SUM (1U << 29) +#define MT_TXD7_IP_SUM (1U << 28) +#define MT_TXD7_TYPE_MASK 0x00300000 +#define MT_TXD7_SUB_TYPE_MASK 0x000f0000 +#define MT_TXD7_TYPE(x) (((x) << 20) & MT_TXD7_TYPE_MASK) +#define MT_TXD7_SUB_TYPE(x) (((x) << 16) & MT_TXD7_SUB_TYPE_MASK) + +#define MT_TXD7_PSE_FID GENMASK(27, 16) +#define MT_TXD7_SPE_IDX GENMASK(15, 11) +#define MT_TXD7_HW_AMSDU (1U << 10) +#define MT_TXD7_TX_TIME 0x000003ff + +#define MT_TX_RATE_STBC (1U << 13) +#define MT_TX_RATE_NSS_MASK 0x00001c00 +#define MT_TX_RATE_NSS_SHIFT 10 +#define MT_TX_RATE_MODE_MASK 0x000003c0 +#define MT_TX_RATE_MODE_SHIFT 6 +#define MT_TX_RATE_SU_EXT_TONE (1U << 5) +#define MT_TX_RATE_DCM (1U << 4) +/* VHT/HE only use bits 0-3 */ +#define MT_TX_RATE_IDX_MASK 0x0000003f + + +#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_NUM_MASK 0x0000ff00 +#define MT_RXD3_NORMAL_CH_NUM_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]; +}; + +#define MT_SKU_POWER_LIMIT 161 + +struct mt76_connac_sku_tlv { + uint8_t channel; + int8_t pwr_limit[MT_SKU_POWER_LIMIT]; +} __packed; + +struct mt76_power_limits { + int8_t cck[4]; + int8_t ofdm[8]; + int8_t mcs[4][10]; + int8_t ru[7][12]; +}; + +#define MT_TX_PWR_BAND_2GHZ 1 +#define MT_TX_PWR_BAND_5GHZ 2 +#define MT_TX_PWR_BAND_6GHZ 3 + +struct mt76_connac_tx_power_limit_tlv { + /* DW0 - common info*/ + uint8_t ver; + uint8_t pad0; + uint16_t len; + /* DW1 - cmd hint */ + uint8_t n_chan; /* # channel */ + uint8_t band; /* 2.4GHz - 5GHz - 6GHz */ + uint8_t last_msg; + uint8_t pad1; + /* DW3 */ + uint8_t alpha2[4]; /* regulatory_request.alpha2 */ + uint8_t pad2[32]; +} __packed; + +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[IEEE80211_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[IEEE80211_ADDR_LEN]; + /* valid when BIT(1) in scan_func is set. */ + uint8_t random_mac[IEEE80211_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; + +/* STA_REC HEADER */ +struct sta_req_hdr { + uint8_t bss_idx; + uint8_t wlan_idx_lo; + uint16_t tlv_num; + uint8_t is_tlv_append; + uint8_t muar_idx; + uint8_t wlan_idx_hi; + uint8_t rsv; +} __packed; + +#define STA_REC_BASIC 0x00 +struct sta_rec_basic { + uint16_t tag; + uint16_t len; + uint32_t conn_type; + uint8_t conn_state; + uint8_t qos; + uint16_t aid; + uint8_t peer_addr[IEEE80211_ADDR_LEN]; +#define EXTRA_INFO_VER (1U << 0) +#define EXTRA_INFO_NEW (1U << 1) + uint16_t extra_info; +} __packed; + +#define STA_REC_RA 0x01 +#define HT_MCS_MASK_NUM 10 +struct sta_rec_ra_info { + uint16_t tag; + uint16_t len; + uint16_t legacy; + uint8_t rx_mcs_bitmask[HT_MCS_MASK_NUM]; +} __packed; +#define RA_LEGACY_OFDM 0x3fc0 +#define RA_LEGACY_CCK 0x000f + +#define STA_REC_STATE 0x07 +struct sta_rec_state { + uint16_t tag; + uint16_t len; + uint32_t flags; + uint8_t state; + uint8_t vht_opmode; + uint8_t action; + uint8_t rsv[1]; +} __packed; + +#define STA_REC_WTBL 0x0d +struct sta_rec_wtbl { + uint16_t tag; + uint16_t len; + uint8_t wlan_idx_lo; + uint8_t operation; + uint16_t tlv_num; + uint8_t wlan_idx_hi; + uint8_t rsv[3]; +} __packed; + +#define STA_REC_PHY 0x15 +struct sta_rec_phy { + uint16_t tag; + uint16_t len; + uint16_t basic_rate; + uint8_t phy_type; + uint8_t ampdu; + uint8_t rts_policy; + uint8_t rcpi; + uint8_t rsv[2]; +} __packed; + +/* WTBL REC */ +#define WTBL_RESET_AND_SET 1 +#define WTBL_SET 2 +#define WTBL_QUERY 3 +#define WTBL_RESET_ALL 4 + + +#define WTBL_GENERIC 0x00 +struct wtbl_generic { + uint16_t tag; + uint16_t len; + uint8_t peer_addr[IEEE80211_ADDR_LEN]; + uint8_t muar_idx; + uint8_t skip_tx; + uint8_t cf_ack; + uint8_t qos; + uint8_t mesh; + uint8_t adm; + uint16_t partial_aid; + uint8_t baf_en; + uint8_t aad_om; +} __packed; + +#define WTBL_RX 0x01 +struct wtbl_rx { + uint16_t tag; + uint16_t len; + uint8_t rcid; + uint8_t rca1; + uint8_t rca2; + uint8_t rv; + uint8_t rsv[4]; +} __packed; + +#define WTBL_HDR_TRANS 0x06 +struct wtbl_hdr_trans { + uint16_t tag; + uint16_t len; + uint8_t to_ds; + uint8_t from_ds; + uint8_t no_rx_trans; + uint8_t rsv; +} __packed; + +#define WTBL_SMPS 0x0d +struct wtbl_smps { + uint16_t tag; + uint16_t len; + uint8_t smps; + uint8_t rsv[3]; +} __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, +}; + +enum mt76_phy_type { + MT_PHY_TYPE_CCK, + MT_PHY_TYPE_OFDM, + MT_PHY_TYPE_HT, + MT_PHY_TYPE_HT_GF, + MT_PHY_TYPE_VHT, + MT_PHY_TYPE_HE_SU = 8, + MT_PHY_TYPE_HE_EXT_SU, + MT_PHY_TYPE_HE_TB, + MT_PHY_TYPE_HE_MU, + __MT_PHY_TYPE_HE_MAX, +}; + + +#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 CONN_STATE_DISCONNECT 0 +#define CONN_STATE_CONNECT 1 +#define CONN_STATE_PORT_SECURE 2 + +#define DEV_INFO_ACTIVE 0 + +#define PHY_TYPE_BIT_HR_DSSS (1U << 0) +#define PHY_TYPE_BIT_ERP (1U << 1) +#define PHY_TYPE_BIT_OFDM (1U << 3) +#define PHY_TYPE_BIT_HT (1U << 4) +#define PHY_TYPE_BIT_VHT (1U << 5) +#define PHY_TYPE_BIT_HE (1U << 6) + +#define rssi_to_rcpi(rssi) (2 * (rssi) + 220) +#define rcpi_to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index 5d1f9a7b8..ec675a233 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_mbuf.c,v 1.288 2023/10/20 16:25:15 bluhm Exp $ */ +/* $OpenBSD: uipc_mbuf.c,v 1.289 2024/02/21 09:28:29 claudio Exp $ */ /* $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $ */ /* @@ -550,21 +550,24 @@ int m_defrag(struct mbuf *m, int how) { struct mbuf *m0; + unsigned int adj; if (m->m_next == NULL) return (0); KASSERT(m->m_flags & M_PKTHDR); + adj = mtod(m, unsigned long) & (sizeof(long) - 1); if ((m0 = m_gethdr(how, m->m_type)) == NULL) return (ENOBUFS); - if (m->m_pkthdr.len > MHLEN) { - MCLGETL(m0, how, m->m_pkthdr.len); + if (m->m_pkthdr.len + adj > MHLEN) { + MCLGETL(m0, how, m->m_pkthdr.len + adj); if (!(m0->m_flags & M_EXT)) { m_free(m0); return (ENOBUFS); } } + m0->m_data += adj; m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t)); m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len; @@ -583,9 +586,9 @@ m_defrag(struct mbuf *m, int how) memcpy(&m->m_ext, &m0->m_ext, sizeof(struct mbuf_ext)); MCLINITREFERENCE(m); m->m_flags |= m0->m_flags & (M_EXT|M_EXTWR); - m->m_data = m->m_ext.ext_buf; + m->m_data = m->m_ext.ext_buf + adj; } else { - m->m_data = m->m_pktdat; + m->m_data = m->m_pktdat + adj; memcpy(m->m_data, m0->m_data, m0->m_len); } m->m_pkthdr.len = m->m_len = m0->m_len; diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index b0c76c2e7..866a65b1d 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mbuf.h,v 1.261 2023/07/16 03:01:31 yasuoka Exp $ */ +/* $OpenBSD: mbuf.h,v 1.262 2024/02/21 13:42:06 bluhm Exp $ */ /* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */ /* @@ -234,7 +234,7 @@ struct mbuf { ("\20\1IPV4_CSUM_OUT\2TCP_CSUM_OUT\3UDP_CSUM_OUT\4IPV4_CSUM_IN_OK" \ "\5IPV4_CSUM_IN_BAD\6TCP_CSUM_IN_OK\7TCP_CSUM_IN_BAD\10UDP_CSUM_IN_OK" \ "\11UDP_CSUM_IN_BAD\12ICMP_CSUM_OUT\13ICMP_CSUM_IN_OK\14ICMP_CSUM_IN_BAD" \ - "\15IPV6_NODF_OUT" "\16TIMESTAMP" "\17FLOWID") + "\15IPV6_NODF_OUT" "\16TIMESTAMP" "\17FLOWID" "\20TCP_TSO") #endif /* mbuf types */ diff --git a/sys/sys/siginfo.h b/sys/sys/siginfo.h index c10c1b43e..15e94e881 100644 --- a/sys/sys/siginfo.h +++ b/sys/sys/siginfo.h @@ -1,4 +1,4 @@ -/* $OpenBSD: siginfo.h,v 1.13 2022/10/25 16:08:26 kettenis Exp $ */ +/* $OpenBSD: siginfo.h,v 1.14 2024/02/21 15:53:07 deraadt Exp $ */ /* * Copyright (c) 1997 Theo de Raadt @@ -61,7 +61,8 @@ union sigval { #define ILL_PRVREG 6 /* privileged register */ #define ILL_COPROC 7 /* co-processor */ #define ILL_BADSTK 8 /* bad stack */ -#define NSIGILL 8 +#define ILL_BTCFI 9 /* IBT missing on indirect call */ +#define NSIGILL 9 #define EMT_TAGOVF 1 /* tag overflow */ #define NSIGEMT 1 diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c index dfd65decd..93d0c98b8 100644 --- a/sys/uvm/uvm_map.c +++ b/sys/uvm/uvm_map.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_map.c,v 1.326 2024/01/21 17:21:55 deraadt Exp $ */ +/* $OpenBSD: uvm_map.c,v 1.327 2024/02/21 03:28:29 deraadt Exp $ */ /* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */ /* @@ -4556,7 +4556,7 @@ uvm_map_clean(struct vm_map *map, vaddr_t start, vaddr_t end, int flags) struct vm_page *pg; struct uvm_object *uobj; vaddr_t cp_start, cp_end; - int refs; + int refs, imut = 0; int error; boolean_t rv; @@ -4572,10 +4572,8 @@ uvm_map_clean(struct vm_map *map, vaddr_t start, vaddr_t end, int flags) /* Make a first pass to check for various conditions. */ for (entry = first; entry != NULL && entry->start < end; entry = RBT_NEXT(uvm_map_addr, entry)) { - if (entry->etype & UVM_ET_IMMUTABLE) { - vm_map_unlock(map); - return EPERM; - } + if (entry->etype & UVM_ET_IMMUTABLE) + imut = 1; if (UVM_ET_ISSUBMAP(entry)) { vm_map_unlock(map); return EINVAL; @@ -4608,6 +4606,11 @@ uvm_map_clean(struct vm_map *map, vaddr_t start, vaddr_t end, int flags) if (amap == NULL || (flags & (PGO_DEACTIVATE|PGO_FREE)) == 0) goto flush_object; + if (imut) { + vm_map_unbusy(map); + return EPERM; + } + cp_start = MAX(entry->start, start); cp_end = MIN(entry->end, end); diff --git a/usr.bin/ctfconv/dw.c b/usr.bin/ctfconv/dw.c index e1ee7bf11..9ebe9d950 100644 --- a/usr.bin/ctfconv/dw.c +++ b/usr.bin/ctfconv/dw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dw.c,v 1.5 2021/10/25 19:54:29 kn Exp $ */ +/* $OpenBSD: dw.c,v 1.6 2024/02/21 13:16:14 claudio Exp $ */ /* * Copyright (c) 2016 Martin Pieuchot @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -184,6 +185,7 @@ const char * dw_at2name(uint64_t at) { static const char *dw_attrs[] = { DW_AT_NAMES }; + static char buf[64]; if (at <= nitems(dw_attrs)) return dw_attrs[at - 1]; @@ -193,7 +195,8 @@ dw_at2name(uint64_t at) if (at == DW_AT_hi_user) return "DW_AT_hi_user"; - return NULL; + snprintf(buf, sizeof(buf), "#%llu", at); + return buf; } const char * diff --git a/usr.bin/ctfconv/dwarf.h b/usr.bin/ctfconv/dwarf.h index 7da94aaeb..ecb788731 100644 --- a/usr.bin/ctfconv/dwarf.h +++ b/usr.bin/ctfconv/dwarf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dwarf.h,v 1.2 2017/08/11 14:58:56 jasper Exp $ */ +/* $OpenBSD: dwarf.h,v 1.3 2024/02/21 13:16:14 claudio Exp $ */ /* * Copyright (c) 2016 Martin Pieuchot @@ -273,6 +273,7 @@ #define DW_AT_const_expr 0x6c #define DW_AT_enum_class 0x6d #define DW_AT_linkage_name 0x6e +#define DW_AT_noreturn 0x87 #define DW_AT_lo_user 0x2000 #define DW_AT_hi_user 0x3fff @@ -413,6 +414,7 @@ "DW_AT_const_expr", \ "DW_AT_enum_class", \ "DW_AT_linkage_name", \ + [0x87 - 1] = "DW_AT_noreturn", \ #define DW_FORM_addr 0x01 #define DW_FORM_block2 0x03 diff --git a/usr.bin/ctfconv/parse.c b/usr.bin/ctfconv/parse.c index d74f95005..1b271c8d2 100644 --- a/usr.bin/ctfconv/parse.c +++ b/usr.bin/ctfconv/parse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.c,v 1.15 2022/12/26 18:43:49 jmc Exp $ */ +/* $OpenBSD: parse.c,v 1.19 2024/02/21 13:24:37 claudio Exp $ */ /* * Copyright (c) 2016-2017 Martin Pieuchot @@ -50,7 +50,11 @@ struct pool it_pool, im_pool, ir_pool; #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif -#define DPRINTF(x...) do { /*printf(x)*/ } while (0) +#ifdef DEBUG +#define DPRINTF(x...) do { printf(x); } while (0) +#else +#define DPRINTF(x...) do { ; } while (0) +#endif #define VOID_OFFSET 1 /* Fake offset for generating "void" type. */ @@ -329,6 +333,11 @@ it_cmp(struct itype *a, struct itype *b) (diff = (a->it_size - b->it_size) != 0)) return diff; + /* Arrays need to have same number of elements */ + if ((a->it_type == CTF_K_ARRAY) && + (diff = (a->it_nelems - b->it_nelems) != 0)) + return diff; + /* Match by name */ if (!(a->it_flags & ITF_ANON) && !(b->it_flags & ITF_ANON)) return strcmp(it_name(a), it_name(b)); @@ -341,7 +350,7 @@ it_cmp(struct itype *a, struct itype *b) if ((a->it_refp != NULL) && (b->it_refp != NULL)) return it_cmp(a->it_refp, b->it_refp); - return 1; + return 0; } int @@ -833,7 +842,7 @@ parse_refers(struct dwdie *die, size_t psz, int type) if (it->it_ref == 0 && (it->it_size == sizeof(void *) || type == CTF_K_CONST || type == CTF_K_VOLATILE || - type == CTF_K_POINTER)) { + type == CTF_K_POINTER || type == CTF_K_TYPEDEF)) { /* Work around GCC/clang not emiting a type for void */ it->it_flags &= ~ITF_UNRES; it->it_ref = VOID_OFFSET; @@ -1345,6 +1354,8 @@ dav2val(struct dwaval *dav, size_t psz) case DW_FORM_sdata: case DW_FORM_data8: case DW_FORM_ref8: + case DW_FORM_udata: + case DW_FORM_ref_udata: val = dav->dav_u64; break; case DW_FORM_strp: diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c index 6fa70cb7c..31eaa9500 100644 --- a/usr.bin/ssh/clientloop.c +++ b/usr.bin/ssh/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.402 2023/11/24 00:31:30 dtucker Exp $ */ +/* $OpenBSD: clientloop.c,v 1.403 2024/02/21 05:57:34 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -508,7 +508,7 @@ send_chaff(struct ssh *ssh) { int r; - if ((ssh->kex->flags & KEX_HAS_PING) == 0) + if (ssh->kex == NULL || (ssh->kex->flags & KEX_HAS_PING) == 0) return 0; /* XXX probabilistically send chaff? */ /* diff --git a/usr.bin/ssh/ssh_config.5 b/usr.bin/ssh/ssh_config.5 index 19a2402dc..165ba75f9 100644 --- a/usr.bin/ssh/ssh_config.5 +++ b/usr.bin/ssh/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.393 2024/01/10 06:33:13 jmc Exp $ -.Dd $Mdocdate: January 10 2024 $ +.\" $OpenBSD: ssh_config.5,v 1.394 2024/02/21 06:01:13 djm Exp $ +.Dd $Mdocdate: February 21 2024 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -144,7 +144,7 @@ The available criteria keywords are: .Cm localnetwork , .Cm host , .Cm originalhost , -.Cm Tag , +.Cm tagged , .Cm user , and .Cm localuser . diff --git a/usr.bin/ssh/sshd_config.5 b/usr.bin/ssh/sshd_config.5 index 0cc1fd719..93afc3eeb 100644 --- a/usr.bin/ssh/sshd_config.5 +++ b/usr.bin/ssh/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.352 2024/01/10 06:33:13 jmc Exp $ -.Dd $Mdocdate: January 10 2024 $ +.\" $OpenBSD: sshd_config.5,v 1.355 2024/02/21 06:17:29 djm Exp $ +.Dd $Mdocdate: February 21 2024 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -486,7 +486,7 @@ to after authentication. At session startup .Xr sshd 8 checks that all components of the pathname are root-owned directories -which are not writable by any other user or group. +which are not writable by group or others. After the chroot, .Xr sshd 8 changes the working directory to the user's home directory. @@ -1127,7 +1127,8 @@ DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. Logging with a DEBUG level violates the privacy of users and is not recommended. .It Cm LogVerbose -Specify one or more overrides to LogLevel. +Specify one or more overrides to +.Cm LogLevel . An override consists of a pattern lists that matches the source file, function and line number to force detailed logging for. For example, an override pattern of: @@ -1792,6 +1793,14 @@ implements an in-process SFTP server. This may simplify configurations using .Cm ChrootDirectory to force a different filesystem root on clients. +It accepts the same command line arguments as +.Cm sftp-server +and even though it is in-process, settings such as +.Cm LogLevel +or +.Cm SyslogFacility +do not apply to it and must be set explicitly via +command line arguments. .Pp By default no subsystems are defined. .It Cm SyslogFacility diff --git a/usr.sbin/ntpd/ntp.c b/usr.sbin/ntpd/ntp.c index a0984e943..178d51ec3 100644 --- a/usr.sbin/ntpd/ntp.c +++ b/usr.sbin/ntpd/ntp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ntp.c,v 1.173 2024/02/08 00:15:53 jsg Exp $ */ +/* $OpenBSD: ntp.c,v 1.174 2024/02/21 03:31:28 deraadt Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -596,7 +596,7 @@ ntp_dispatch_imsg_dns(void) dlen = imsg.hdr.len - IMSG_HEADER_SIZE; if (dlen == 0) { /* no data -> temp error */ - log_warnx("DNS lookup tempfail"); + log_debug("DNS lookup tempfail"); peer->state = STATE_DNS_TEMPFAIL; if (conf->tmpfail++ == TRIES_AUTO_DNSFAIL) priv_settime(0, "of dns failures"); diff --git a/usr.sbin/rpki-client/aspa.c b/usr.sbin/rpki-client/aspa.c index 294c45b54..6ec63b6fb 100644 --- a/usr.sbin/rpki-client/aspa.c +++ b/usr.sbin/rpki-client/aspa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aspa.c,v 1.27 2024/02/16 15:13:49 tb Exp $ */ +/* $OpenBSD: aspa.c,v 1.28 2024/02/21 09:17:06 tb Exp $ */ /* * Copyright (c) 2022 Job Snijders * Copyright (c) 2022 Theo Buehler @@ -32,14 +32,6 @@ #include "extern.h" -/* - * Parse results and data of the ASPA object. - */ -struct parse { - const char *fn; /* ASPA file name */ - struct aspa *res; /* results */ -}; - extern ASN1_OBJECT *aspa_oid; /* @@ -68,26 +60,26 @@ IMPLEMENT_ASN1_FUNCTIONS(ASProviderAttestation); * Return zero on failure, non-zero on success. */ static int -aspa_parse_providers(struct parse *p, const STACK_OF(ASN1_INTEGER) *providers) +aspa_parse_providers(const char *fn, struct aspa *aspa, + const STACK_OF(ASN1_INTEGER) *providers) { const ASN1_INTEGER *pa; uint32_t provider; size_t providersz, i; if ((providersz = sk_ASN1_INTEGER_num(providers)) == 0) { - warnx("%s: ASPA: ProviderASSet needs at least one entry", - p->fn); + warnx("%s: ASPA: ProviderASSet needs at least one entry", fn); return 0; } if (providersz >= MAX_ASPA_PROVIDERS) { - warnx("%s: ASPA: too many providers (more than %d)", p->fn, + warnx("%s: ASPA: too many providers (more than %d)", fn, MAX_ASPA_PROVIDERS); return 0; } - p->res->providers = calloc(providersz, sizeof(provider)); - if (p->res->providers == NULL) + aspa->providers = calloc(providersz, sizeof(provider)); + if (aspa->providers == NULL) err(1, NULL); for (i = 0; i < providersz; i++) { @@ -96,29 +88,29 @@ aspa_parse_providers(struct parse *p, const STACK_OF(ASN1_INTEGER) *providers) memset(&provider, 0, sizeof(provider)); if (!as_id_parse(pa, &provider)) { - warnx("%s: ASPA: malformed ProviderAS", p->fn); + warnx("%s: ASPA: malformed ProviderAS", fn); return 0; } - if (p->res->custasid == provider) { + if (aspa->custasid == provider) { warnx("%s: ASPA: CustomerASID can't also be Provider", - p->fn); + fn); return 0; } if (i > 0) { - if (p->res->providers[i - 1] > provider) { + if (aspa->providers[i - 1] > provider) { warnx("%s: ASPA: invalid ProviderASSet order", - p->fn); + fn); return 0; } - if (p->res->providers[i - 1] == provider) { - warnx("%s: ASPA: duplicate ProviderAS", p->fn); + if (aspa->providers[i - 1] == provider) { + warnx("%s: ASPA: duplicate ProviderAS", fn); return 0; } } - p->res->providers[p->res->providersz++] = provider; + aspa->providers[aspa->providersz++] = provider; } return 1; @@ -129,7 +121,8 @@ aspa_parse_providers(struct parse *p, const STACK_OF(ASN1_INTEGER) *providers) * Returns zero on failure, non-zero on success. */ static int -aspa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) +aspa_parse_econtent(const char *fn, struct aspa *aspa, const unsigned char *d, + size_t dsz) { const unsigned char *oder; ASProviderAttestation *aspa_asn1; @@ -137,24 +130,24 @@ aspa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) oder = d; if ((aspa_asn1 = d2i_ASProviderAttestation(NULL, &d, dsz)) == NULL) { - warnx("%s: ASPA: failed to parse ASProviderAttestation", p->fn); + warnx("%s: ASPA: failed to parse ASProviderAttestation", fn); goto out; } if (d != oder + dsz) { - warnx("%s: %td bytes trailing garbage in eContent", p->fn, + warnx("%s: %td bytes trailing garbage in eContent", fn, oder + dsz - d); goto out; } - if (!valid_econtent_version(p->fn, aspa_asn1->version, 1)) + if (!valid_econtent_version(fn, aspa_asn1->version, 1)) goto out; - if (!as_id_parse(aspa_asn1->customerASID, &p->res->custasid)) { - warnx("%s: malformed CustomerASID", p->fn); + if (!as_id_parse(aspa_asn1->customerASID, &aspa->custasid)) { + warnx("%s: malformed CustomerASID", fn); goto out; } - if (!aspa_parse_providers(p, aspa_asn1->providers)) + if (!aspa_parse_providers(fn, aspa, aspa_asn1->providers)) goto out; rc = 1; @@ -171,36 +164,33 @@ struct aspa * aspa_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, size_t len) { - struct parse p; + struct aspa *aspa; size_t cmsz; unsigned char *cms; struct cert *cert = NULL; time_t signtime = 0; int rc = 0; - memset(&p, 0, sizeof(struct parse)); - p.fn = fn; - cms = cms_parse_validate(x509, fn, der, len, aspa_oid, &cmsz, &signtime); if (cms == NULL) return NULL; - if ((p.res = calloc(1, sizeof(*p.res))) == NULL) + if ((aspa = calloc(1, sizeof(*aspa))) == NULL) err(1, NULL); - p.res->signtime = signtime; + aspa->signtime = signtime; - if (!x509_get_aia(*x509, fn, &p.res->aia)) + if (!x509_get_aia(*x509, fn, &aspa->aia)) goto out; - if (!x509_get_aki(*x509, fn, &p.res->aki)) + if (!x509_get_aki(*x509, fn, &aspa->aki)) goto out; - if (!x509_get_sia(*x509, fn, &p.res->sia)) + if (!x509_get_sia(*x509, fn, &aspa->sia)) goto out; - if (!x509_get_ski(*x509, fn, &p.res->ski)) + if (!x509_get_ski(*x509, fn, &aspa->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || - p.res->ski == NULL) { + if (aspa->aia == NULL || aspa->aki == NULL || aspa->sia == NULL || + aspa->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI, SIA, or SKI X509 extension", fn); goto out; @@ -211,9 +201,9 @@ aspa_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, goto out; } - if (!x509_get_notbefore(*x509, fn, &p.res->notbefore)) + if (!x509_get_notbefore(*x509, fn, &aspa->notbefore)) goto out; - if (!x509_get_notafter(*x509, fn, &p.res->notafter)) + if (!x509_get_notafter(*x509, fn, &aspa->notafter)) goto out; if (x509_any_inherits(*x509)) { @@ -221,25 +211,25 @@ aspa_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, goto out; } - if (!aspa_parse_econtent(cms, cmsz, &p)) + if (!aspa_parse_econtent(fn, aspa, cms, cmsz)) goto out; if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) goto out; - p.res->valid = valid_aspa(fn, cert, p.res); + aspa->valid = valid_aspa(fn, cert, aspa); rc = 1; out: if (rc == 0) { - aspa_free(p.res); - p.res = NULL; + aspa_free(aspa); + aspa = NULL; X509_free(*x509); *x509 = NULL; } cert_free(cert); free(cms); - return p.res; + return aspa; } /* diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index 2eb167dc2..10235441c 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.204 2024/02/16 05:18:29 tb Exp $ */ +/* $OpenBSD: extern.h,v 1.207 2024/02/21 12:48:25 tb Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -652,7 +652,6 @@ void takey_free(struct takey *); void tak_free(struct tak *); struct tak *tak_parse(X509 **, const char *, int, const unsigned char *, size_t); -struct tak *tak_read(struct ibuf *); void aspa_buffer(struct ibuf *, const struct aspa *); void aspa_free(struct aspa *); @@ -703,16 +702,15 @@ int cms_parse_validate_detached(X509 **, const char *, /* Work with RFC 3779 IP addresses, prefixes, ranges. */ int ip_addr_afi_parse(const char *, const ASN1_OCTET_STRING *, - enum afi *); + enum afi *); int ip_addr_parse(const ASN1_BIT_STRING *, - enum afi, const char *, struct ip_addr *); + enum afi, const char *, struct ip_addr *); void ip_addr_print(const struct ip_addr *, enum afi, char *, - size_t); -int ip_addr_cmp(const struct ip_addr *, const struct ip_addr *); + size_t); int ip_addr_check_overlap(const struct cert_ip *, - const char *, const struct cert_ip *, size_t, int); + const char *, const struct cert_ip *, size_t, int); int ip_addr_check_covered(enum afi, const unsigned char *, - const unsigned char *, const struct cert_ip *, size_t); + const unsigned char *, const struct cert_ip *, size_t); int ip_cert_compose_ranges(struct cert_ip *); void ip_roa_compose_ranges(struct roa_ip *); void ip_warn(const char *, const char *, const struct cert_ip *); @@ -729,9 +727,9 @@ int sbgp_parse_ipaddrblk(const char *, const IPAddrBlocks *, int as_id_parse(const ASN1_INTEGER *, uint32_t *); int as_check_overlap(const struct cert_as *, const char *, - const struct cert_as *, size_t, int); + const struct cert_as *, size_t, int); int as_check_covered(uint32_t, uint32_t, - const struct cert_as *, size_t); + const struct cert_as *, size_t); void as_warn(const char *, const char *, const struct cert_as *); int sbgp_as_id(const char *, struct cert_as *, size_t *, @@ -904,9 +902,10 @@ int output_json(FILE *, struct vrp_tree *, struct brk_tree *, int output_ometric(FILE *, struct vrp_tree *, struct brk_tree *, struct vap_tree *, struct stats *); -void logx(const char *fmt, ...) +void logx(const char *fmt, ...) __attribute__((format(printf, 1, 2))); -time_t getmonotime(void); +time_t getmonotime(void); +time_t get_current_time(void); int mkpath(const char *); int mkpathat(int, const char *); @@ -958,12 +957,4 @@ int mkpathat(int, const char *); /* Maximum number of delegated hosting locations (repositories) for each TAL. */ #define MAX_REPO_PER_TAL 1000 -/* - * Time - Evaluation time is used as the current time if it is - * larger than X509_TIME_MIN, otherwise the system time is used. - */ -#define X509_TIME_MAX 253402300799LL -#define X509_TIME_MIN -62167219200LL -extern time_t get_current_time(void); - #endif /* ! EXTERN_H */ diff --git a/usr.sbin/rpki-client/gbr.c b/usr.sbin/rpki-client/gbr.c index fab3c5a25..81c7747d8 100644 --- a/usr.sbin/rpki-client/gbr.c +++ b/usr.sbin/rpki-client/gbr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gbr.c,v 1.29 2023/10/13 12:06:49 job Exp $ */ +/* $OpenBSD: gbr.c,v 1.30 2024/02/21 09:17:06 tb Exp $ */ /* * Copyright (c) 2020 Claudio Jeker * @@ -24,14 +24,6 @@ #include "extern.h" -/* - * Parse results and data of the manifest file. - */ -struct parse { - const char *fn; /* manifest file name */ - struct gbr *res; /* results */ -}; - extern ASN1_OBJECT *gbr_oid; /* @@ -43,44 +35,41 @@ struct gbr * gbr_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, size_t len) { - struct parse p; + struct gbr *gbr; struct cert *cert = NULL; size_t cmsz; unsigned char *cms; time_t signtime = 0; - memset(&p, 0, sizeof(struct parse)); - p.fn = fn; - cms = cms_parse_validate(x509, fn, der, len, gbr_oid, &cmsz, &signtime); if (cms == NULL) return NULL; - if ((p.res = calloc(1, sizeof(*p.res))) == NULL) + if ((gbr = calloc(1, sizeof(*gbr))) == NULL) err(1, NULL); - p.res->signtime = signtime; - if ((p.res->vcard = strndup(cms, cmsz)) == NULL) + gbr->signtime = signtime; + if ((gbr->vcard = strndup(cms, cmsz)) == NULL) err(1, NULL); free(cms); - if (!x509_get_aia(*x509, fn, &p.res->aia)) + if (!x509_get_aia(*x509, fn, &gbr->aia)) goto out; - if (!x509_get_aki(*x509, fn, &p.res->aki)) + if (!x509_get_aki(*x509, fn, &gbr->aki)) goto out; - if (!x509_get_sia(*x509, fn, &p.res->sia)) + if (!x509_get_sia(*x509, fn, &gbr->sia)) goto out; - if (!x509_get_ski(*x509, fn, &p.res->ski)) + if (!x509_get_ski(*x509, fn, &gbr->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || - p.res->ski == NULL) { + if (gbr->aia == NULL || gbr->aki == NULL || gbr->sia == NULL || + gbr->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI, SIA or SKI X509 extension", fn); goto out; } - if (!x509_get_notbefore(*x509, fn, &p.res->notbefore)) + if (!x509_get_notbefore(*x509, fn, &gbr->notbefore)) goto out; - if (!x509_get_notafter(*x509, fn, &p.res->notafter)) + if (!x509_get_notafter(*x509, fn, &gbr->notafter)) goto out; if (!x509_inherits(*x509)) { @@ -91,10 +80,10 @@ gbr_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) goto out; - return p.res; + return gbr; out: - gbr_free(p.res); + gbr_free(gbr); X509_free(*x509); *x509 = NULL; cert_free(cert); diff --git a/usr.sbin/rpki-client/geofeed.c b/usr.sbin/rpki-client/geofeed.c index 4cde5ceae..f7d321fa3 100644 --- a/usr.sbin/rpki-client/geofeed.c +++ b/usr.sbin/rpki-client/geofeed.c @@ -1,4 +1,4 @@ -/* $OpenBSD: geofeed.c,v 1.15 2023/10/13 12:06:49 job Exp $ */ +/* $OpenBSD: geofeed.c,v 1.16 2024/02/21 09:17:06 tb Exp $ */ /* * Copyright (c) 2022 Job Snijders * Copyright (c) 2019 Kristaps Dzonsons @@ -31,11 +31,6 @@ #include "extern.h" -struct parse { - const char *fn; - struct geofeed *res; -}; - extern ASN1_OBJECT *geofeed_oid; /* @@ -43,7 +38,7 @@ extern ASN1_OBJECT *geofeed_oid; * Returns 1 on success, 0 on failure. */ static int -geofeed_parse_geoip(struct geofeed *res, char *cidr, char *loc) +geofeed_parse_geoip(struct geofeed *geofeed, char *cidr, char *loc) { struct geoip *geoip; struct ip_addr *ipaddr; @@ -73,11 +68,11 @@ geofeed_parse_geoip(struct geofeed *res, char *cidr, char *loc) ipaddr->prefixlen = plen; - res->geoips = recallocarray(res->geoips, res->geoipsz, - res->geoipsz + 1, sizeof(struct geoip)); - if (res->geoips == NULL) + geofeed->geoips = recallocarray(geofeed->geoips, geofeed->geoipsz, + geofeed->geoipsz + 1, sizeof(struct geoip)); + if (geofeed->geoips == NULL) err(1, NULL); - geoip = &res->geoips[res->geoipsz++]; + geoip = &geofeed->geoips[geofeed->geoipsz++]; if ((geoip->ip = calloc(1, sizeof(struct cert_ip))) == NULL) err(1, NULL); @@ -102,7 +97,7 @@ geofeed_parse_geoip(struct geofeed *res, char *cidr, char *loc) struct geofeed * geofeed_parse(X509 **x509, const char *fn, int talid, char *buf, size_t len) { - struct parse p; + struct geofeed *geofeed; char *delim, *line, *loc, *nl; ssize_t linelen; BIO *bio; @@ -118,10 +113,7 @@ geofeed_parse(X509 **x509, const char *fn, int talid, char *buf, size_t len) if (bio == NULL) errx(1, "BIO_new"); - memset(&p, 0, sizeof(struct parse)); - p.fn = fn; - - if ((p.res = calloc(1, sizeof(struct geofeed))) == NULL) + if ((geofeed = calloc(1, sizeof(*geofeed))) == NULL) err(1, NULL); while ((nl = memchr(buf, '\n', len)) != NULL) { @@ -217,7 +209,7 @@ geofeed_parse(X509 **x509, const char *fn, int talid, char *buf, size_t len) loc = ""; /* read each prefix */ - if (!geofeed_parse_geoip(p.res, line, loc)) + if (!geofeed_parse_geoip(geofeed, line, loc)) goto out; } @@ -232,24 +224,25 @@ geofeed_parse(X509 **x509, const char *fn, int talid, char *buf, size_t len) } if (!cms_parse_validate_detached(x509, fn, der, dersz, geofeed_oid, - bio, &p.res->signtime)) + bio, &geofeed->signtime)) goto out; - if (!x509_get_aia(*x509, fn, &p.res->aia)) + if (!x509_get_aia(*x509, fn, &geofeed->aia)) goto out; - if (!x509_get_aki(*x509, fn, &p.res->aki)) + if (!x509_get_aki(*x509, fn, &geofeed->aki)) goto out; - if (!x509_get_ski(*x509, fn, &p.res->ski)) + if (!x509_get_ski(*x509, fn, &geofeed->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { + if (geofeed->aia == NULL || geofeed->aki == NULL || + geofeed->ski == NULL) { warnx("%s: missing AIA, AKI, or SKI X509 extension", fn); goto out; } - if (!x509_get_notbefore(*x509, fn, &p.res->notbefore)) + if (!x509_get_notbefore(*x509, fn, &geofeed->notbefore)) goto out; - if (!x509_get_notafter(*x509, fn, &p.res->notafter)) + if (!x509_get_notafter(*x509, fn, &geofeed->notafter)) goto out; if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) @@ -265,13 +258,13 @@ geofeed_parse(X509 **x509, const char *fn, int talid, char *buf, size_t len) goto out; } - p.res->valid = valid_geofeed(fn, cert, p.res); + geofeed->valid = valid_geofeed(fn, cert, geofeed); rc = 1; out: if (rc == 0) { - geofeed_free(p.res); - p.res = NULL; + geofeed_free(geofeed); + geofeed = NULL; X509_free(*x509); *x509 = NULL; } @@ -280,7 +273,7 @@ geofeed_parse(X509 **x509, const char *fn, int talid, char *buf, size_t len) free(b64); free(der); - return p.res; + return geofeed; } /* diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c index 67eea26e4..6f51e0fac 100644 --- a/usr.sbin/rpki-client/main.c +++ b/usr.sbin/rpki-client/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.249 2024/02/16 11:55:42 tb Exp $ */ +/* $OpenBSD: main.c,v 1.250 2024/02/21 12:48:25 tb Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -74,6 +74,11 @@ int rrdpon = 1; int repo_timeout; time_t deadline; +/* 9999-12-31 23:59:59 UTC */ +#define X509_TIME_MAX 253402300799LL +/* 0000-01-01 00:00:00 UTC */ +#define X509_TIME_MIN -62167219200LL + int64_t evaluation_time = X509_TIME_MIN; struct stats stats; @@ -113,6 +118,18 @@ getmonotime(void) return (ts.tv_sec); } +/* + * Time - Evaluation time is used as the current time if it is + * larger than X509_TIME_MIN, otherwise the system time is used. + */ +time_t +get_current_time(void) +{ + if (evaluation_time > X509_TIME_MIN) + return (time_t)evaluation_time; + return time(NULL); +} + void entity_free(struct entity *ent) { @@ -126,14 +143,6 @@ entity_free(struct entity *ent) free(ent); } -time_t -get_current_time(void) -{ - if (evaluation_time > X509_TIME_MIN) - return (time_t)evaluation_time; - return time(NULL); -} - /* * Read a queue entity from the descriptor. * Matched by entity_write_req(). diff --git a/usr.sbin/rpki-client/mft.c b/usr.sbin/rpki-client/mft.c index 59285ca33..bc3fb930b 100644 --- a/usr.sbin/rpki-client/mft.c +++ b/usr.sbin/rpki-client/mft.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mft.c,v 1.110 2024/02/16 15:18:08 tb Exp $ */ +/* $OpenBSD: mft.c,v 1.111 2024/02/21 09:17:06 tb Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2019 Kristaps Dzonsons @@ -34,15 +34,6 @@ #include "extern.h" -/* - * Parse results and data of the manifest file. - */ -struct parse { - const char *fn; /* manifest file name */ - struct mft *res; /* result object */ - int found_crl; -}; - extern ASN1_OBJECT *mft_oid; /* @@ -183,7 +174,8 @@ rtype_from_mftfile(const char *fn) * Return zero on failure, non-zero on success. */ static int -mft_parse_filehash(struct parse *p, const FileAndHash *fh) +mft_parse_filehash(const char *fn, struct mft *mft, const FileAndHash *fh, + int *found_crl) { char *file = NULL; int rc = 0; @@ -192,7 +184,7 @@ mft_parse_filehash(struct parse *p, const FileAndHash *fh) size_t new_idx = 0; if (!valid_mft_filename(fh->file->data, fh->file->length)) { - warnx("%s: RFC 6486 section 4.2.2: bad filename", p->fn); + warnx("%s: RFC 6486 section 4.2.2: bad filename", fn); goto out; } file = strndup(fh->file->data, fh->file->length); @@ -201,25 +193,24 @@ mft_parse_filehash(struct parse *p, const FileAndHash *fh) if (fh->hash->length != SHA256_DIGEST_LENGTH) { warnx("%s: RFC 6486 section 4.2.1: hash: " - "invalid SHA256 length, have %d", - p->fn, fh->hash->length); + "invalid SHA256 length, have %d", fn, fh->hash->length); goto out; } type = rtype_from_mftfile(file); /* remember the filehash for the CRL in struct mft */ - if (type == RTYPE_CRL && strcmp(file, p->res->crl) == 0) { - memcpy(p->res->crlhash, fh->hash->data, SHA256_DIGEST_LENGTH); - p->found_crl = 1; + if (type == RTYPE_CRL && strcmp(file, mft->crl) == 0) { + memcpy(mft->crlhash, fh->hash->data, SHA256_DIGEST_LENGTH); + *found_crl = 1; } if (filemode) - fent = &p->res->files[p->res->filesz++]; + fent = &mft->files[mft->filesz++]; else { /* Fisher-Yates shuffle */ - new_idx = arc4random_uniform(p->res->filesz + 1); - p->res->files[p->res->filesz++] = p->res->files[new_idx]; - fent = &p->res->files[new_idx]; + new_idx = arc4random_uniform(mft->filesz + 1); + mft->files[mft->filesz++] = mft->files[new_idx]; + fent = &mft->files[new_idx]; } fent->type = type; @@ -308,30 +299,30 @@ mft_has_unique_names_and_hashes(const char *fn, const Manifest *mft) * Returns 0 on failure and 1 on success. */ static int -mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) +mft_parse_econtent(const char *fn, struct mft *mft, const unsigned char *d, + size_t dsz) { const unsigned char *oder; Manifest *mft_asn1; FileAndHash *fh; - int i, rc = 0; + int found_crl, i, rc = 0; oder = d; if ((mft_asn1 = d2i_Manifest(NULL, &d, dsz)) == NULL) { - warnx("%s: RFC 6486 section 4: failed to parse Manifest", - p->fn); + warnx("%s: RFC 6486 section 4: failed to parse Manifest", fn); goto out; } if (d != oder + dsz) { - warnx("%s: %td bytes trailing garbage in eContent", p->fn, + warnx("%s: %td bytes trailing garbage in eContent", fn, oder + dsz - d); goto out; } - if (!valid_econtent_version(p->fn, mft_asn1->version, 0)) + if (!valid_econtent_version(fn, mft_asn1->version, 0)) goto out; - p->res->seqnum = x509_convert_seqnum(p->fn, mft_asn1->manifestNumber); - if (p->res->seqnum == NULL) + mft->seqnum = x509_convert_seqnum(fn, mft_asn1->manifestNumber); + if (mft->seqnum == NULL) goto out; /* @@ -339,60 +330,61 @@ mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) * which doesn't conform to RFC 5280. So, double check. */ if (ASN1_STRING_length(mft_asn1->thisUpdate) != GENTIME_LENGTH) { - warnx("%s: embedded from time format invalid", p->fn); + warnx("%s: embedded from time format invalid", fn); goto out; } if (ASN1_STRING_length(mft_asn1->nextUpdate) != GENTIME_LENGTH) { - warnx("%s: embedded until time format invalid", p->fn); + warnx("%s: embedded until time format invalid", fn); goto out; } - if (!x509_get_time(mft_asn1->thisUpdate, &p->res->thisupdate)) { - warn("%s: parsing manifest thisUpdate failed", p->fn); + if (!x509_get_time(mft_asn1->thisUpdate, &mft->thisupdate)) { + warn("%s: parsing manifest thisUpdate failed", fn); goto out; } - if (!x509_get_time(mft_asn1->nextUpdate, &p->res->nextupdate)) { - warn("%s: parsing manifest nextUpdate failed", p->fn); + if (!x509_get_time(mft_asn1->nextUpdate, &mft->nextupdate)) { + warn("%s: parsing manifest nextUpdate failed", fn); goto out; } - if (p->res->thisupdate > p->res->nextupdate) { - warnx("%s: bad update interval", p->fn); + if (mft->thisupdate > mft->nextupdate) { + warnx("%s: bad update interval", fn); goto out; } if (OBJ_obj2nid(mft_asn1->fileHashAlg) != NID_sha256) { warnx("%s: RFC 6486 section 4.2.1: fileHashAlg: " - "want SHA256 object, have %s (NID %d)", p->fn, + "want SHA256 object, have %s (NID %d)", fn, ASN1_tag2str(OBJ_obj2nid(mft_asn1->fileHashAlg)), OBJ_obj2nid(mft_asn1->fileHashAlg)); goto out; } if (sk_FileAndHash_num(mft_asn1->fileList) >= MAX_MANIFEST_ENTRIES) { - warnx("%s: %d exceeds manifest entry limit (%d)", p->fn, + warnx("%s: %d exceeds manifest entry limit (%d)", fn, sk_FileAndHash_num(mft_asn1->fileList), MAX_MANIFEST_ENTRIES); goto out; } - p->res->files = calloc(sk_FileAndHash_num(mft_asn1->fileList), + mft->files = calloc(sk_FileAndHash_num(mft_asn1->fileList), sizeof(struct mftfile)); - if (p->res->files == NULL) + if (mft->files == NULL) err(1, NULL); + found_crl = 0; for (i = 0; i < sk_FileAndHash_num(mft_asn1->fileList); i++) { fh = sk_FileAndHash_value(mft_asn1->fileList, i); - if (!mft_parse_filehash(p, fh)) + if (!mft_parse_filehash(fn, mft, fh, &found_crl)) goto out; } - if (!p->found_crl) { - warnx("%s: CRL not part of MFT fileList", p->fn); + if (!found_crl) { + warnx("%s: CRL not part of MFT fileList", fn); goto out; } - if (!mft_has_unique_names_and_hashes(p->fn, mft_asn1)) + if (!mft_has_unique_names_and_hashes(fn, mft_asn1)) goto out; rc = 1; @@ -409,7 +401,7 @@ struct mft * mft_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, size_t len) { - struct parse p; + struct mft *mft; struct cert *cert = NULL; int rc = 0; size_t cmsz; @@ -417,28 +409,25 @@ mft_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, char *crldp = NULL, *crlfile; time_t signtime = 0; - memset(&p, 0, sizeof(struct parse)); - p.fn = fn; - cms = cms_parse_validate(x509, fn, der, len, mft_oid, &cmsz, &signtime); if (cms == NULL) return NULL; assert(*x509 != NULL); - if ((p.res = calloc(1, sizeof(struct mft))) == NULL) + if ((mft = calloc(1, sizeof(*mft))) == NULL) err(1, NULL); - p.res->signtime = signtime; + mft->signtime = signtime; - if (!x509_get_aia(*x509, fn, &p.res->aia)) + if (!x509_get_aia(*x509, fn, &mft->aia)) goto out; - if (!x509_get_aki(*x509, fn, &p.res->aki)) + if (!x509_get_aki(*x509, fn, &mft->aki)) goto out; - if (!x509_get_sia(*x509, fn, &p.res->sia)) + if (!x509_get_sia(*x509, fn, &mft->sia)) goto out; - if (!x509_get_ski(*x509, fn, &p.res->ski)) + if (!x509_get_ski(*x509, fn, &mft->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || - p.res->ski == NULL) { + if (mft->aia == NULL || mft->aki == NULL || mft->sia == NULL || + mft->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI, SIA, or SKI X509 extension", fn); goto out; @@ -470,16 +459,16 @@ mft_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, "bad CRL distribution point extension", fn); goto out; } - if ((p.res->crl = strdup(crlfile)) == NULL) + if ((mft->crl = strdup(crlfile)) == NULL) err(1, NULL); - if (mft_parse_econtent(cms, cmsz, &p) == 0) + if (mft_parse_econtent(fn, mft, cms, cmsz) == 0) goto out; if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) goto out; - if (p.res->signtime > p.res->nextupdate) { + if (mft->signtime > mft->nextupdate) { warnx("%s: dating issue: CMS signing-time after MFT nextUpdate", fn); goto out; @@ -488,15 +477,15 @@ mft_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, rc = 1; out: if (rc == 0) { - mft_free(p.res); - p.res = NULL; + mft_free(mft); + mft = NULL; X509_free(*x509); *x509 = NULL; } free(crldp); cert_free(cert); free(cms); - return p.res; + return mft; } /* diff --git a/usr.sbin/rpki-client/roa.c b/usr.sbin/rpki-client/roa.c index 633c200de..9c98ca9f9 100644 --- a/usr.sbin/rpki-client/roa.c +++ b/usr.sbin/rpki-client/roa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: roa.c,v 1.76 2024/02/16 15:13:49 tb Exp $ */ +/* $OpenBSD: roa.c,v 1.77 2024/02/21 09:17:06 tb Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2019 Kristaps Dzonsons @@ -31,14 +31,6 @@ #include "extern.h" -/* - * Parse results and data of the manifest file. - */ -struct parse { - const char *fn; /* manifest file name */ - struct roa *res; /* results */ -}; - extern ASN1_OBJECT *roa_oid; /* @@ -103,7 +95,8 @@ IMPLEMENT_ASN1_FUNCTIONS(RouteOriginAttestation); * Returns zero on failure, non-zero on success. */ static int -roa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) +roa_parse_econtent(const char *fn, struct roa *roa, const unsigned char *d, + size_t dsz) { const unsigned char *oder; RouteOriginAttestation *roa_asn1; @@ -121,39 +114,40 @@ roa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) oder = d; if ((roa_asn1 = d2i_RouteOriginAttestation(NULL, &d, dsz)) == NULL) { warnx("%s: RFC 6482 section 3: failed to parse " - "RouteOriginAttestation", p->fn); + "RouteOriginAttestation", fn); goto out; } if (d != oder + dsz) { - warnx("%s: %td bytes trailing garbage in eContent", p->fn, + warnx("%s: %td bytes trailing garbage in eContent", fn, oder + dsz - d); goto out; } - if (!valid_econtent_version(p->fn, roa_asn1->version, 0)) + if (!valid_econtent_version(fn, roa_asn1->version, 0)) goto out; - if (!as_id_parse(roa_asn1->asid, &p->res->asid)) { + if (!as_id_parse(roa_asn1->asid, &roa->asid)) { warnx("%s: RFC 6482 section 3.2: asID: " - "malformed AS identifier", p->fn); + "malformed AS identifier", fn); goto out; } ipaddrblocksz = sk_ROAIPAddressFamily_num(roa_asn1->ipAddrBlocks); if (ipaddrblocksz != 1 && ipaddrblocksz != 2) { warnx("%s: draft-rfc6482bis: unexpected number of ipAddrBlocks " - "(got %d, expected 1 or 2)", p->fn, ipaddrblocksz); + "(got %d, expected 1 or 2)", fn, ipaddrblocksz); goto out; } for (i = 0; i < ipaddrblocksz; i++) { - addrfam = sk_ROAIPAddressFamily_value(roa_asn1->ipAddrBlocks, i); + addrfam = sk_ROAIPAddressFamily_value(roa_asn1->ipAddrBlocks, + i); addrs = addrfam->addresses; addrsz = sk_ROAIPAddress_num(addrs); - if (!ip_addr_afi_parse(p->fn, addrfam->addressFamily, &afi)) { + if (!ip_addr_afi_parse(fn, addrfam->addressFamily, &afi)) { warnx("%s: RFC 6482 section 3.3: addressFamily: " - "invalid", p->fn); + "invalid", fn); goto out; } @@ -161,14 +155,14 @@ roa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) case AFI_IPV4: if (ipv4_seen++ > 0) { warnx("%s: RFC 6482bis section 4.3.2: " - "IPv4 appears twice", p->fn); + "IPv4 appears twice", fn); goto out; } break; case AFI_IPV6: if (ipv6_seen++ > 0) { warnx("%s: RFC 6482bis section 4.3.2: " - "IPv6 appears twice", p->fn); + "IPv6 appears twice", fn); goto out; } break; @@ -176,27 +170,26 @@ roa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) if (addrsz == 0) { warnx("%s: RFC 6482bis, section 4.3.2: " - "empty ROAIPAddressFamily", p->fn); + "empty ROAIPAddressFamily", fn); goto out; } - if (p->res->ipsz + addrsz >= MAX_IP_SIZE) { + if (roa->ipsz + addrsz >= MAX_IP_SIZE) { warnx("%s: too many ROAIPAddress entries: limit %d", - p->fn, MAX_IP_SIZE); + fn, MAX_IP_SIZE); goto out; } - p->res->ips = recallocarray(p->res->ips, p->res->ipsz, - p->res->ipsz + addrsz, sizeof(struct roa_ip)); - if (p->res->ips == NULL) + roa->ips = recallocarray(roa->ips, roa->ipsz, + roa->ipsz + addrsz, sizeof(struct roa_ip)); + if (roa->ips == NULL) err(1, NULL); for (j = 0; j < addrsz; j++) { addr = sk_ROAIPAddress_value(addrs, j); - if (!ip_addr_parse(addr->address, afi, p->fn, - &ipaddr)) { + if (!ip_addr_parse(addr->address, afi, fn, &ipaddr)) { warnx("%s: RFC 6482 section 3.3: address: " - "invalid IP address", p->fn); + "invalid IP address", fn); goto out; } maxlen = ipaddr.prefixlen; @@ -206,24 +199,24 @@ roa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) addr->maxLength)) { warnx("%s: RFC 6482 section 3.2: " "ASN1_INTEGER_get_uint64 failed", - p->fn); + fn); goto out; } if (ipaddr.prefixlen > maxlen) { warnx("%s: prefixlen (%d) larger than " - "maxLength (%llu)", p->fn, + "maxLength (%llu)", fn, ipaddr.prefixlen, (unsigned long long)maxlen); goto out; } if (maxlen > ((afi == AFI_IPV4) ? 32 : 128)) { warnx("%s: maxLength (%llu) too large", - p->fn, (unsigned long long)maxlen); + fn, (unsigned long long)maxlen); goto out; } } - res = &p->res->ips[p->res->ipsz++]; + res = &roa->ips[roa->ipsz++]; res->addr = ipaddr; res->afi = afi; res->maxlength = maxlen; @@ -245,45 +238,42 @@ struct roa * roa_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, size_t len) { - struct parse p; + struct roa *roa; size_t cmsz; unsigned char *cms; struct cert *cert = NULL; time_t signtime = 0; int rc = 0; - memset(&p, 0, sizeof(struct parse)); - p.fn = fn; - cms = cms_parse_validate(x509, fn, der, len, roa_oid, &cmsz, &signtime); if (cms == NULL) return NULL; - if ((p.res = calloc(1, sizeof(struct roa))) == NULL) + if ((roa = calloc(1, sizeof(struct roa))) == NULL) err(1, NULL); - p.res->signtime = signtime; + roa->signtime = signtime; - if (!x509_get_aia(*x509, fn, &p.res->aia)) + if (!x509_get_aia(*x509, fn, &roa->aia)) goto out; - if (!x509_get_aki(*x509, fn, &p.res->aki)) + if (!x509_get_aki(*x509, fn, &roa->aki)) goto out; - if (!x509_get_sia(*x509, fn, &p.res->sia)) + if (!x509_get_sia(*x509, fn, &roa->sia)) goto out; - if (!x509_get_ski(*x509, fn, &p.res->ski)) + if (!x509_get_ski(*x509, fn, &roa->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || - p.res->ski == NULL) { + if (roa->aia == NULL || roa->aki == NULL || roa->sia == NULL || + roa->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI, SIA, or SKI X509 extension", fn); goto out; } - if (!x509_get_notbefore(*x509, fn, &p.res->notbefore)) + if (!x509_get_notbefore(*x509, fn, &roa->notbefore)) goto out; - if (!x509_get_notafter(*x509, fn, &p.res->notafter)) + if (!x509_get_notafter(*x509, fn, &roa->notafter)) goto out; - if (!roa_parse_econtent(cms, cmsz, &p)) + if (!roa_parse_econtent(fn, roa, cms, cmsz)) goto out; if (x509_any_inherits(*x509)) { @@ -303,19 +293,19 @@ roa_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, * If the ROA isn't valid, we accept it anyway and depend upon * the code around roa_read() to check the "valid" field itself. */ - p.res->valid = valid_roa(fn, cert, p.res); + roa->valid = valid_roa(fn, cert, roa); rc = 1; out: if (rc == 0) { - roa_free(p.res); - p.res = NULL; + roa_free(roa); + roa = NULL; X509_free(*x509); *x509 = NULL; } cert_free(cert); free(cms); - return p.res; + return roa; } /* diff --git a/usr.sbin/rpki-client/rsc.c b/usr.sbin/rpki-client/rsc.c index 6bac1f767..19dddde36 100644 --- a/usr.sbin/rpki-client/rsc.c +++ b/usr.sbin/rpki-client/rsc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rsc.c,v 1.33 2024/02/16 15:19:02 tb Exp $ */ +/* $OpenBSD: rsc.c,v 1.34 2024/02/21 09:17:06 tb Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2022 Job Snijders @@ -31,14 +31,6 @@ #include "extern.h" -/* - * Parse results and data of the Signed Checklist file. - */ -struct parse { - const char *fn; /* Signed Checklist file name */ - struct rsc *res; /* results */ -}; - extern ASN1_OBJECT *rsc_oid; /* @@ -135,7 +127,8 @@ IMPLEMENT_ASN1_FUNCTIONS(RpkiSignedChecklist); * Return 0 on failure. */ static int -rsc_parse_aslist(struct parse *p, const ConstrainedASIdentifiers *asids) +rsc_parse_aslist(const char *fn, struct rsc *rsc, + const ConstrainedASIdentifiers *asids) { int i, asz; @@ -143,18 +136,18 @@ rsc_parse_aslist(struct parse *p, const ConstrainedASIdentifiers *asids) return 1; if ((asz = sk_ASIdOrRange_num(asids->asnum)) == 0) { - warnx("%s: RSC asID empty", p->fn); + warnx("%s: RSC asID empty", fn); return 0; } if (asz >= MAX_AS_SIZE) { warnx("%s: too many AS number entries: limit %d", - p->fn, MAX_AS_SIZE); + fn, MAX_AS_SIZE); return 0; } - p->res->as = calloc(asz, sizeof(struct cert_as)); - if (p->res->as == NULL) + rsc->as = calloc(asz, sizeof(struct cert_as)); + if (rsc->as == NULL) err(1, NULL); for (i = 0; i < asz; i++) { @@ -164,18 +157,16 @@ rsc_parse_aslist(struct parse *p, const ConstrainedASIdentifiers *asids) switch (aor->type) { case ASIdOrRange_id: - if (!sbgp_as_id(p->fn, p->res->as, &p->res->asz, - aor->u.id)) + if (!sbgp_as_id(fn, rsc->as, &rsc->asz, aor->u.id)) return 0; break; case ASIdOrRange_range: - if (!sbgp_as_range(p->fn, p->res->as, &p->res->asz, + if (!sbgp_as_range(fn, rsc->as, &rsc->asz, aor->u.range)) return 0; break; default: - warnx("%s: RSC AsList: unknown type %d", p->fn, - aor->type); + warnx("%s: RSC AsList: unknown type %d", fn, aor->type); return 0; } } @@ -184,7 +175,8 @@ rsc_parse_aslist(struct parse *p, const ConstrainedASIdentifiers *asids) } static int -rsc_parse_iplist(struct parse *p, const ConstrainedIPAddrBlocks *ipAddrBlocks) +rsc_parse_iplist(const char *fn, struct rsc *rsc, + const ConstrainedIPAddrBlocks *ipAddrBlocks) { const ConstrainedIPAddressFamily *af; const IPAddressOrRanges *aors; @@ -197,7 +189,7 @@ rsc_parse_iplist(struct parse *p, const ConstrainedIPAddrBlocks *ipAddrBlocks) return 1; if (sk_ConstrainedIPAddressFamily_num(ipAddrBlocks) == 0) { - warnx("%s: RSC ipAddrBlocks empty", p->fn); + warnx("%s: RSC ipAddrBlocks empty", fn); return 0; } @@ -205,20 +197,20 @@ rsc_parse_iplist(struct parse *p, const ConstrainedIPAddrBlocks *ipAddrBlocks) af = sk_ConstrainedIPAddressFamily_value(ipAddrBlocks, i); aors = af->addressesOrRanges; - ipsz = p->res->ipsz + sk_IPAddressOrRange_num(aors); + ipsz = rsc->ipsz + sk_IPAddressOrRange_num(aors); if (ipsz >= MAX_IP_SIZE) { warnx("%s: too many IP address entries: limit %d", - p->fn, MAX_IP_SIZE); + fn, MAX_IP_SIZE); return 0; } - p->res->ips = recallocarray(p->res->ips, p->res->ipsz, ipsz, + rsc->ips = recallocarray(rsc->ips, rsc->ipsz, ipsz, sizeof(struct cert_ip)); - if (p->res->ips == NULL) + if (rsc->ips == NULL) err(1, NULL); - if (!ip_addr_afi_parse(p->fn, af->addressFamily, &afi)) { - warnx("%s: RSC: invalid AFI", p->fn); + if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) { + warnx("%s: RSC: invalid AFI", fn); return 0; } @@ -226,18 +218,18 @@ rsc_parse_iplist(struct parse *p, const ConstrainedIPAddrBlocks *ipAddrBlocks) aor = sk_IPAddressOrRange_value(aors, j); switch (aor->type) { case IPAddressOrRange_addressPrefix: - if (!sbgp_addr(p->fn, p->res->ips, - &p->res->ipsz, afi, aor->u.addressPrefix)) + if (!sbgp_addr(fn, rsc->ips, + &rsc->ipsz, afi, aor->u.addressPrefix)) return 0; break; case IPAddressOrRange_addressRange: - if (!sbgp_addr_range(p->fn, p->res->ips, - &p->res->ipsz, afi, aor->u.addressRange)) + if (!sbgp_addr_range(fn, rsc->ips, + &rsc->ipsz, afi, aor->u.addressRange)) return 0; break; default: warnx("%s: RFC 3779: IPAddressOrRange: " - "unknown type %d", p->fn, aor->type); + "unknown type %d", fn, aor->type); return 0; } } @@ -247,7 +239,7 @@ rsc_parse_iplist(struct parse *p, const ConstrainedIPAddrBlocks *ipAddrBlocks) } static int -rsc_check_digesttype(struct parse *p, const X509_ALGOR *alg) +rsc_check_digesttype(const char *fn, struct rsc *rsc, const X509_ALGOR *alg) { const ASN1_OBJECT *obj; int type, nid; @@ -256,13 +248,13 @@ rsc_check_digesttype(struct parse *p, const X509_ALGOR *alg) if (type != V_ASN1_UNDEF) { warnx("%s: RSC DigestAlgorithmIdentifier unexpected parameters:" - " %d", p->fn, type); + " %d", fn, type); return 0; } if ((nid = OBJ_obj2nid(obj)) != NID_sha256) { warnx("%s: RSC DigestAlgorithmIdentifier: want SHA256, have %s" - " (NID %d)", p->fn, ASN1_tag2str(nid), nid); + " (NID %d)", fn, ASN1_tag2str(nid), nid); return 0; } @@ -274,7 +266,8 @@ rsc_check_digesttype(struct parse *p, const X509_ALGOR *alg) * Return zero on failure, non-zero on success. */ static int -rsc_parse_checklist(struct parse *p, const STACK_OF(FileNameAndHash) *checkList) +rsc_parse_checklist(const char *fn, struct rsc *rsc, + const STACK_OF(FileNameAndHash) *checkList) { FileNameAndHash *fh; ASN1_IA5STRING *fileName; @@ -282,28 +275,28 @@ rsc_parse_checklist(struct parse *p, const STACK_OF(FileNameAndHash) *checkList) size_t sz, i; if ((sz = sk_FileNameAndHash_num(checkList)) == 0) { - warnx("%s: RSC checkList needs at least one entry", p->fn); + warnx("%s: RSC checkList needs at least one entry", fn); return 0; } if (sz >= MAX_CHECKLIST_ENTRIES) { - warnx("%s: %zu exceeds checklist entry limit (%d)", p->fn, sz, + warnx("%s: %zu exceeds checklist entry limit (%d)", fn, sz, MAX_CHECKLIST_ENTRIES); return 0; } - p->res->files = calloc(sz, sizeof(struct rscfile)); - if (p->res->files == NULL) + rsc->files = calloc(sz, sizeof(struct rscfile)); + if (rsc->files == NULL) err(1, NULL); - p->res->filesz = sz; + rsc->filesz = sz; for (i = 0; i < sz; i++) { fh = sk_FileNameAndHash_value(checkList, i); - file = &p->res->files[i]; + file = &rsc->files[i]; if (fh->hash->length != SHA256_DIGEST_LENGTH) { - warnx("%s: RSC Digest: invalid SHA256 length", p->fn); + warnx("%s: RSC Digest: invalid SHA256 length", fn); return 0; } memcpy(file->hash, fh->hash->data, SHA256_DIGEST_LENGTH); @@ -312,7 +305,7 @@ rsc_parse_checklist(struct parse *p, const STACK_OF(FileNameAndHash) *checkList) continue; if (!valid_filename(fileName->data, fileName->length)) { - warnx("%s: RSC FileNameAndHash: bad filename", p->fn); + warnx("%s: RSC FileNameAndHash: bad filename", fn); return 0; } @@ -330,7 +323,8 @@ rsc_parse_checklist(struct parse *p, const STACK_OF(FileNameAndHash) *checkList) * Returns zero on failure, non-zero on success. */ static int -rsc_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) +rsc_parse_econtent(const char *fn, struct rsc *rsc, const unsigned char *d, + size_t dsz) { const unsigned char *oder; RpkiSignedChecklist *rsc_asn1; @@ -343,35 +337,35 @@ rsc_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) oder = d; if ((rsc_asn1 = d2i_RpkiSignedChecklist(NULL, &d, dsz)) == NULL) { - warnx("%s: RSC: failed to parse RpkiSignedChecklist", p->fn); + warnx("%s: RSC: failed to parse RpkiSignedChecklist", fn); goto out; } if (d != oder + dsz) { - warnx("%s: %td bytes trailing garbage in eContent", p->fn, + warnx("%s: %td bytes trailing garbage in eContent", fn, oder + dsz - d); goto out; } - if (!valid_econtent_version(p->fn, rsc_asn1->version, 0)) + if (!valid_econtent_version(fn, rsc_asn1->version, 0)) goto out; resources = rsc_asn1->resources; if (resources->asID == NULL && resources->ipAddrBlocks == NULL) { warnx("%s: RSC: one of asID or ipAddrBlocks must be present", - p->fn); + fn); goto out; } - if (!rsc_parse_aslist(p, resources->asID)) + if (!rsc_parse_aslist(fn, rsc, resources->asID)) goto out; - if (!rsc_parse_iplist(p, resources->ipAddrBlocks)) + if (!rsc_parse_iplist(fn, rsc, resources->ipAddrBlocks)) goto out; - if (!rsc_check_digesttype(p, rsc_asn1->digestAlgorithm)) + if (!rsc_check_digesttype(fn, rsc, rsc_asn1->digestAlgorithm)) goto out; - if (!rsc_parse_checklist(p, rsc_asn1->checkList)) + if (!rsc_parse_checklist(fn, rsc, rsc_asn1->checkList)) goto out; rc = 1; @@ -388,40 +382,37 @@ struct rsc * rsc_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, size_t len) { - struct parse p; + struct rsc *rsc; unsigned char *cms; size_t cmsz; struct cert *cert = NULL; time_t signtime = 0; int rc = 0; - memset(&p, 0, sizeof(struct parse)); - p.fn = fn; - cms = cms_parse_validate(x509, fn, der, len, rsc_oid, &cmsz, &signtime); if (cms == NULL) return NULL; - if ((p.res = calloc(1, sizeof(struct rsc))) == NULL) + if ((rsc = calloc(1, sizeof(struct rsc))) == NULL) err(1, NULL); - p.res->signtime = signtime; + rsc->signtime = signtime; - if (!x509_get_aia(*x509, fn, &p.res->aia)) + if (!x509_get_aia(*x509, fn, &rsc->aia)) goto out; - if (!x509_get_aki(*x509, fn, &p.res->aki)) + if (!x509_get_aki(*x509, fn, &rsc->aki)) goto out; - if (!x509_get_ski(*x509, fn, &p.res->ski)) + if (!x509_get_ski(*x509, fn, &rsc->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { + if (rsc->aia == NULL || rsc->aki == NULL || rsc->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI or SKI X509 extension", fn); goto out; } - if (!x509_get_notbefore(*x509, fn, &p.res->notbefore)) + if (!x509_get_notbefore(*x509, fn, &rsc->notbefore)) goto out; - if (!x509_get_notafter(*x509, fn, &p.res->notafter)) + if (!x509_get_notafter(*x509, fn, &rsc->notafter)) goto out; if (X509_get_ext_by_NID(*x509, NID_sinfo_access, -1) != -1) { @@ -434,25 +425,25 @@ rsc_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, goto out; } - if (!rsc_parse_econtent(cms, cmsz, &p)) + if (!rsc_parse_econtent(fn, rsc, cms, cmsz)) goto out; if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) goto out; - p.res->valid = valid_rsc(fn, cert, p.res); + rsc->valid = valid_rsc(fn, cert, rsc); rc = 1; out: if (rc == 0) { - rsc_free(p.res); - p.res = NULL; + rsc_free(rsc); + rsc = NULL; X509_free(*x509); *x509 = NULL; } cert_free(cert); free(cms); - return p.res; + return rsc; } /* diff --git a/usr.sbin/rpki-client/tak.c b/usr.sbin/rpki-client/tak.c index 72a886144..b0b15558c 100644 --- a/usr.sbin/rpki-client/tak.c +++ b/usr.sbin/rpki-client/tak.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tak.c,v 1.18 2024/02/16 15:13:49 tb Exp $ */ +/* $OpenBSD: tak.c,v 1.19 2024/02/21 09:17:06 tb Exp $ */ /* * Copyright (c) 2022 Job Snijders * Copyright (c) 2022 Theo Buehler @@ -31,14 +31,6 @@ #include "extern.h" -/* - * Parse results and data of the Trust Anchor Key file. - */ -struct parse { - const char *fn; /* TAK file name */ - struct tak *res; /* results */ -}; - extern ASN1_OBJECT *tak_oid; /* @@ -161,22 +153,20 @@ parse_takey(const char *fn, const TAKey *takey) * Returns zero on failure, non-zero on success. */ static int -tak_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) +tak_parse_econtent(const char *fn, struct tak *tak, const unsigned char *d, + size_t dsz) { const unsigned char *oder; TAK *tak_asn1; - const char *fn; int rc = 0; - fn = p->fn; - oder = d; if ((tak_asn1 = d2i_TAK(NULL, &d, dsz)) == NULL) { warnx("%s: failed to parse Trust Anchor Key", fn); goto out; } if (d != oder + dsz) { - warnx("%s: %td bytes trailing garbage in eContent", p->fn, + warnx("%s: %td bytes trailing garbage in eContent", fn, oder + dsz - d); goto out; } @@ -184,19 +174,19 @@ tak_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) if (!valid_econtent_version(fn, tak_asn1->version, 0)) goto out; - p->res->current = parse_takey(fn, tak_asn1->current); - if (p->res->current == NULL) + tak->current = parse_takey(fn, tak_asn1->current); + if (tak->current == NULL) goto out; if (tak_asn1->predecessor != NULL) { - p->res->predecessor = parse_takey(fn, tak_asn1->predecessor); - if (p->res->predecessor == NULL) + tak->predecessor = parse_takey(fn, tak_asn1->predecessor); + if (tak->predecessor == NULL) goto out; } if (tak_asn1->successor != NULL) { - p->res->successor = parse_takey(fn, tak_asn1->successor); - if (p->res->successor == NULL) + tak->successor = parse_takey(fn, tak_asn1->successor); + if (tak->successor == NULL) goto out; } @@ -214,42 +204,39 @@ struct tak * tak_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, size_t len) { - struct parse p; + struct tak *tak; struct cert *cert = NULL; unsigned char *cms; size_t cmsz; time_t signtime = 0; int rc = 0; - memset(&p, 0, sizeof(struct parse)); - p.fn = fn; - cms = cms_parse_validate(x509, fn, der, len, tak_oid, &cmsz, &signtime); if (cms == NULL) return NULL; - if ((p.res = calloc(1, sizeof(struct tak))) == NULL) + if ((tak = calloc(1, sizeof(struct tak))) == NULL) err(1, NULL); - p.res->signtime = signtime; + tak->signtime = signtime; - if (!x509_get_aia(*x509, fn, &p.res->aia)) + if (!x509_get_aia(*x509, fn, &tak->aia)) goto out; - if (!x509_get_aki(*x509, fn, &p.res->aki)) + if (!x509_get_aki(*x509, fn, &tak->aki)) goto out; - if (!x509_get_sia(*x509, fn, &p.res->sia)) + if (!x509_get_sia(*x509, fn, &tak->sia)) goto out; - if (!x509_get_ski(*x509, fn, &p.res->ski)) + if (!x509_get_ski(*x509, fn, &tak->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || - p.res->ski == NULL) { + if (tak->aia == NULL || tak->aki == NULL || tak->sia == NULL || + tak->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI, SIA, or SKI X509 extension", fn); goto out; } - if (!x509_get_notbefore(*x509, fn, &p.res->notbefore)) + if (!x509_get_notbefore(*x509, fn, &tak->notbefore)) goto out; - if (!x509_get_notafter(*x509, fn, &p.res->notafter)) + if (!x509_get_notafter(*x509, fn, &tak->notafter)) goto out; if (!x509_inherits(*x509)) { @@ -257,13 +244,13 @@ tak_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, goto out; } - if (!tak_parse_econtent(cms, cmsz, &p)) + if (!tak_parse_econtent(fn, tak, cms, cmsz)) goto out; if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) goto out; - if (strcmp(p.res->aki, p.res->current->ski) != 0) { + if (strcmp(tak->aki, tak->current->ski) != 0) { warnx("%s: current TAKey's SKI does not match EE AKI", fn); goto out; } @@ -271,14 +258,14 @@ tak_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, rc = 1; out: if (rc == 0) { - tak_free(p.res); - p.res = NULL; + tak_free(tak); + tak = NULL; X509_free(*x509); *x509 = NULL; } cert_free(cert); free(cms); - return p.res; + return tak; } /*