From a77f0ad44fde89874654ba48f461209fb0382107 Mon Sep 17 00:00:00 2001 From: Pagadala Yesu Anjaneyulu Date: Wed, 12 Nov 2025 11:10:23 +0200 Subject: wifi: cfg80211: Add support for 6GHz AP role not relevant AP type Add IEEE80211_6GHZ_CTRL_REG_AP_ROLE_NOT_RELEVANT and map it to IEEE80211_REG_LPI_AP for safe regulatory compliance when AP role classification is not applicable. Use LPI as safe fallback to prevent power limit violations. Signed-off-by: Pagadala Yesu Anjaneyulu Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251112110828.856283677cc7.I36138a34847c3b4e680974bf347dde844448f3bc@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211-he.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/ieee80211-he.h b/include/linux/ieee80211-he.h index 904d50db5bb8..a08c446fbb04 100644 --- a/include/linux/ieee80211-he.h +++ b/include/linux/ieee80211-he.h @@ -548,6 +548,7 @@ static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len) #define IEEE80211_6GHZ_CTRL_REG_VLP_AP 2 #define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP 3 #define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD 4 +#define IEEE80211_6GHZ_CTRL_REG_AP_ROLE_NOT_RELEVANT 7 #define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP 8 /** -- cgit v1.2.3 From 4255545a28f75fb6082b6f91d1e7ada28383ab22 Mon Sep 17 00:00:00 2001 From: Chien Wong Date: Thu, 13 Nov 2025 22:05:08 +0800 Subject: wifi: mac80211: add generic MMIE struct defines The added struct is needed when writing generic handler for both CMAC-128 and CMAC-256. Signed-off-by: Chien Wong Link: https://patch.msgid.link/20251113140511.48658-3-m@xv97.com Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 6d4bc80caf96..d55d8ea3a8be 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1207,7 +1207,7 @@ struct ieee80211_mgmt { #define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u) -/* Management MIC information element (IEEE 802.11w) */ +/* Management MIC information element (IEEE 802.11w) for CMAC */ struct ieee80211_mmie { u8 element_id; u8 length; @@ -1225,6 +1225,15 @@ struct ieee80211_mmie_16 { u8 mic[16]; } __packed; +/* Management MIC information element (IEEE 802.11w) for all variants */ +struct ieee80211_mmie_var { + u8 element_id; + u8 length; + __le16 key_id; + u8 sequence_number[6]; + u8 mic[]; /* 8 or 16 bytes */ +} __packed; + struct ieee80211_vendor_ie { u8 element_id; u8 len; @@ -1889,6 +1898,9 @@ enum ieee80211_radio_measurement_actioncode { #define IEEE80211_GCMP_HDR_LEN 8 #define IEEE80211_GCMP_MIC_LEN 16 #define IEEE80211_GCMP_PN_LEN 6 +#define IEEE80211_CMAC_128_MIC_LEN 8 +#define IEEE80211_CMAC_256_MIC_LEN 16 +#define IEEE80211_GMAC_MIC_LEN 16 #define FILS_NONCE_LEN 16 #define FILS_MAX_KEK_LEN 64 -- cgit v1.2.3 From 385aab8fccd7a8746b9f1a17f3c1e38498a14bc7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 8 Oct 2025 12:41:48 +0200 Subject: wifi: mt76: wed: use proper wed reference in mt76 wed driver callabacks MT7996 driver can use both wed and wed_hif2 devices to offload traffic from/to the wireless NIC. In the current codebase we assume to always use the primary wed device in wed callbacks resulting in the following crash if the hw runs wed_hif2 (e.g. 6GHz link). [ 297.455876] Unable to handle kernel read from unreadable memory at virtual address 000000000000080a [ 297.464928] Mem abort info: [ 297.467722] ESR = 0x0000000096000005 [ 297.471461] EC = 0x25: DABT (current EL), IL = 32 bits [ 297.476766] SET = 0, FnV = 0 [ 297.479809] EA = 0, S1PTW = 0 [ 297.482940] FSC = 0x05: level 1 translation fault [ 297.487809] Data abort info: [ 297.490679] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000 [ 297.496156] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 297.501196] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 297.506500] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000107480000 [ 297.512927] [000000000000080a] pgd=08000001097fb003, p4d=08000001097fb003, pud=08000001097fb003, pmd=0000000000000000 [ 297.523532] Internal error: Oops: 0000000096000005 [#1] SMP [ 297.715393] CPU: 2 UID: 0 PID: 45 Comm: kworker/u16:2 Tainted: G O 6.12.50 #0 [ 297.723908] Tainted: [O]=OOT_MODULE [ 297.727384] Hardware name: Banana Pi BPI-R4 (2x SFP+) (DT) [ 297.732857] Workqueue: nf_ft_offload_del nf_flow_rule_route_ipv6 [nf_flow_table] [ 297.740254] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 297.747205] pc : mt76_wed_offload_disable+0x64/0xa0 [mt76] [ 297.752688] lr : mtk_wed_flow_remove+0x58/0x80 [ 297.757126] sp : ffffffc080fe3ae0 [ 297.760430] x29: ffffffc080fe3ae0 x28: ffffffc080fe3be0 x27: 00000000deadbef7 [ 297.767557] x26: ffffff80c5ebca00 x25: 0000000000000001 x24: ffffff80c85f4c00 [ 297.774683] x23: ffffff80c1875b78 x22: ffffffc080d42cd0 x21: ffffffc080660018 [ 297.781809] x20: ffffff80c6a076d0 x19: ffffff80c6a043c8 x18: 0000000000000000 [ 297.788935] x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000 [ 297.796060] x14: 0000000000000019 x13: ffffff80c0ad8ec0 x12: 00000000fa83b2da [ 297.803185] x11: ffffff80c02700c0 x10: ffffff80c0ad8ec0 x9 : ffffff81fef96200 [ 297.810311] x8 : ffffff80c02700c0 x7 : ffffff80c02700d0 x6 : 0000000000000002 [ 297.817435] x5 : 0000000000000400 x4 : 0000000000000000 x3 : 0000000000000000 [ 297.824561] x2 : 0000000000000001 x1 : 0000000000000800 x0 : ffffff80c6a063c8 [ 297.831686] Call trace: [ 297.834123] mt76_wed_offload_disable+0x64/0xa0 [mt76] [ 297.839254] mtk_wed_flow_remove+0x58/0x80 [ 297.843342] mtk_flow_offload_cmd+0x434/0x574 [ 297.847689] mtk_wed_setup_tc_block_cb+0x30/0x40 [ 297.852295] nf_flow_offload_ipv6_hook+0x7f4/0x964 [nf_flow_table] [ 297.858466] nf_flow_rule_route_ipv6+0x438/0x4a4 [nf_flow_table] [ 297.864463] process_one_work+0x174/0x300 [ 297.868465] worker_thread+0x278/0x430 [ 297.872204] kthread+0xd8/0xdc [ 297.875251] ret_from_fork+0x10/0x20 [ 297.878820] Code: 928b5ae0 8b000273 91400a60 f943fa61 (79401421) [ 297.884901] ---[ end trace 0000000000000000 ]--- Fix the issue detecting the proper wed reference to use running wed callabacks. Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support") Tested-by: Daniel Pawlik Tested-by: Matteo Croce Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251008-wed-fixes-v1-1-8f7678583385@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 9 +++++++++ drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 1 + drivers/net/wireless/mediatek/mt76/wed.c | 10 +++++----- include/linux/soc/mediatek/mtk_wed.h | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 86b812f68c97..e0a036b03b03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1260,6 +1260,15 @@ static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, #define mt76_dereference(p, dev) \ rcu_dereference_protected(p, lockdep_is_held(&(dev)->mutex)) +static inline struct mt76_dev *mt76_wed_to_dev(struct mtk_wed_device *wed) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + if (wed->wlan.hif2) + return container_of(wed, struct mt76_dev, mmio.wed_hif2); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + return container_of(wed, struct mt76_dev, mmio.wed); +} + static inline struct mt76_wcid * __mt76_wcid_ptr(struct mt76_dev *dev, u16 idx) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index d14b626ee511..80db102ed809 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -595,6 +595,7 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf; + wed->wlan.hif2 = hif2; wed->wlan.amsdu_max_subframes = 8; wed->wlan.amsdu_max_len = 1536; diff --git a/drivers/net/wireless/mediatek/mt76/wed.c b/drivers/net/wireless/mediatek/mt76/wed.c index 907a8e43e72a..fbd7e59c73aa 100644 --- a/drivers/net/wireless/mediatek/mt76/wed.c +++ b/drivers/net/wireless/mediatek/mt76/wed.c @@ -8,7 +8,7 @@ void mt76_wed_release_rx_buf(struct mtk_wed_device *wed) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt76_dev *dev = mt76_wed_to_dev(wed); int i; for (i = 0; i < dev->rx_token_size; i++) { @@ -31,8 +31,8 @@ EXPORT_SYMBOL_GPL(mt76_wed_release_rx_buf); #ifdef CONFIG_NET_MEDIATEK_SOC_WED u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; + struct mt76_dev *dev = mt76_wed_to_dev(wed); struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct mt76_txwi_cache *t = NULL; int i; @@ -80,7 +80,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_init_rx_buf); int mt76_wed_offload_enable(struct mtk_wed_device *wed) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt76_dev *dev = mt76_wed_to_dev(wed); spin_lock_bh(&dev->token_lock); dev->token_size = wed->wlan.token_start; @@ -164,7 +164,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_dma_setup); void mt76_wed_offload_disable(struct mtk_wed_device *wed) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt76_dev *dev = mt76_wed_to_dev(wed); spin_lock_bh(&dev->token_lock); dev->token_size = dev->drv->token_size; @@ -174,7 +174,7 @@ EXPORT_SYMBOL_GPL(mt76_wed_offload_disable); void mt76_wed_reset_complete(struct mtk_wed_device *wed) { - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt76_dev *dev = mt76_wed_to_dev(wed); complete(&dev->mmio.wed_reset_complete); } diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h index c4ff6bab176d..3fa93bd65004 100644 --- a/include/linux/soc/mediatek/mtk_wed.h +++ b/include/linux/soc/mediatek/mtk_wed.h @@ -154,6 +154,7 @@ struct mtk_wed_device { bool wcid_512; bool hw_rro; bool msi; + bool hif2; u16 token_start; unsigned int nbuf; -- cgit v1.2.3 From 7fb554b1b623c7da845521604bd05fa9570d07bc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 17 Oct 2025 10:50:32 +0200 Subject: wifi: mt76: Introduce the NPU generic layer Add the NPU generic layer in mt76 module. NPU will be used to enable traffic forward offloading between the MT76 NIC and the Airoha ethernet one available on the Airoha EN7581 SoC using Netfilter Flowtable APIs. Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251017-mt76-npu-devel-v2-4-ddaa90901723@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Kconfig | 4 + drivers/net/wireless/mediatek/mt76/Makefile | 1 + drivers/net/wireless/mediatek/mt76/dma.c | 41 ++- drivers/net/wireless/mediatek/mt76/dma.h | 36 ++ drivers/net/wireless/mediatek/mt76/mac80211.c | 6 +- drivers/net/wireless/mediatek/mt76/mt76.h | 135 +++++++ drivers/net/wireless/mediatek/mt76/npu.c | 501 ++++++++++++++++++++++++++ include/linux/soc/airoha/airoha_offload.h | 1 + 8 files changed, 718 insertions(+), 7 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/npu.c (limited to 'include/linux') diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index d0aff94075d6..502303622a53 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -37,6 +37,10 @@ config MT792x_USB tristate select MT76_USB +config MT76_NPU + bool + depends on MT76_CORE + source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig" diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 53e7bcefe770..1d42adfe8030 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -12,6 +12,7 @@ mt76-y := \ mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ tx.o agg-rx.o mcu.o wed.o scan.o channel.o +mt76-$(CONFIG_MT76_NPU) += npu.o mt76-$(CONFIG_PCI) += pci.o mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index a4c1b6c66488..f240016ed9f0 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -189,10 +189,15 @@ static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { Q_WRITE(q, desc_base, q->desc_dma); - if (q->flags & MT_QFLAG_WED_RRO_EN) + if ((q->flags & MT_QFLAG_WED_RRO_EN) && !mt76_npu_device_active(dev)) Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); else Q_WRITE(q, ring_size, q->ndesc); + + if (mt76_queue_is_npu_tx(q)) { + writel(q->desc_dma, &q->regs->desc_base); + writel(q->ndesc, &q->regs->ring_size); + } q->head = Q_READ(q, dma_idx); q->tail = q->head; } @@ -204,7 +209,7 @@ void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, return; if (!mt76_queue_is_wed_rro_ind(q) && - !mt76_queue_is_wed_rro_rxdmad_c(q)) { + !mt76_queue_is_wed_rro_rxdmad_c(q) && !mt76_queue_is_npu(q)) { int i; /* clear descriptors */ @@ -415,6 +420,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) while (q->queued > 0 && q->tail != last) { mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry); + mt76_npu_txdesc_cleanup(q, q->tail); mt76_queue_tx_complete(dev, q, &entry); if (entry.txwi) { @@ -649,6 +655,10 @@ mt76_dma_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, if (test_bit(MT76_RESET, &phy->state)) goto free_skb; + /* TODO: Take into account unlinear skbs */ + if (mt76_npu_device_active(dev) && skb_linearize(skb)) + goto free_skb; + t = mt76_get_txwi(dev); if (!t) goto free_skb; @@ -696,6 +706,9 @@ mt76_dma_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, if (ret < 0) goto unmap; + if (mt76_npu_device_active(dev)) + return mt76_npu_dma_add_buf(phy, q, skb, &tx_info.buf[1], txwi); + return mt76_dma_add_buf(dev, q, tx_info.buf, tx_info.nbuf, tx_info.info, tx_info.skb, t); @@ -796,8 +809,15 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, q->hw_idx = idx; q->dev = dev; - size = mt76_queue_is_wed_rro_ind(q) ? sizeof(struct mt76_wed_rro_desc) - : sizeof(struct mt76_desc); + if (mt76_queue_is_wed_rro_ind(q)) + size = sizeof(struct mt76_wed_rro_desc); + else if (mt76_queue_is_npu_tx(q)) + size = sizeof(struct airoha_npu_tx_dma_desc); + else if (mt76_queue_is_npu_rx(q)) + size = sizeof(struct airoha_npu_rx_dma_desc); + else + size = sizeof(struct mt76_desc); + q->desc = dmam_alloc_coherent(dev->dma_dev, q->ndesc * size, &q->desc_dma, GFP_KERNEL); if (!q->desc) @@ -813,6 +833,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, if (ret) return ret; + mt76_npu_queue_setup(dev, q); ret = mt76_wed_dma_setup(dev, q, false); if (ret) return ret; @@ -840,6 +861,11 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) if (!q->ndesc) return; + if (mt76_queue_is_npu(q)) { + mt76_npu_queue_cleanup(dev, q); + return; + } + do { spin_lock_bh(&q->lock); buf = mt76_dma_dequeue(dev, q, true, NULL, NULL, &more, NULL); @@ -870,7 +896,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) return; if (!mt76_queue_is_wed_rro_ind(q) && - !mt76_queue_is_wed_rro_rxdmad_c(q)) { + !mt76_queue_is_wed_rro_rxdmad_c(q) && !mt76_queue_is_npu(q)) { int i; for (i = 0; i < q->ndesc; i++) @@ -890,7 +916,10 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) return; mt76_dma_sync_idx(dev, q); - mt76_dma_rx_fill_buf(dev, q, false); + if (mt76_queue_is_npu(q)) + mt76_npu_fill_rx_queue(dev, q); + else + mt76_dma_rx_fill(dev, q, false); } static void diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 19bc768913ff..4a63de6c5bf5 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -70,6 +70,42 @@ writel(_val, &(_q)->regs->_field); \ } while (0) +#elif IS_ENABLED(CONFIG_MT76_NPU) + +#define Q_READ(_q, _field) ({ \ + u32 _offset = offsetof(struct mt76_queue_regs, _field); \ + u32 _val = 0; \ + if ((_q)->flags & MT_QFLAG_NPU) { \ + struct airoha_npu *npu; \ + \ + rcu_read_lock(); \ + npu = rcu_dereference(q->dev->mmio.npu); \ + if (npu) \ + regmap_read(npu->regmap, \ + ((_q)->wed_regs + _offset), &_val); \ + rcu_read_unlock(); \ + } else { \ + _val = readl(&(_q)->regs->_field); \ + } \ + _val; \ +}) + +#define Q_WRITE(_q, _field, _val) do { \ + u32 _offset = offsetof(struct mt76_queue_regs, _field); \ + if ((_q)->flags & MT_QFLAG_NPU) { \ + struct airoha_npu *npu; \ + \ + rcu_read_lock(); \ + npu = rcu_dereference(q->dev->mmio.npu); \ + if (npu) \ + regmap_write(npu->regmap, \ + ((_q)->wed_regs + _offset), _val); \ + rcu_read_unlock(); \ + } else { \ + writel(_val, &(_q)->regs->_field); \ + } \ +} while (0) + #else #define Q_READ(_q, _field) readl(&(_q)->regs->_field) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 4be47aea2253..72ed3c825fa6 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -630,6 +630,8 @@ int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q) case MT_RXQ_MAIN: case MT_RXQ_BAND1: case MT_RXQ_BAND2: + case MT_RXQ_NPU0: + case MT_RXQ_NPU1: pp_params.pool_size = 256; break; default: @@ -814,6 +816,7 @@ void mt76_free_device(struct mt76_dev *dev) destroy_workqueue(dev->wq); dev->wq = NULL; } + mt76_npu_deinit(dev); ieee80211_free_hw(dev->hw); } EXPORT_SYMBOL_GPL(mt76_free_device); @@ -1553,7 +1556,8 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { mt76_check_sta(dev, skb); - if (mtk_wed_device_active(&dev->mmio.wed)) + if (mtk_wed_device_active(&dev->mmio.wed) || + mt76_npu_device_active(dev)) __skb_queue_tail(&frames, skb); else mt76_rx_aggr_reorder(skb, &frames); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a66b89bc4b4a..d05e83ea1cac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #define MT_QFLAG_WED_RRO BIT(6) #define MT_QFLAG_WED_RRO_EN BIT(7) #define MT_QFLAG_EMI_EN BIT(8) +#define MT_QFLAG_NPU BIT(9) #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ @@ -48,6 +50,12 @@ #define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0) #define MT_WED_RRO_Q_RXDMAD_C __MT_WED_RRO_Q(MT76_WED_RRO_Q_RXDMAD_C, 0) +#define __MT_NPU_Q(_type, _n) (MT_QFLAG_NPU | \ + FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ + FIELD_PREP(MT_QFLAG_WED_RING, _n)) +#define MT_NPU_Q_TX(_n) __MT_NPU_Q(MT76_WED_Q_TX, _n) +#define MT_NPU_Q_RX(_n) __MT_NPU_Q(MT76_WED_Q_RX, _n) + struct mt76_dev; struct mt76_phy; struct mt76_wcid; @@ -139,6 +147,8 @@ enum mt76_rxq_id { MT_RXQ_TXFREE_BAND2, MT_RXQ_RRO_IND, MT_RXQ_RRO_RXDMAD_C, + MT_RXQ_NPU0, + MT_RXQ_NPU1, __MT_RXQ_MAX }; @@ -707,6 +717,11 @@ struct mt76_mmio { struct mtk_wed_device wed_hif2; struct completion wed_reset; struct completion wed_reset_complete; + + struct airoha_ppe_dev __rcu *ppe_dev; + struct airoha_npu __rcu *npu; + phys_addr_t phy_addr; + int npu_type; }; struct mt76_rx_status { @@ -1617,6 +1632,109 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state); int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len); +#ifdef CONFIG_MT76_NPU +void mt76_npu_check_ppe(struct mt76_dev *dev, struct sk_buff *skb, + u32 info); +int mt76_npu_dma_add_buf(struct mt76_phy *phy, struct mt76_queue *q, + struct sk_buff *skb, struct mt76_queue_buf *buf, + void *txwi_ptr); +int mt76_npu_rx_queue_init(struct mt76_dev *dev, struct mt76_queue *q); +int mt76_npu_fill_rx_queue(struct mt76_dev *dev, struct mt76_queue *q); +void mt76_npu_queue_cleanup(struct mt76_dev *dev, struct mt76_queue *q); +void mt76_npu_disable_irqs(struct mt76_dev *dev); +int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type); +void mt76_npu_deinit(struct mt76_dev *dev); +void mt76_npu_queue_setup(struct mt76_dev *dev, struct mt76_queue *q); +void mt76_npu_txdesc_cleanup(struct mt76_queue *q, int index); +int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *dev, enum tc_setup_type type, + void *type_data); +#else +static inline void mt76_npu_check_ppe(struct mt76_dev *dev, + struct sk_buff *skb, u32 info) +{ +} + +static inline int mt76_npu_dma_add_buf(struct mt76_phy *phy, + struct mt76_queue *q, + struct sk_buff *skb, + struct mt76_queue_buf *buf, + void *txwi_ptr) +{ + return -EOPNOTSUPP; +} + +static inline int mt76_npu_fill_rx_queue(struct mt76_dev *dev, + struct mt76_queue *q) +{ + return 0; +} + +static inline void mt76_npu_queue_cleanup(struct mt76_dev *dev, + struct mt76_queue *q) +{ +} + +static inline void mt76_npu_disable_irqs(struct mt76_dev *dev) +{ +} + +static inline int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, + int type) +{ + return 0; +} + +static inline void mt76_npu_deinit(struct mt76_dev *dev) +{ +} + +static inline void mt76_npu_queue_setup(struct mt76_dev *dev, + struct mt76_queue *q) +{ +} + +static inline void mt76_npu_txdesc_cleanup(struct mt76_queue *q, + int index) +{ +} + +static inline int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct net_device *dev, + enum tc_setup_type type, + void *type_data) +{ + return -EOPNOTSUPP; +} +#endif /* CONFIG_MT76_NPU */ + +static inline bool mt76_npu_device_active(struct mt76_dev *dev) +{ + return !!rcu_access_pointer(dev->mmio.npu); +} + +static inline bool mt76_ppe_device_active(struct mt76_dev *dev) +{ + return !!rcu_access_pointer(dev->mmio.ppe_dev); +} + +static inline int mt76_npu_send_msg(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_set_cmd cmd, + u32 val, gfp_t gfp) +{ + return airoha_npu_wlan_send_msg(npu, ifindex, cmd, &val, sizeof(val), + gfp); +} + +static inline int mt76_npu_get_msg(struct airoha_npu *npu, int ifindex, + enum airoha_npu_wlan_get_cmd cmd, + u32 *val, gfp_t gfp) +{ + return airoha_npu_wlan_get_msg(npu, ifindex, cmd, val, sizeof(*val), + gfp); +} + static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable) { #ifdef CONFIG_NL80211_TESTMODE @@ -1858,6 +1976,23 @@ static inline bool mt76_queue_is_emi(struct mt76_queue *q) return q->flags & MT_QFLAG_EMI_EN; } +static inline bool mt76_queue_is_npu(struct mt76_queue *q) +{ + return q->flags & MT_QFLAG_NPU; +} + +static inline bool mt76_queue_is_npu_tx(struct mt76_queue *q) +{ + return mt76_queue_is_npu(q) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TX; +} + +static inline bool mt76_queue_is_npu_rx(struct mt76_queue *q) +{ + return mt76_queue_is_npu(q) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; +} + struct mt76_txwi_cache * mt76_token_release(struct mt76_dev *dev, int token, bool *wake); int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi); diff --git a/drivers/net/wireless/mediatek/mt76/npu.c b/drivers/net/wireless/mediatek/mt76/npu.c new file mode 100644 index 000000000000..ec36975f6dc9 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/npu.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 AIROHA Inc + * Author: Lorenzo Bianconi + */ +#include +#include +#include + +#include "mt76.h" +#include "dma.h" +#include "mt76_connac.h" + +#define MT76_NPU_RX_BUF_SIZE (1800 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + +int mt76_npu_fill_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + int nframes = 0; + + while (q->queued < q->ndesc - 1) { + struct airoha_npu_rx_dma_desc *desc = (void *)q->desc; + struct mt76_queue_entry *e = &q->entry[q->head]; + struct page *page; + int offset; + + e->buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); + if (!e->buf) + break; + + e->dma_len[0] = SKB_WITH_OVERHEAD(q->buf_size); + page = virt_to_head_page(e->buf); + e->dma_addr[0] = page_pool_get_dma_addr(page) + offset; + + memset(&desc[q->head], 0, sizeof(*desc)); + desc[q->head].addr = e->dma_addr[0]; + + q->head = (q->head + 1) % q->ndesc; + q->queued++; + nframes++; + } + + return nframes; +} + +void mt76_npu_queue_cleanup(struct mt76_dev *dev, struct mt76_queue *q) +{ + spin_lock_bh(&q->lock); + while (q->queued > 0) { + struct mt76_queue_entry *e = &q->entry[q->tail]; + + dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0], + e->dma_len[0], + page_pool_get_dma_dir(q->page_pool)); + mt76_put_page_pool_buf(e->buf, false); + q->tail = (q->tail + 1) % q->ndesc; + q->queued--; + } + spin_unlock_bh(&q->lock); +} + +static struct sk_buff *mt76_npu_dequeue(struct mt76_dev *dev, + struct mt76_queue *q, + u32 *info) +{ + struct airoha_npu_rx_dma_desc *desc = (void *)q->desc; + int i, nframes, index = q->tail; + struct sk_buff *skb = NULL; + + nframes = FIELD_GET(NPU_RX_DMA_PKT_COUNT_MASK, desc[index].info); + nframes = max_t(int, nframes, 1); + + for (i = 0; i < nframes; i++) { + struct mt76_queue_entry *e = &q->entry[index]; + int len = FIELD_GET(NPU_RX_DMA_DESC_CUR_LEN_MASK, + desc[index].ctrl); + + if (!FIELD_GET(NPU_RX_DMA_DESC_DONE_MASK, desc[index].ctrl)) { + dev_kfree_skb(skb); + return NULL; + } + + dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0], + e->dma_len[0], + page_pool_get_dma_dir(q->page_pool)); + + if (!skb) { + skb = napi_build_skb(e->buf, q->buf_size); + if (!skb) + return NULL; + + __skb_put(skb, len); + skb_reset_mac_header(skb); + skb_mark_for_recycle(skb); + } else { + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct page *page = virt_to_head_page(e->buf); + int nr_frags = shinfo->nr_frags; + + if (nr_frags < ARRAY_SIZE(shinfo->frags)) + skb_add_rx_frag(skb, nr_frags, page, + e->buf - page_address(page), + len, q->buf_size); + } + + *info = desc[index].info; + index = (index + 1) % q->ndesc; + } + q->tail = index; + q->queued -= i; + Q_WRITE(q, dma_idx, q->tail); + + return skb; +} + +void mt76_npu_check_ppe(struct mt76_dev *dev, struct sk_buff *skb, + u32 info) +{ + struct airoha_ppe_dev *ppe_dev; + u16 reason, hash; + + if (!mt76_npu_device_active(dev)) + return; + + rcu_read_lock(); + + ppe_dev = rcu_dereference(dev->mmio.ppe_dev); + if (!ppe_dev) + goto out; + + hash = FIELD_GET(NPU_RX_DMA_FOE_ID_MASK, info); + skb_set_hash(skb, hash, PKT_HASH_TYPE_L4); + + reason = FIELD_GET(NPU_RX_DMA_CRSN_MASK, info); + if (reason == PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) { + skb_set_mac_header(skb, 0); + airoha_ppe_dev_check_skb(ppe_dev, skb, hash, true); + } +out: + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(mt76_npu_check_ppe); + +static int mt76_npu_rx_poll(struct napi_struct *napi, int budget) +{ + struct mt76_dev *dev = mt76_priv(napi->dev); + enum mt76_rxq_id qid = napi - dev->napi; + struct airoha_npu *npu; + int done = 0; + + rcu_read_lock(); + + npu = rcu_dereference(dev->mmio.npu); + if (!npu) + goto out; + + while (done < budget) { + struct sk_buff *skb; + u32 info = 0; + + skb = mt76_npu_dequeue(dev, &dev->q_rx[qid], &info); + if (!skb) + break; + + dev->drv->rx_skb(dev, qid, skb, &info); + mt76_rx_poll_complete(dev, qid, napi); + done++; + } + + mt76_npu_fill_rx_queue(dev, &dev->q_rx[qid]); +out: + if (done < budget && napi_complete(napi)) + dev->drv->rx_poll_complete(dev, qid); + + rcu_read_unlock(); + + return done; +} + +static irqreturn_t mt76_npu_irq_handler(int irq, void *q_instance) +{ + struct mt76_queue *q = q_instance; + struct mt76_dev *dev = q->dev; + int qid = q - &dev->q_rx[0]; + int index = qid - MT_RXQ_NPU0; + struct airoha_npu *npu; + u32 status; + + rcu_read_lock(); + + npu = rcu_dereference(dev->mmio.npu); + if (!npu) + goto out; + + status = airoha_npu_wlan_get_irq_status(npu, index); + airoha_npu_wlan_set_irq_status(npu, status); + + airoha_npu_wlan_disable_irq(npu, index); + napi_schedule(&dev->napi[qid]); +out: + rcu_read_unlock(); + + return IRQ_HANDLED; +} + +int mt76_npu_dma_add_buf(struct mt76_phy *phy, struct mt76_queue *q, + struct sk_buff *skb, struct mt76_queue_buf *buf, + void *txwi_ptr) +{ + u16 txwi_len = min_t(u16, phy->dev->drv->txwi_size, NPU_TXWI_LEN); + struct airoha_npu_tx_dma_desc *desc = (void *)q->desc; + int ret; + + /* TODO: Take into account unlinear skbs */ + memcpy(desc[q->head].txwi, txwi_ptr, txwi_len); + desc[q->head].addr = buf->addr; + desc[q->head].ctrl = FIELD_PREP(NPU_TX_DMA_DESC_VEND_LEN_MASK, txwi_len) | + FIELD_PREP(NPU_TX_DMA_DESC_LEN_MASK, skb->len) | + NPU_TX_DMA_DESC_DONE_MASK; + + ret = q->head; + q->entry[q->head].skip_buf0 = true; + q->entry[q->head].skip_buf1 = true; + q->entry[q->head].txwi = NULL; + q->entry[q->head].skb = NULL; + q->entry[q->head].wcid = 0xffff; + + q->head = (q->head + 1) % q->ndesc; + q->queued++; + + return ret; +} + +void mt76_npu_txdesc_cleanup(struct mt76_queue *q, int index) +{ + struct airoha_npu_tx_dma_desc *desc = (void *)q->desc; + + if (!mt76_queue_is_npu_tx(q)) + return; + + desc[index].ctrl &= ~NPU_TX_DMA_DESC_DONE_MASK; +} + +void mt76_npu_queue_setup(struct mt76_dev *dev, struct mt76_queue *q) +{ + int qid = FIELD_GET(MT_QFLAG_WED_RING, q->flags); + bool xmit = mt76_queue_is_npu_tx(q); + struct airoha_npu *npu; + + if (!mt76_queue_is_npu(q)) + return; + + npu = rcu_dereference_protected(dev->mmio.npu, &dev->mutex); + if (npu) + q->wed_regs = airoha_npu_wlan_get_queue_addr(npu, qid, xmit); +} + +int mt76_npu_rx_queue_init(struct mt76_dev *dev, struct mt76_queue *q) +{ + int err, irq, qid = q - &dev->q_rx[0]; + int size, index = qid - MT_RXQ_NPU0; + struct airoha_npu *npu; + const char *name; + + mutex_lock(&dev->mutex); + + npu = rcu_dereference_protected(dev->mmio.npu, &dev->mutex); + irq = npu && index < ARRAY_SIZE(npu->irqs) ? npu->irqs[index] + : -EINVAL; + if (irq < 0) { + err = irq; + goto out; + } + + q->flags = MT_NPU_Q_RX(index); + size = qid == MT_RXQ_NPU1 ? NPU_RX1_DESC_NUM : NPU_RX0_DESC_NUM; + err = dev->queue_ops->alloc(dev, q, 0, size, + MT76_NPU_RX_BUF_SIZE, 0); + if (err) + goto out; + + name = devm_kasprintf(dev->dev, GFP_KERNEL, "mt76-npu.%d", index); + if (!name) { + err = -ENOMEM; + goto out; + } + + err = devm_request_irq(dev->dev, irq, mt76_npu_irq_handler, + IRQF_SHARED, name, q); + if (err) + goto out; + + netif_napi_add(dev->napi_dev, &dev->napi[qid], mt76_npu_rx_poll); + mt76_npu_fill_rx_queue(dev, q); + napi_enable(&dev->napi[qid]); +out: + mutex_unlock(&dev->mutex); + + return err; +} +EXPORT_SYMBOL_GPL(mt76_npu_rx_queue_init); + +static int mt76_npu_setup_tc_block_cb(enum tc_setup_type type, + void *type_data, void *cb_priv) +{ + struct mt76_phy *phy = cb_priv; + struct mt76_dev *dev = phy->dev; + struct airoha_ppe_dev *ppe_dev; + int err = -EOPNOTSUPP; + + if (type != TC_SETUP_CLSFLOWER) + return -EOPNOTSUPP; + + mutex_lock(&dev->mutex); + + ppe_dev = rcu_dereference_protected(dev->mmio.ppe_dev, &dev->mutex); + if (ppe_dev) + err = airoha_ppe_dev_setup_tc_block_cb(ppe_dev, type_data); + + mutex_unlock(&dev->mutex); + + return err; +} + +static int mt76_npu_setup_tc_block(struct mt76_phy *phy, + struct net_device *dev, + struct flow_block_offload *f) +{ + flow_setup_cb_t *cb = mt76_npu_setup_tc_block_cb; + static LIST_HEAD(block_cb_list); + struct flow_block_cb *block_cb; + + if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) + return -EOPNOTSUPP; + + if (!tc_can_offload(dev)) + return -EOPNOTSUPP; + + f->driver_block_list = &block_cb_list; + switch (f->command) { + case FLOW_BLOCK_BIND: + block_cb = flow_block_cb_lookup(f->block, cb, dev); + if (block_cb) { + flow_block_cb_incref(block_cb); + return 0; + } + + block_cb = flow_block_cb_alloc(cb, dev, phy, NULL); + if (IS_ERR(block_cb)) + return PTR_ERR(block_cb); + + flow_block_cb_incref(block_cb); + flow_block_cb_add(block_cb, f); + list_add_tail(&block_cb->driver_list, &block_cb_list); + return 0; + case FLOW_BLOCK_UNBIND: + block_cb = flow_block_cb_lookup(f->block, cb, dev); + if (!block_cb) + return -ENOENT; + + if (!flow_block_cb_decref(block_cb)) { + flow_block_cb_remove(block_cb, f); + list_del(&block_cb->driver_list); + } + return 0; + default: + return -EOPNOTSUPP; + } +} + +int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *dev, enum tc_setup_type type, + void *type_data) +{ + struct mt76_phy *phy = hw->priv; + + if (!tc_can_offload(dev)) + return -EOPNOTSUPP; + + if (!mt76_npu_device_active(phy->dev)) + return -EOPNOTSUPP; + + switch (type) { + case TC_SETUP_BLOCK: + case TC_SETUP_FT: + return mt76_npu_setup_tc_block(phy, dev, type_data); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(mt76_npu_net_setup_tc); + +void mt76_npu_disable_irqs(struct mt76_dev *dev) +{ + struct airoha_npu *npu; + int i; + + rcu_read_lock(); + + npu = rcu_dereference(dev->mmio.npu); + if (!npu) + goto unlock; + + for (i = MT_RXQ_NPU0; i <= MT_RXQ_NPU1; i++) { + int qid = i - MT_RXQ_NPU0; + u32 status; + + status = airoha_npu_wlan_get_irq_status(npu, qid); + airoha_npu_wlan_set_irq_status(npu, status); + airoha_npu_wlan_disable_irq(npu, qid); + } +unlock: + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(mt76_npu_disable_irqs); + +int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type) +{ + struct airoha_ppe_dev *ppe_dev; + struct airoha_npu *npu; + int err = 0; + + /* NPU offloading is only supported by MT7992 */ + if (!is_mt7992(dev)) + return 0; + + mutex_lock(&dev->mutex); + + npu = airoha_npu_get(dev->dev); + if (IS_ERR(npu)) { + request_module("airoha-npu"); + npu = airoha_npu_get(dev->dev); + } + + if (IS_ERR(npu)) { + err = PTR_ERR(npu); + goto error_unlock; + } + + ppe_dev = airoha_ppe_get_dev(dev->dev); + if (IS_ERR(ppe_dev)) { + request_module("airoha-eth"); + ppe_dev = airoha_ppe_get_dev(dev->dev); + } + + if (IS_ERR(ppe_dev)) { + err = PTR_ERR(ppe_dev); + goto error_npu_put; + } + + err = airoha_npu_wlan_init_reserved_memory(npu); + if (err) + goto error_ppe_put; + + dev->dma_dev = npu->dev; + dev->mmio.phy_addr = phy_addr; + dev->mmio.npu_type = type; + /* NPU offloading requires HW-RRO for RX packet reordering. */ + dev->hwrro_mode = MT76_HWRRO_V3_1; + + rcu_assign_pointer(dev->mmio.npu, npu); + rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev); + synchronize_rcu(); + + mutex_unlock(&dev->mutex); + + return 0; + +error_ppe_put: + airoha_ppe_put_dev(ppe_dev); +error_npu_put: + airoha_npu_put(npu); +error_unlock: + mutex_unlock(&dev->mutex); + + return err; +} +EXPORT_SYMBOL_GPL(mt76_npu_init); + +void mt76_npu_deinit(struct mt76_dev *dev) +{ + struct airoha_ppe_dev *ppe_dev; + struct airoha_npu *npu; + + mutex_lock(&dev->mutex); + + npu = rcu_replace_pointer(dev->mmio.npu, NULL, + lockdep_is_held(&dev->mutex)); + if (npu) + airoha_npu_put(npu); + + ppe_dev = rcu_replace_pointer(dev->mmio.ppe_dev, NULL, + lockdep_is_held(&dev->mutex)); + if (ppe_dev) + airoha_ppe_put_dev(ppe_dev); + + mutex_unlock(&dev->mutex); + + mt76_npu_queue_cleanup(dev, &dev->q_rx[MT_RXQ_NPU0]); + mt76_npu_queue_cleanup(dev, &dev->q_rx[MT_RXQ_NPU1]); +} diff --git a/include/linux/soc/airoha/airoha_offload.h b/include/linux/soc/airoha/airoha_offload.h index 6f66eb339b3f..4d23cbb7d407 100644 --- a/include/linux/soc/airoha/airoha_offload.h +++ b/include/linux/soc/airoha/airoha_offload.h @@ -6,6 +6,7 @@ #ifndef AIROHA_OFFLOAD_H #define AIROHA_OFFLOAD_H +#include #include #include -- cgit v1.2.3 From 24d4da5c2565313c2ad3c43449937a9351a64407 Mon Sep 17 00:00:00 2001 From: Ria Thomas Date: Mon, 24 Nov 2025 18:26:37 +0530 Subject: wifi: ieee80211: correct FILS status codes The FILS status codes are set to 108/109, but the IEEE 802.11-2020 spec defines them as 112/113. Update the enum so it matches the specification and keeps the kernel consistent with standard values. Fixes: a3caf7440ded ("cfg80211: Add support for FILS shared key authentication offload") Signed-off-by: Ria Thomas Reviewed-by: Jeff Johnson Link: https://patch.msgid.link/20251124125637.3936154-1-ria.thomas@morsemicro.com Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index d55d8ea3a8be..96439de55f07 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1493,8 +1493,8 @@ enum ieee80211_statuscode { WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99, WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103, /* 802.11ai */ - WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 108, - WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 109, + WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 112, + WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 113, WLAN_STATUS_SAE_HASH_TO_ELEMENT = 126, WLAN_STATUS_SAE_PK = 127, WLAN_STATUS_DENIED_TID_TO_LINK_MAPPING = 133, -- cgit v1.2.3