Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen
2026-03-18 11:06:07 +08:00
29 changed files with 866 additions and 667 deletions
@@ -0,0 +1,412 @@
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Thu, 29 Jan 2026 14:15:46 +0100
Subject: [PATCH] wifi: mac80211: Add eMLSR/eMLMR action frame parsing support
Introduce support in AP mode for parsing of the Operating Mode Notification
frame sent by the client to enable/disable MLO eMLSR or eMLMR if supported
by both the AP and the client.
Add drv_set_eml_op_mode mac80211 callback in order to configure underlay
driver with eMLSR/eMLMR info.
Tested-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20260129-mac80211-emlsr-v4-1-14bdadf57380@kernel.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1612,6 +1612,12 @@ struct ieee80211_mgmt {
u8 action_code;
u8 variable[];
} __packed epcs;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u8 control;
+ u8 variable[];
+ } __packed eml_omn;
} u;
} __packed action;
DECLARE_FLEX_ARRAY(u8, body); /* Generic frame body */
@@ -5462,6 +5468,17 @@ struct ieee80211_mle_tdls_common_info {
/* no fixed fields in PRIO_ACCESS */
+#define IEEE80211_EML_CTRL_EMLSR_MODE BIT(0)
+#define IEEE80211_EML_CTRL_EMLMR_MODE BIT(1)
+#define IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE BIT(2)
+#define IEEE80211_EML_CTRL_INDEV_COEX_ACT BIT(3)
+
+#define IEEE80211_EML_EMLSR_PAD_DELAY 0x07
+#define IEEE80211_EML_EMLSR_TRANS_DELAY 0x38
+
+#define IEEE80211_EML_EMLMR_RX_MCS_MAP 0xf0
+#define IEEE80211_EML_EMLMR_TX_MCS_MAP 0x0f
+
/**
* ieee80211_mle_common_size - check multi-link element common size
* @data: multi-link element, must already be checked for size using
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1901,6 +1901,31 @@ enum ieee80211_offload_flags {
};
/**
+ * struct ieee80211_eml_params - EHT Operating mode notification parameters
+ *
+ * EML Operating mode notification parameters received in the Operating mode
+ * notification frame. This struct is used as a container to pass the info to
+ * the underlay driver.
+ *
+ * @link_id: the link ID where the Operating mode notification frame has been
+ * received.
+ * @control: EML control field defined in P802.11be section 9.4.1.76.
+ * @link_bitmap: eMLSR/eMLMR enabled links defined in P802.11be
+ * section 9.4.1.76.
+ * @emlmr_mcs_map_count: eMLMR number of valid mcs_map_bw fields according to
+ * P802.11be section 9.4.1.76 (valid if eMLMR mode control bit is set).
+ * @emlmr_mcs_map_bw: eMLMR supported MCS and NSS set subfileds defined in
+ * P802.11be section 9.4.1.76 (valid if eMLMR mode control bit is set).
+ */
+struct ieee80211_eml_params {
+ u8 link_id;
+ u8 control;
+ u16 link_bitmap;
+ u8 emlmr_mcs_map_count;
+ u8 emlmr_mcs_map_bw[9];
+};
+
+/**
* struct ieee80211_vif_cfg - interface configuration
* @assoc: association status
* @ibss_joined: indicates whether this station is part of an IBSS or not
@@ -4509,6 +4534,9 @@ struct ieee80211_prep_tx_info {
* interface with the specified type would be added, and thus drivers that
* implement this callback need to handle such cases. The type is the full
* &enum nl80211_iftype.
+ * @set_eml_op_mode: Configure eMLSR/eMLMR operation mode in the underlay
+ * driver according to the parameter received in the EML Operating mode
+ * notification frame.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -4904,6 +4932,10 @@ struct ieee80211_ops {
struct ieee80211_neg_ttlm *ttlm);
void (*prep_add_interface)(struct ieee80211_hw *hw,
enum nl80211_iftype type);
+ int (*set_eml_op_mode)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_eml_params *eml_params);
};
/**
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1772,4 +1772,25 @@ drv_prep_add_interface(struct ieee80211_
trace_drv_return_void(local);
}
+static inline int drv_set_eml_op_mode(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ struct ieee80211_eml_params *eml_params)
+{
+ struct ieee80211_local *local = sdata->local;
+ int ret = -EOPNOTSUPP;
+
+ might_sleep();
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+ trace_drv_set_eml_op_mode(local, sdata, sta, eml_params->link_id,
+ eml_params->control,
+ eml_params->link_bitmap);
+ if (local->ops->set_eml_op_mode)
+ ret = local->ops->set_eml_op_mode(&local->hw, &sdata->vif,
+ sta, eml_params);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
#endif /* __MAC80211_DRIVER_OPS */
--- a/net/mac80211/eht.c
+++ b/net/mac80211/eht.c
@@ -5,6 +5,7 @@
* Copyright(c) 2021-2025 Intel Corporation
*/
+#include "driver-ops.h"
#include "ieee80211_i.h"
void
@@ -102,3 +103,177 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(stru
ieee80211_sta_recalc_aggregates(&link_sta->sta->sta);
}
+
+static void
+ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *req, int opt_len)
+{
+ int len = offsetofend(struct ieee80211_mgmt, u.action.u.eml_omn);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_mgmt *mgmt;
+ struct sk_buff *skb;
+
+ len += opt_len; /* optional len */
+ skb = dev_alloc_skb(local->tx_headroom + len);
+ if (!skb)
+ return;
+
+ skb_reserve(skb, local->tx_headroom);
+ mgmt = skb_put_zero(skb, len);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+ memcpy(mgmt->da, req->sa, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+ memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+
+ mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
+ mgmt->u.action.u.eml_omn.action_code =
+ WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF;
+ mgmt->u.action.u.eml_omn.dialog_token =
+ req->u.action.u.eml_omn.dialog_token;
+ mgmt->u.action.u.eml_omn.control = req->u.action.u.eml_omn.control &
+ ~(IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE |
+ IEEE80211_EML_CTRL_INDEV_COEX_ACT);
+ /* Copy optional fields from the received notification frame */
+ memcpy(mgmt->u.action.u.eml_omn.variable,
+ req->u.action.u.eml_omn.variable, opt_len);
+
+ ieee80211_tx_skb(sdata, skb);
+}
+
+void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ int len = offsetofend(struct ieee80211_mgmt, u.action.u.eml_omn);
+ enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif);
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ const struct wiphy_iftype_ext_capab *ift_ext_capa;
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ struct ieee80211_local *local = sdata->local;
+ u8 control = mgmt->u.action.u.eml_omn.control;
+ u8 *ptr = mgmt->u.action.u.eml_omn.variable;
+ struct ieee80211_eml_params eml_params = {
+ .link_id = status->link_id,
+ };
+ struct sta_info *sta;
+ int opt_len = 0;
+
+ if (!ieee80211_vif_is_mld(&sdata->vif))
+ return;
+
+ /* eMLSR and eMLMR can't be enabled at the same time */
+ if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) &&
+ (control & IEEE80211_EML_CTRL_EMLMR_MODE))
+ return;
+
+ if ((control & IEEE80211_EML_CTRL_EMLMR_MODE) &&
+ (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE))
+ return;
+
+ ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type);
+ if (!ift_ext_capa)
+ return;
+
+ if (!status->link_valid)
+ return;
+
+ sta = sta_info_get_bss(sdata, mgmt->sa);
+ if (!sta)
+ return;
+
+ if (control & IEEE80211_EML_CTRL_EMLSR_MODE) {
+ u8 emlsr_param_update_len;
+
+ if (!(ift_ext_capa->eml_capabilities &
+ IEEE80211_EML_CAP_EMLSR_SUPP))
+ return;
+
+ opt_len += sizeof(__le16); /* eMLSR link_bitmap */
+ /* eMLSR param update field is not part of Notfication frame
+ * sent by the AP to client so account it separately.
+ */
+ emlsr_param_update_len =
+ !!(control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE);
+
+ if (skb->len < len + opt_len + emlsr_param_update_len)
+ return;
+
+ if (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE) {
+ u8 pad_delay, trans_delay;
+
+ pad_delay = u8_get_bits(ptr[2],
+ IEEE80211_EML_EMLSR_PAD_DELAY);
+ if (pad_delay >
+ IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US)
+ return;
+
+ trans_delay = u8_get_bits(ptr[2],
+ IEEE80211_EML_EMLSR_TRANS_DELAY);
+ if (trans_delay >
+ IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US)
+ return;
+
+ /* Update sta padding and transition delay */
+ sta->sta.eml_cap =
+ u8_replace_bits(sta->sta.eml_cap,
+ pad_delay,
+ IEEE80211_EML_CAP_EMLSR_PADDING_DELAY);
+ sta->sta.eml_cap =
+ u8_replace_bits(sta->sta.eml_cap,
+ trans_delay,
+ IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY);
+ }
+ }
+
+ if (control & IEEE80211_EML_CTRL_EMLMR_MODE) {
+ u8 mcs_map_size;
+ int i;
+
+ if (!(ift_ext_capa->eml_capabilities &
+ IEEE80211_EML_CAP_EMLMR_SUPPORT))
+ return;
+
+ opt_len += sizeof(__le16); /* eMLMR link_bitmap */
+ opt_len++; /* eMLMR mcs_map_count */
+ if (skb->len < len + opt_len)
+ return;
+
+ eml_params.emlmr_mcs_map_count = ptr[2];
+ if (eml_params.emlmr_mcs_map_count > 2)
+ return;
+
+ mcs_map_size = 3 * (1 + eml_params.emlmr_mcs_map_count);
+ opt_len += mcs_map_size;
+ if (skb->len < len + opt_len)
+ return;
+
+ for (i = 0; i < mcs_map_size; i++) {
+ u8 rx_mcs, tx_mcs;
+
+ rx_mcs = u8_get_bits(ptr[3 + i],
+ IEEE80211_EML_EMLMR_RX_MCS_MAP);
+ if (rx_mcs > 8)
+ return;
+
+ tx_mcs = u8_get_bits(ptr[3 + i],
+ IEEE80211_EML_EMLMR_TX_MCS_MAP);
+ if (tx_mcs > 8)
+ return;
+ }
+
+ memcpy(eml_params.emlmr_mcs_map_bw, &ptr[3], mcs_map_size);
+ }
+
+ if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) ||
+ (control & IEEE80211_EML_CTRL_EMLMR_MODE)) {
+ eml_params.link_bitmap = get_unaligned_le16(ptr);
+ if ((eml_params.link_bitmap & sdata->vif.active_links) !=
+ eml_params.link_bitmap)
+ return;
+ }
+
+ if (drv_set_eml_op_mode(sdata, &sta->sta, &eml_params))
+ return;
+
+ ieee80211_send_eml_op_mode_notif(sdata, mgmt, opt_len);
+}
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2859,6 +2859,8 @@ void ieee80211_destroy_frag_cache(struct
u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata);
+void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
void
ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1630,7 +1630,15 @@ static void ieee80211_iface_process_skb(
}
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_EHT) {
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ switch (mgmt->u.action.u.eml_omn.action_code) {
+ case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF:
+ ieee80211_rx_eml_op_mode_notif(sdata, skb);
+ break;
+ default:
+ break;
+ }
+ } else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
switch (mgmt->u.action.u.ttlm_req.action_code) {
case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ:
ieee80211_process_neg_ttlm_req(sdata, mgmt,
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3834,6 +3834,14 @@ ieee80211_rx_h_action(struct ieee80211_r
u.action.u.epcs))
goto invalid;
goto queue;
+ case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF:
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
+ break;
+
+ if (len < offsetofend(typeof(*mgmt),
+ u.action.u.eml_omn))
+ goto invalid;
+ goto queue;
default:
break;
}
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -3359,6 +3359,38 @@ TRACE_EVENT(drv_prep_add_interface,
)
);
+TRACE_EVENT(drv_set_eml_op_mode,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ unsigned int link_id,
+ u8 control, u16 link_bitmap),
+
+ TP_ARGS(local, sdata, sta, link_id, control, link_bitmap),
+
+ TP_STRUCT__entry(LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(u32, link_id)
+ __field(u8, control)
+ __field(u16, link_bitmap)),
+
+ TP_fast_assign(LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_NAMED_ASSIGN(sta);
+ __entry->link_id = link_id;
+ __entry->control = control;
+ __entry->link_bitmap = link_bitmap;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT
+ " (link:%d control:%02x link_bitmap:%04x)",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->link_id,
+ __entry->control, __entry->link_bitmap
+ )
+);
+
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--- /dev/null
+++ b/include/linux/ieee80211-eht.h
@@ -0,0 +1 @@
+#include <linux/ieee80211.h>
+20 -3
View File
@@ -8,9 +8,9 @@ PKG_LICENSE_FILES:=
PKG_SOURCE_URL:=https://github.com/openwrt/mt76
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2025-11-06
PKG_SOURCE_VERSION:=eb567bc7f9b692bbf1ddfe31dd740861c58ec85b
PKG_MIRROR_HASH:=7cfe242a5494cdf5d8e8eea86633778a525717528bcce70aedef96eee5594383
PKG_SOURCE_DATE:=2026-03-05
PKG_SOURCE_VERSION:=9f95baf93a070692ed922a2fc57ef8bfde801c84
PKG_MIRROR_HASH:=eaca371ec6f8d0f089d098a3f7fc8c5819aea090e05f4f3d9e8a9b2a2d4f2ff8
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_USE_NINJA:=0
@@ -328,6 +328,12 @@ define KernelPackage/mt7996e
AUTOLOAD:=$(call AutoProbe,mt7996e)
endef
define KernelPackage/mt7990-firmware
$(KernelPackage/mt76-default)
TITLE:=MediaTek MT7990 firmware
DEPENDS+=+kmod-mt7996e
endef
define KernelPackage/mt7992-firmware
$(KernelPackage/mt76-default)
TITLE:=MediaTek MT7992 firmware
@@ -665,6 +671,16 @@ define KernelPackage/mt7925-firmware/install
$(1)/lib/firmware/mediatek/mt7925
endef
define KernelPackage/mt7990-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996
cp \
$(PKG_BUILD_DIR)/firmware/mt7996/mt7990_eeprom.bin \
$(PKG_BUILD_DIR)/firmware/mt7996/mt7990_eeprom_2i5i.bin \
$(PKG_BUILD_DIR)/firmware/mt7996/mt7990_rom_patch.bin \
$(PKG_BUILD_DIR)/firmware/mt7996/mt7990_wm.bin \
$(1)/lib/firmware/mediatek/mt7996
endef
define KernelPackage/mt7992-firmware/install
$(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996
cp \
@@ -769,6 +785,7 @@ $(eval $(call KernelPackage,mt7921e))
$(eval $(call KernelPackage,mt7925u))
$(eval $(call KernelPackage,mt7925e))
$(eval $(call KernelPackage,mt7996e))
$(eval $(call KernelPackage,mt7990-firmware))
$(eval $(call KernelPackage,mt7992-firmware))
$(eval $(call KernelPackage,mt7992-23-firmware))
$(eval $(call KernelPackage,mt7996-firmware-common))
@@ -0,0 +1,42 @@
From e78688a4f44478a9270813ac494fc548ed6b3be9 Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Fri, 13 Mar 2026 12:19:37 +0100
Subject: [PATCH] wifi: mt76: mt7915: set mt76 specific PS flag
mt76 tracks the PSM state of a sta internally with a wcid flag. TX to
such clients is skipped based on the presence of this flag.
This flag was not added to the PS state notify handler for MT7915 chips.
Without this flag, mt76 queues pending frames to the hardware,
accounting for airtime when a PSM notification is received while in a TX
iteration.
Set the PS flag for the STA WCID to prevent this from happening. TX gets
skipped in presence of this flag.
Link: https://patchwork.kernel.org/project/linux-wireless/patch/20260313112502.2026974-1-mail@david-bauer.net/
Signed-off-by: David Bauer <mail@david-bauer.net>
---
mt7915/mcu.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
index 6625f905..52c89d2b 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -421,6 +421,11 @@ static void mt7915_mcu_rx_ps_sync(struct mt7915_dev *dev, struct sk_buff *skb)
if (!sta)
goto out;
+ if (p->ps_bit)
+ set_bit(MT_WCID_FLAG_PS, &wcid->flags);
+ else
+ clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
+
ieee80211_sta_ps_transition_ni(sta, !!p->ps_bit);
out:
--
2.51.0
@@ -1,25 +0,0 @@
From f473d66ab595d5f37aedc868bfe407da0a1245c8 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 12 Nov 2025 16:32:44 +0000
Subject: wifi: mt76: mt7996: fix crash in mt7996_tx_prepare_skb
Add missing NULL pointer check. In mesh mode, sta can be NULL even for
qosdata frames.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Upstream: https://github.com/openwrt/mt76/commit/f473d66ab595d5f37aedc868bfe407da0a1245c8
---
mt7996/mac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -1061,7 +1061,7 @@ int mt7996_tx_prepare_skb(struct mt76_de
if (!wcid)
wcid = &dev->mt76.global_wcid;
- if ((is_8023 || ieee80211_is_data_qos(hdr->frame_control)) && sta->mlo &&
+ if ((is_8023 || ieee80211_is_data_qos(hdr->frame_control)) && sta && sta->mlo &&
likely(tx_info->skb->protocol != cpu_to_be16(ETH_P_PAE))) {
u8 tid = tx_info->skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@@ -1,406 +0,0 @@
From 6434ec7449b854fbdf8b1cab9c142e67a0a8a9a4 Mon Sep 17 00:00:00 2001
From: Roopni Devanathan <quic_rdevanat@quicinc.com>
Date: Sun, 15 Jun 2025 13:53:09 +0530
Subject: [PATCH] wifi: cfg80211/mac80211: Add support to get radio index
Currently, per-radio attributes are set on per-phy basis, i.e., all the
radios present in a wiphy will take attributes values sent from user. But
each radio in a wiphy can get different values from userspace based on
its requirement.
To extend support to set per-radio attributes, add support to get radio
index from userspace. Add an NL attribute - NL80211_ATTR_WIPHY_RADIO_INDEX,
to get user specified radio index for which attributes should be changed.
Pass this to individual drivers, so that the drivers can use this radio
index to change per-radio attributes when necessary. Currently, per-radio
attributes identified are:
NL80211_ATTR_WIPHY_TX_POWER_LEVEL
NL80211_ATTR_WIPHY_ANTENNA_TX
NL80211_ATTR_WIPHY_ANTENNA_RX
NL80211_ATTR_WIPHY_RETRY_SHORT
NL80211_ATTR_WIPHY_RETRY_LONG
NL80211_ATTR_WIPHY_FRAG_THRESHOLD
NL80211_ATTR_WIPHY_RTS_THRESHOLD
NL80211_ATTR_WIPHY_COVERAGE_CLASS
NL80211_ATTR_TXQ_LIMIT
NL80211_ATTR_TXQ_MEMORY_LIMIT
NL80211_ATTR_TXQ_QUANTUM
By default, the radio index is set to -1. This means the attribute should
be treated as a global configuration. If the user has not specified any
index, then the radio index passed to individual drivers would be -1. This
would indicate that the attribute applies to all radios in that wiphy.
Signed-off-by: Roopni Devanathan <quic_rdevanat@quicinc.com>
Link: https://patch.msgid.link/20250615082312.619639-2-quic_rdevanat@quicinc.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
mac80211.c | 3 ++-
mt76.h | 3 ++-
mt7603/main.c | 5 +++--
mt7615/main.c | 11 +++++++----
mt76x0/main.c | 2 +-
mt76x0/mt76x0.h | 2 +-
mt76x02.h | 4 ++--
mt76x02_util.c | 4 ++--
mt76x2/pci_main.c | 6 +++---
mt76x2/usb_main.c | 2 +-
mt7915/main.c | 13 ++++++++-----
mt7921/main.c | 8 +++++---
mt7925/main.c | 8 +++++---
mt792x.h | 3 ++-
mt792x_core.c | 3 ++-
mt7996/main.c | 11 +++++++----
16 files changed, 53 insertions(+), 35 deletions(-)
--- a/mac80211.c
+++ b/mac80211.c
@@ -1936,7 +1936,8 @@ void mt76_sw_scan_complete(struct ieee80
}
EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
-int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
+int mt76_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant,
+ u32 *rx_ant)
{
struct mt76_phy *phy = hw->priv;
struct mt76_dev *dev = phy->dev;
--- a/mt76.h
+++ b/mt76.h
@@ -1598,7 +1598,8 @@ int mt76_get_sar_power(struct mt76_phy *
void mt76_csa_check(struct mt76_dev *dev);
void mt76_csa_finish(struct mt76_dev *dev);
-int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
+int mt76_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant,
+ u32 *rx_ant);
int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id);
int mt76_get_rate(struct mt76_dev *dev,
--- a/mt7603/main.c
+++ b/mt7603/main.c
@@ -216,7 +216,7 @@ static int mt7603_set_sar_specs(struct i
}
static int
-mt7603_config(struct ieee80211_hw *hw, u32 changed)
+mt7603_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct mt7603_dev *dev = hw->priv;
int ret = 0;
@@ -657,7 +657,8 @@ mt7603_sta_rate_tbl_update(struct ieee80
}
static void
-mt7603_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
+mt7603_set_coverage_class(struct ieee80211_hw *hw, int radio_idx,
+ s16 coverage_class)
{
struct mt7603_dev *dev = hw->priv;
--- a/mt7615/main.c
+++ b/mt7615/main.c
@@ -420,7 +420,7 @@ static int mt7615_set_sar_specs(struct i
return mt76_update_channel(phy->mt76);
}
-static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
+static int mt7615_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
@@ -784,7 +784,8 @@ static void mt7615_tx(struct ieee80211_h
mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb);
}
-static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
+static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
+ u32 val)
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
@@ -972,7 +973,8 @@ mt7615_offset_tsf(struct ieee80211_hw *h
}
static void
-mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
+mt7615_set_coverage_class(struct ieee80211_hw *hw, int radio_idx,
+ s16 coverage_class)
{
struct mt7615_phy *phy = mt7615_hw_phy(hw);
struct mt7615_dev *dev = phy->dev;
@@ -984,7 +986,8 @@ mt7615_set_coverage_class(struct ieee802
}
static int
-mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+mt7615_set_antenna(struct ieee80211_hw *hw, int radio_idx,
+ u32 tx_ant, u32 rx_ant)
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
--- a/mt76x0/main.c
+++ b/mt76x0/main.c
@@ -57,7 +57,7 @@ out:
}
EXPORT_SYMBOL_GPL(mt76x0_set_sar_specs);
-int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
+int mt76x0_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct mt76x02_dev *dev = hw->priv;
--- a/mt76x0/mt76x0.h
+++ b/mt76x0/mt76x0.h
@@ -48,7 +48,7 @@ void mt76x0_chip_onoff(struct mt76x02_de
void mt76x0_mac_stop(struct mt76x02_dev *dev);
-int mt76x0_config(struct ieee80211_hw *hw, u32 changed);
+int mt76x0_config(struct ieee80211_hw *hw, int radio_idx, u32 changed);
int mt76x0_set_channel(struct mt76_phy *mphy);
int mt76x0_set_sar_specs(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar);
--- a/mt76x02.h
+++ b/mt76x02.h
@@ -183,8 +183,8 @@ void mt76x02_wdt_work(struct work_struct
void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr);
void mt76x02_set_tx_ackto(struct mt76x02_dev *dev);
void mt76x02_set_coverage_class(struct ieee80211_hw *hw,
- s16 coverage_class);
-int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val);
+ int radio_idx, s16 coverage_class);
+int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val);
void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len);
bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update);
void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
--- a/mt76x02_util.c
+++ b/mt76x02_util.c
@@ -548,7 +548,7 @@ void mt76x02_set_tx_ackto(struct mt76x02
EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto);
void mt76x02_set_coverage_class(struct ieee80211_hw *hw,
- s16 coverage_class)
+ int radio_idx, s16 coverage_class)
{
struct mt76x02_dev *dev = hw->priv;
@@ -559,7 +559,7 @@ void mt76x02_set_coverage_class(struct i
}
EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class);
-int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
+int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val)
{
struct mt76x02_dev *dev = hw->priv;
--- a/mt76x2/pci_main.c
+++ b/mt76x2/pci_main.c
@@ -54,7 +54,7 @@ int mt76x2e_set_channel(struct mt76_phy
}
static int
-mt76x2_config(struct ieee80211_hw *hw, u32 changed)
+mt76x2_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct mt76x02_dev *dev = hw->priv;
@@ -99,8 +99,8 @@ mt76x2_flush(struct ieee80211_hw *hw, st
{
}
-static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
- u32 rx_ant)
+static int mt76x2_set_antenna(struct ieee80211_hw *hw, int radio_idx,
+ u32 tx_ant, u32 rx_ant)
{
struct mt76x02_dev *dev = hw->priv;
--- a/mt76x2/usb_main.c
+++ b/mt76x2/usb_main.c
@@ -50,7 +50,7 @@ int mt76x2u_set_channel(struct mt76_phy
}
static int
-mt76x2u_config(struct ieee80211_hw *hw, u32 changed)
+mt76x2u_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct mt76x02_dev *dev = hw->priv;
int err = 0;
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -449,7 +449,8 @@ out:
return err;
}
-static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
+static int mt7915_config(struct ieee80211_hw *hw, int radio_idx,
+ u32 changed)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
@@ -913,7 +914,8 @@ static void mt7915_tx(struct ieee80211_h
mt76_tx(mphy, control->sta, wcid, skb);
}
-static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
+static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
+ u32 val)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
@@ -1109,7 +1111,8 @@ mt7915_offset_tsf(struct ieee80211_hw *h
}
static void
-mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
+mt7915_set_coverage_class(struct ieee80211_hw *hw, int radio_idx,
+ s16 coverage_class)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_dev *dev = phy->dev;
@@ -1121,7 +1124,7 @@ mt7915_set_coverage_class(struct ieee802
}
static int
-mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+mt7915_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_ant)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
@@ -1699,7 +1702,7 @@ mt7915_twt_teardown_request(struct ieee8
}
static int
-mt7915_set_frag_threshold(struct ieee80211_hw *hw, u32 val)
+mt7915_set_frag_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val)
{
return 0;
}
--- a/mt7921/main.c
+++ b/mt7921/main.c
@@ -626,7 +626,7 @@ void mt7921_set_runtime_pm(struct mt792x
mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
}
-static int mt7921_config(struct ieee80211_hw *hw, u32 changed)
+static int mt7921_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_phy *phy = mt792x_hw_phy(hw);
@@ -915,7 +915,8 @@ void mt7921_mac_sta_remove(struct mt76_d
}
EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove);
-static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
+static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
+ u32 val)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
@@ -1096,7 +1097,8 @@ mt7921_stop_sched_scan(struct ieee80211_
}
static int
-mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+mt7921_set_antenna(struct ieee80211_hw *hw, int radio_idx,
+ u32 tx_ant, u32 rx_ant)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_phy *phy = mt792x_hw_phy(hw);
--- a/mt7925/main.c
+++ b/mt7925/main.c
@@ -758,7 +758,7 @@ void mt7925_set_runtime_pm(struct mt792x
mt7925_mcu_set_deep_sleep(dev, pm->ds_enable);
}
-static int mt7925_config(struct ieee80211_hw *hw, u32 changed)
+static int mt7925_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
int ret = 0;
@@ -1219,7 +1219,8 @@ void mt7925_mac_sta_remove(struct mt76_d
}
EXPORT_SYMBOL_GPL(mt7925_mac_sta_remove);
-static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
+static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
+ u32 val)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
@@ -1438,7 +1439,8 @@ mt7925_stop_sched_scan(struct ieee80211_
}
static int
-mt7925_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+mt7925_set_antenna(struct ieee80211_hw *hw, int radio_idx,
+ u32 tx_ant, u32 rx_ant)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_phy *phy = mt792x_hw_phy(hw);
--- a/mt792x.h
+++ b/mt792x.h
@@ -413,7 +413,8 @@ void mt792x_sta_statistics(struct ieee80
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct station_info *sinfo);
-void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class);
+void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx,
+ s16 coverage_class);
void mt792x_dma_cleanup(struct mt792x_dev *dev);
int mt792x_dma_enable(struct mt792x_dev *dev);
int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force);
--- a/mt792x_core.c
+++ b/mt792x_core.c
@@ -601,7 +601,8 @@ void mt792x_sta_statistics(struct ieee80
}
EXPORT_SYMBOL_GPL(mt792x_sta_statistics);
-void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
+void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx,
+ s16 coverage_class)
{
struct mt792x_phy *phy = mt792x_hw_phy(hw);
struct mt792x_dev *dev = phy->dev;
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -644,7 +644,7 @@ static int mt7996_set_key(struct ieee802
return err;
}
-static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
+static int mt7996_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
{
return 0;
}
@@ -1370,7 +1370,8 @@ unlock:
rcu_read_unlock();
}
-static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
+static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
+ u32 val)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
int i, ret = 0;
@@ -1590,7 +1591,8 @@ unlock:
}
static void
-mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
+mt7996_set_coverage_class(struct ieee80211_hw *hw, int radio_idx,
+ s16 coverage_class)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy;
@@ -1604,7 +1606,8 @@ mt7996_set_coverage_class(struct ieee802
}
static int
-mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+mt7996_set_antenna(struct ieee80211_hw *hw, int radio_idx,
+ u32 tx_ant, u32 rx_ant)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
int i;
+6 -5
View File
@@ -1,14 +1,15 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=libubox
PKG_RELEASE=1
PKG_RELEASE=2
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/libubox.git
PKG_MIRROR_HASH:=fb43a86d13bbbf16d47358caa2fe7eec3b802e3a57ba5142520add159469c927
PKG_SOURCE_DATE:=2026-02-13
PKG_SOURCE_VERSION:=1aa36ee774c8db4d7a396903e0d2e1fb79ee8bf1
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
PKG_MIRROR_HASH:=55b2298ea74bb4c7267e4b615d442aeff601e0de88ec0e641e4c40eed8454e85
PKG_SOURCE_DATE:=2026-03-13
PKG_SOURCE_VERSION:=815633847cd32ffe6da28943cbeb37edc88265c8
# PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
PKG_ABI_VERSION:=20260213
CMAKE_INSTALL:=1
PKG_LICENSE:=ISC
@@ -354,10 +354,10 @@ function device_htmode_append(config) {
config.vht_capab += '[BF-ANTENNA-' + min(((vht_capab >> 13) & 3) + 1, config.beamformer_antennas) + ']';
/* supported Channel widths */
if ((vht_capab & 0xc) == 8 && config.vht160 <= 2)
config.vht_capab += '[VHT160-80PLUS80]';
else if ((vht_capab & 0xc) == 4 && config.vht160 <= 2)
if (((vht_capab & 0xc) == 4 || (vht_capab & 0xc) == 8) && config.vht160 >= 1)
config.vht_capab += '[VHT160]';
if ((vht_capab & 0xc) == 8 && config.vht160 >= 2)
config.vht_capab += '[VHT160-80PLUS80]';
/* maximum MPDU length */
if ((vht_capab & 3) > 1 && config.vht_max_mpdu >= 11454)
+3 -3
View File
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/odhcpd.git
PKG_MIRROR_HASH:=ece983c3342db39ed5cfb48f32cf6af90f854cfc44ecccd09a05a91b9aa32289
PKG_SOURCE_DATE:=2026-01-19
PKG_SOURCE_VERSION:=2e5068b9729011587b9c1c489b65480e8219a97d
PKG_MIRROR_HASH:=95c64e712210ffba44452bcf63b771ad4859a116bc9a13e67ffbd09654fb4cae
PKG_SOURCE_DATE:=2026-03-16
PKG_SOURCE_VERSION:=edf2e523b7ae23830a7377343b66c7675c7703c7
PKG_MAINTAINER:=Álvaro Fernández Rojas <noltari@gmail.com>
PKG_LICENSE:=GPL-2.0
+3 -3
View File
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_URL=$(PROJECT_GIT)/project/mdnsd.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2025-10-04
PKG_SOURCE_VERSION:=2f75344fd0cc848558bf2ea3a94c0bf8b903ff89
PKG_MIRROR_HASH:=ca03392a39e3e38b276514d4627bab25093cf873abf361352c82dfec0c4bdc93
PKG_SOURCE_DATE:=2026-02-06
PKG_SOURCE_VERSION:=a52cdb354d13c179150d2ba26f9f8a51d418b43d
PKG_MIRROR_HASH:=64d6b454aefd208881a130ec0d503e690375565ed3de0171a8c70f5d1a4a25bf
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=LGPL-2.1
+3 -1
View File
@@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=iptables
PKG_VERSION:=1.8.10
PKG_RELEASE:=2
PKG_RELEASE:=3
PKG_SOURCE_URL:=https://netfilter.org/projects/iptables/files
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
@@ -144,6 +144,7 @@ $(call Package/iptables/Default)
TITLE:=IP firewall administration tool nft
DEPENDS:=+kmod-ipt-core +xtables-nft
PROVIDES:=iptables
DEFAULT_VARIANT:=1
ALTERNATIVES:=\
300:/usr/sbin/iptables:xtables-nft-multi \
300:/usr/sbin/iptables-restore:xtables-nft-multi \
@@ -489,6 +490,7 @@ $(call Package/iptables/Default)
DEPENDS:=@IPV6 +kmod-ip6tables +xtables-nft
TITLE:=IP firewall administration tool nft
PROVIDES:=ip6tables
DEFAULT_VARIANT:=1
ALTERNATIVES:=\
300:/usr/sbin/ip6tables:xtables-nft-multi \
300:/usr/sbin/ip6tables-restore:xtables-nft-multi \
+3 -3
View File
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/procd.git
PKG_MIRROR_HASH:=123c54964fd8048931002bd74181335dfcbff8ed949af2055e367e03180fe287
PKG_SOURCE_DATE:=2026-02-20
PKG_SOURCE_VERSION:=2881a59f304326cf0a71c849738d052ba317b4cb
PKG_MIRROR_HASH:=8bd86938479609045e1ceebed904e4f5cb96fdb38220d41c3579b7e764fbb05b
PKG_SOURCE_DATE:=2026-03-13
PKG_SOURCE_VERSION:=58eb263d5abe03f8c1280bdfa65a3b052614215d
CMAKE_INSTALL:=1
PKG_LICENSE:=GPL-2.0
+3 -3
View File
@@ -5,9 +5,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/jsonpath.git
PKG_SOURCE_DATE:=2025-10-04
PKG_SOURCE_VERSION:=f4fe702d0e8d9f8704b42f5d5c10950470ada231
PKG_MIRROR_HASH:=799b630107aedb5bfd4b0494af82843f803759324140cce89256b479124d5b1c
PKG_SOURCE_DATE:=2026-03-16
PKG_SOURCE_VERSION:=b9034210bd331749673416c6bf389cccd4e23610
PKG_MIRROR_HASH:=e8616b3eee53c6dd3420a7d800337e13a61e1333dfbd8551b50ab15bafd94a0e
CMAKE_INSTALL:=1
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
@@ -0,0 +1,85 @@
From 63161fb6353493c648a260244f6ac7eca65fd48e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Van=C4=9Bk?= <linuxtardis@gmail.com>
Date: Mon, 2 Mar 2026 20:31:37 +0100
Subject: [PATCH] net: phy: Work around MDIO collisions in the YT8821 driver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The Cudy M3000 router suffers from a MDIO bus collision:
- The MT7981B internal gigabit PHY listens on address 0.
- The Motorcomm YT8821 is strapped to listen on address 1,
but it initially also listens on address 0 (Motorcomm
incorrectly considers that address a broadcast address).
Without this patch, the YT8821 reacts to MDIO commands intended
for the internal gigabit PHY and that makes it work unreliably.
The YT8821 state somehow gets corrupted by the commands for the MT7981
(e.g. we get 100Mbps speeds on gigabit links).
This dirty workaround resets the PHY to cancel out any earlier
YT8821 register corruption and then it disables the address 0
as soon as possible. This should make the YT8821 work reliably.
BEWARE though: the PHY will be reset only if the device tree
node that defines the PHY carries the reset-gpios attribute.
The PHY will not be reset if the reset GPIO is either on the MDIO
bus node or is not defined at all. This might not always be a problem --
some routers do not require the PHY to be reset (e.g. Cudy WR3000H,
where there likely is less communication with the MT7981B PHY,
and so the YT8821 PHY works reasonably well there even without this patch).
This patch also does not address the possible MDIO bus collisions
when the MT7981B PHY driver initially configures that PHY and invokes
some read transactions on the bus. I am hoping that the MT7981B MDIO
bus controller gives priority to the internal PHY and so it would
not be affected by these collisions. However, I don't have anything
to base this on apart from it "seeming to be working okay".
This patch is unlikely to be mergeable into the mainline kernel.
Upstream has strongly indicated that they would prefer this problem
to be resolved by the platform bootloader (e.g. U-Boot), see
- https://lore.kernel.org/all/d3bb9c36-5a0e-4339-901d-2dd21bdba395@gmail.com/
- https://lore.kernel.org/all/20260228232241.1274236-1-linuxtardis@gmail.com/
Signed-off-by: Jakub Vaněk <linuxtardis@gmail.com>
---
drivers/net/phy/motorcomm.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -214,6 +214,9 @@
#define YT8521_RC1R_RGMII_2_100_NS 14
#define YT8521_RC1R_RGMII_2_250_NS 15
+#define YTPHY_MDIO_ADDRESS_CONTROL_REG 0xA005
+#define YTPHY_MACR_EN_PHY_ADDR_0 BIT(6)
+
#define YTPHY_MISC_CONFIG_REG 0xA006
#define YTPHY_MCR_FIBER_SPEED_MASK BIT(0)
#define YTPHY_MCR_FIBER_1000BX (0x1 << 0)
@@ -2659,6 +2662,23 @@ static int yt8821_config_init(struct phy
int ret;
u16 set;
+ /* Hard-reset the PHY to clear out any register corruption
+ * from preceding MDIO bus conflicts.
+ */
+ phy_device_reset(phydev, 1);
+
+ /* Deassert the reset GPIO under the MDIO bus lock to make
+ * sure that nothing will communicate on the bus until we
+ * disable the broadcast address in the YT8821.
+ */
+ phy_lock_mdio_bus(phydev);
+ phy_device_reset(phydev, 0);
+ ret = ytphy_modify_ext(phydev,
+ YTPHY_MDIO_ADDRESS_CONTROL_REG,
+ YTPHY_MACR_EN_PHY_ADDR_0,
+ 0);
+ phy_unlock_mdio_bus(phydev);
+
if (phydev->interface == PHY_INTERFACE_MODE_2500BASEX)
mode = YT8821_CHIP_MODE_FORCE_BX2500;
-1
View File
@@ -392,7 +392,6 @@ define Device/devolo_magic-2-wifi-next
IMAGE_SIZE := 26624k
IMAGES := sysupgrade.bin
IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata
DEFAULT := n
endef
TARGET_DEVICES += devolo_magic-2-wifi-next
@@ -314,7 +314,7 @@
};
};
stp: stp@e100bb0 {
stp: gpio@e100bb0 {
#gpio-cells = <2>;
compatible = "lantiq,gpio-stp-xway";
gpio-controller;
@@ -354,7 +354,7 @@
};
};
stp: stp@e100bb0 {
stp: gpio@e100bb0 {
status = "disabled";
compatible = "lantiq,gpio-stp-xway";
reg = <0xe100bb0 0x40>;
@@ -2,6 +2,7 @@ set_preinit_iface() {
case $(board_name) in
bazis,ax3000wm|\
cudy,m3000-v1|\
cudy,m3000-v2-yt8821|\
cudy,tr3000-256mb-v1|\
cudy,tr3000-v1|\
cudy,tr3000-v1-ubootmod|\
@@ -2,106 +2,15 @@
/dts-v1/;
#include "mt7981b.dtsi"
#include "mt7981b-cudy-m3000.dtsi"
/ {
model = "Cudy M3000 v1";
model = "Cudy M3000 v1/v2";
compatible = "cudy,m3000-v1", "mediatek,mt7981";
aliases {
label-mac-device = &gmac0;
led-boot = &led_status;
led-failsafe = &led_status;
led-running = &led_status;
led-upgrade = &led_status;
serial0 = &uart0;
};
chosen {
stdout-path = "serial0:115200n8";
};
gpio-keys {
compatible = "gpio-keys";
reset {
label = "reset";
gpios = <&pio 1 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
wps {
label = "wps";
gpios = <&pio 0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_WPS_BUTTON>;
};
};
leds {
compatible = "gpio-leds";
led_status: internet-white {
function = LED_FUNCTION_WAN_ONLINE;
color = <LED_COLOR_ID_WHITE>;
gpios = <&pio 10 GPIO_ACTIVE_LOW>;
};
internet-red {
function = LED_FUNCTION_WAN_ONLINE;
color = <LED_COLOR_ID_RED>;
gpios = <&pio 4 GPIO_ACTIVE_LOW>;
};
wan {
function = LED_FUNCTION_WAN;
color = <LED_COLOR_ID_GREEN>;
gpios = <&pio 5 GPIO_ACTIVE_LOW>;
};
lan {
function = LED_FUNCTION_LAN;
color = <LED_COLOR_ID_GREEN>;
gpios = <&pio 9 GPIO_ACTIVE_LOW>;
};
};
};
&uart0 {
status = "okay";
};
&watchdog {
status = "okay";
};
&eth {
pinctrl-names = "default";
pinctrl-0 = <&mdio_pins>;
status = "okay";
gmac0: mac@0 {
compatible = "mediatek,eth-mac";
reg = <0>;
phy-mode = "2500base-x";
phy-handle = <&rtl8221b_phy>;
nvmem-cell-names = "mac-address";
nvmem-cells = <&macaddr_bdinfo_de00 0>;
};
gmac1: mac@1 {
compatible = "mediatek,eth-mac";
reg = <1>;
phy-mode = "gmii";
phy-handle = <&int_gbe_phy>;
nvmem-cell-names = "mac-address";
nvmem-cells = <&macaddr_bdinfo_de00 1>;
};
};
&mdio_bus {
rtl8221b_phy: ethernet-phy@1 {
wan_phy: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c45";
reg = <1>;
reset-assert-us = <100000>;
@@ -111,100 +20,3 @@
interrupt-parent = <&pio>;
};
};
&spi0 {
pinctrl-names = "default";
pinctrl-0 = <&spi0_flash_pins>;
status = "okay";
spi_nand: spi_nand@0 {
compatible = "spi-nand";
reg = <0>;
spi-max-frequency = <52000000>;
spi-tx-bus-width = <4>;
spi-rx-bus-width = <4>;
mediatek,nmbm;
mediatek,bmt-max-ratio = <1>;
mediatek,bmt-max-reserved-blocks = <64>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "BL2";
reg = <0x0000000 0x0100000>;
read-only;
};
partition@100000 {
label = "u-boot-env";
reg = <0x0100000 0x0080000>;
};
factory: partition@180000 {
label = "Factory";
reg = <0x0180000 0x0200000>;
read-only;
};
bdinfo: partition@380000 {
label = "bdinfo";
reg = <0x0380000 0x0040000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_bdinfo_de00: macaddr@de00 {
#nvmem-cell-cells = <1>;
compatible = "mac-base";
reg = <0xde00 0x6>;
};
};
};
partition@3c0000 {
label = "FIP";
reg = <0x03c0000 0x0200000>;
read-only;
};
partition@5c0000 {
label = "ubi";
reg = <0x05c0000 0x4000000>;
};
};
};
};
&pio {
spi0_flash_pins: spi0-pins {
mux {
function = "spi";
groups = "spi0", "spi0_wp_hold";
};
conf-pu {
pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
drive-strength = <MTK_DRIVE_8mA>;
bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
};
conf-pd {
pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
drive-strength = <MTK_DRIVE_8mA>;
bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
};
};
};
&wifi {
status = "okay";
mediatek,mtd-eeprom = <&factory 0x0>;
};
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/dts-v1/;
#include "mt7981b-cudy-m3000.dtsi"
/ {
model = "Cudy M3000 v2 with Motorcomm YT8821";
compatible = "cudy,m3000-v2-yt8821", "mediatek,mt7981";
};
&mdio_bus {
wan_phy: ethernet-phy@1 {
compatible = "ethernet-phy-id4f51.ea19";
reg = <1>;
reset-assert-us = <100000>;
reset-deassert-us = <100000>;
reset-gpios = <&pio 39 GPIO_ACTIVE_LOW>;
interrupts = <38 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&pio>;
};
};
@@ -0,0 +1,195 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/dts-v1/;
#include "mt7981b.dtsi"
/ {
aliases {
label-mac-device = &gmac0;
led-boot = &led_status;
led-failsafe = &led_status;
led-running = &led_status;
led-upgrade = &led_status;
serial0 = &uart0;
};
chosen {
stdout-path = "serial0:115200n8";
};
gpio-keys {
compatible = "gpio-keys";
reset {
label = "reset";
gpios = <&pio 1 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
wps {
label = "wps";
gpios = <&pio 0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_WPS_BUTTON>;
};
};
leds {
compatible = "gpio-leds";
led_status: internet-white {
function = LED_FUNCTION_WAN_ONLINE;
color = <LED_COLOR_ID_WHITE>;
gpios = <&pio 10 GPIO_ACTIVE_LOW>;
};
internet-red {
function = LED_FUNCTION_WAN_ONLINE;
color = <LED_COLOR_ID_RED>;
gpios = <&pio 4 GPIO_ACTIVE_LOW>;
};
wan {
function = LED_FUNCTION_WAN;
color = <LED_COLOR_ID_GREEN>;
gpios = <&pio 5 GPIO_ACTIVE_LOW>;
};
lan {
function = LED_FUNCTION_LAN;
color = <LED_COLOR_ID_GREEN>;
gpios = <&pio 9 GPIO_ACTIVE_LOW>;
};
};
};
&uart0 {
status = "okay";
};
&watchdog {
status = "okay";
};
&eth {
pinctrl-names = "default";
pinctrl-0 = <&mdio_pins>;
status = "okay";
gmac0: mac@0 {
compatible = "mediatek,eth-mac";
reg = <0>;
phy-mode = "2500base-x";
phy-handle = <&wan_phy>;
nvmem-cell-names = "mac-address";
nvmem-cells = <&macaddr_bdinfo_de00 0>;
};
gmac1: mac@1 {
compatible = "mediatek,eth-mac";
reg = <1>;
phy-mode = "gmii";
phy-handle = <&int_gbe_phy>;
nvmem-cell-names = "mac-address";
nvmem-cells = <&macaddr_bdinfo_de00 1>;
};
};
&spi0 {
pinctrl-names = "default";
pinctrl-0 = <&spi0_flash_pins>;
status = "okay";
spi_nand: spi_nand@0 {
compatible = "spi-nand";
reg = <0>;
spi-max-frequency = <52000000>;
spi-tx-bus-width = <4>;
spi-rx-bus-width = <4>;
mediatek,nmbm;
mediatek,bmt-max-ratio = <1>;
mediatek,bmt-max-reserved-blocks = <64>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "BL2";
reg = <0x0000000 0x0100000>;
read-only;
};
partition@100000 {
label = "u-boot-env";
reg = <0x0100000 0x0080000>;
};
factory: partition@180000 {
label = "Factory";
reg = <0x0180000 0x0200000>;
read-only;
};
bdinfo: partition@380000 {
label = "bdinfo";
reg = <0x0380000 0x0040000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_bdinfo_de00: macaddr@de00 {
#nvmem-cell-cells = <1>;
compatible = "mac-base";
reg = <0xde00 0x6>;
};
};
};
partition@3c0000 {
label = "FIP";
reg = <0x03c0000 0x0200000>;
read-only;
};
partition@5c0000 {
label = "ubi";
reg = <0x05c0000 0x4000000>;
};
};
};
};
&pio {
spi0_flash_pins: spi0-pins {
mux {
function = "spi";
groups = "spi0", "spi0_wp_hold";
};
conf-pu {
pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
drive-strength = <MTK_DRIVE_8mA>;
bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
};
conf-pd {
pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
drive-strength = <MTK_DRIVE_8mA>;
bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
};
};
};
&wifi {
status = "okay";
mediatek,mtd-eeprom = <&factory 0x0>;
};
@@ -27,7 +27,7 @@
};
memory@40000000 {
reg = <0x0 0x40000000 0x0 0x40000000>;
reg = <0x0 0x40000000 0x0 0x20000000>;
device_type = "memory";
};
@@ -69,6 +69,12 @@
linux,code = <KEY_WPS_BUTTON>;
gpios = <&pio 14 GPIO_ACTIVE_LOW>;
};
wifi {
label = "wlan";
linux,code = <KEY_WLAN>;
gpios = <&pio 34 GPIO_ACTIVE_LOW>;
};
};
gpio-leds {
@@ -121,7 +127,7 @@
gpios = <&pio 68 GPIO_ACTIVE_HIGH>;
color = <LED_COLOR_ID_BLUE>;
function = LED_FUNCTION_USB;
};
};
};
};
@@ -148,7 +154,6 @@
spi_nand: spi_nand@0 {
compatible = "spi-nand";
reg = <0>;
spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>;
@@ -156,7 +161,7 @@
spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4E 0x41 0x4E 0x44>;
spi-cal-datalen = <7>;
spi-cal-enable;
spi-cal-mode = "read-data";
spi-cal-mode = "read-data";
spi-max-frequency = <52000000>;
spi-rx-bus-width = <4>;
@@ -240,7 +245,7 @@
reset-gpios = <&pio 3 GPIO_ACTIVE_LOW>;
reset-assert-us = <100000>;
reset-deassert-us = <100000>;
reset-deassert-us = <221000>;
};
};
@@ -323,8 +328,8 @@
&pio {
button_pins: button-pins {
pins = "GPIO_RESET", "GPIO_WPS";
bias-disable; /* bias-disable */
pins = "GPIO_RESET", "GPIO_WPS", "SPI2_MISO";
bias-disable;
};
mdio0_pins: mdio0-pins {
@@ -361,11 +366,11 @@
};
enable-usb-power {
gpio-hog;
gpios = <32 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "USB power";
};
gpio-hog;
gpios = <32 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "USB power";
};
};
&ssusb1 {
@@ -133,6 +133,7 @@ mediatek_setup_interfaces()
;;
bazis,ax3000wm|\
cudy,m3000-v1|\
cudy,m3000-v2-yt8821|\
cudy,tr3000-256mb-v1|\
cudy,tr3000-v1|\
cudy,tr3000-v1-ubootmod|\
@@ -83,6 +83,7 @@ case "$board" in
cudy,ap3000wall-v1|\
cudy,ap3000-v1|\
cudy,m3000-v1|\
cudy,m3000-v2-yt8821|\
cudy,re3000-v1|\
cudy,tr3000-256mb-v1|\
cudy,tr3000-v1|\
+23 -1
View File
@@ -1165,7 +1165,7 @@ TARGET_DEVICES += cudy_ap3000-v1
define Device/cudy_m3000-v1
DEVICE_VENDOR := Cudy
DEVICE_MODEL := M3000
DEVICE_VARIANT := v1
DEVICE_VARIANT := v1/v2
DEVICE_DTS := mt7981b-cudy-m3000-v1
DEVICE_DTS_DIR := ../dts
SUPPORTED_DEVICES += R37
@@ -1184,6 +1184,28 @@ define Device/cudy_m3000-v1
endef
TARGET_DEVICES += cudy_m3000-v1
define Device/cudy_m3000-v2-yt8821
DEVICE_VENDOR := Cudy
DEVICE_MODEL := M3000
DEVICE_VARIANT := v2 with Motorcomm YT8821
DEVICE_DTS := mt7981b-cudy-m3000-v2-yt8821
DEVICE_DTS_DIR := ../dts
SUPPORTED_DEVICES += R37
DEVICE_DTS_LOADADDR := 0x44000000
BLOCKSIZE := 128k
PAGESIZE := 2048
IMAGE_SIZE := 65536k
KERNEL_IN_UBI := 1
KERNEL := kernel-bin | lzma | \
fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb
KERNEL_INITRAMFS := kernel-bin | lzma | \
fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd | pad-to 64k
IMAGES := sysupgrade.bin
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
DEVICE_PACKAGES := kmod-mt7915e kmod-mt7981-firmware mt7981-wo-firmware kmod-phy-motorcomm
endef
TARGET_DEVICES += cudy_m3000-v2-yt8821
define Device/cudy_re3000-v1
DEVICE_VENDOR := Cudy
DEVICE_MODEL := RE3000
@@ -58,7 +58,7 @@
<&sgpio_out 0 3 GPIO_ACTIVE_HIGH>;
settle-time-us = <100>;
i2c_sfp0: i2c@0 {
i2c_sfp2: i2c@0 {
reg = <0x0>;
};
@@ -66,7 +66,7 @@
reg = <0x1>;
};
i2c_sfp2: i2c@2 {
i2c_sfp0: i2c@2 {
reg = <0x2>;
};
@@ -112,6 +112,7 @@ platform_do_upgrade() {
iptime,ax2004m|\
iptime,t5004|\
jcg,q20|\
keenetic,kn-1910|\
keenetic,kn-3510|\
linksys,e5600|\
linksys,e7350|\
View File
@@ -78,9 +78,21 @@ static int rtlsmp_register(void)
static void __init apply_early_quirks(void)
{
/* Open up write protected registers. Never mess with this elsewhere */
if (soc_info.family == RTL8380_FAMILY_ID)
if (soc_info.family == RTL8380_FAMILY_ID) {
/*
* Open up write protected registers. SDK opens/closes this whenever needed. For
* simplicity always work with an "open" register set.
*/
sw_w32(0x3, RTL838X_INT_RW_CTRL);
/*
* Disable 4 byte address mode of flash controller. If this bit is not cleared
* the watchdog cannot reset the SoC. The SDK changes this short before restart.
* Until this quirk was implemented all RTL838x devices ran with this disabled
* because of a coding error. As no issues were detected keep the behaviour
* until more details are known.
*/
sw_w32_mask(BIT(30), 0, RTL838X_PLL_CML_CTRL);
}
}
void __init device_tree_init(void)
+1 -1
View File
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=expat
PKG_CPE_ID:=cpe:/a:libexpat:libexpat
PKG_CPE_ID:=cpe:/a:libexpat_project:libexpat
PKG_VERSION:=2.7.3
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz