From: Álvaro Fernández Rojas Date: Sun, 23 Jun 2024 17:19:47 +0000 (+0200) Subject: generic: 6.6: backport upstream r8169 patches X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=ea2ff25d4cb437fa3223f4508e7b7bcd26902e37;p=openwrt%2Fstaging%2Fansuel.git generic: 6.6: backport upstream r8169 patches Backport a bunch of upstream r8169 patches: - RTL8168/RTL8101 LEDs support. - RTL8126A support. - RTL8125/RTL8126 LEDs support. - RTL8168M support. Signed-off-by: Álvaro Fernández Rojas --- diff --git a/package/kernel/linux/modules/netdevices.mk b/package/kernel/linux/modules/netdevices.mk index 06bae6a7ed..c1188351dc 100644 --- a/package/kernel/linux/modules/netdevices.mk +++ b/package/kernel/linux/modules/netdevices.mk @@ -779,8 +779,7 @@ define KernelPackage/r8169 DEPENDS:=@PCI_SUPPORT +kmod-mii +r8169-firmware +kmod-phy-realtek +kmod-mdio-devres KCONFIG:= \ CONFIG_R8169 \ - CONFIG_R8169_NAPI=y \ - CONFIG_R8169_VLAN=n + CONFIG_R8169_LEDS=y@ge6.6 FILES:=$(LINUX_DIR)/drivers/net/ethernet/realtek/r8169.ko AUTOLOAD:=$(call AutoProbe,r8169) endef diff --git a/target/linux/bcm27xx/patches-6.6/950-0832-r8169-add-support-for-LED-s-on-RTL8168-RTL8101.patch b/target/linux/bcm27xx/patches-6.6/950-0832-r8169-add-support-for-LED-s-on-RTL8168-RTL8101.patch deleted file mode 100644 index 65c75abe31..0000000000 --- a/target/linux/bcm27xx/patches-6.6/950-0832-r8169-add-support-for-LED-s-on-RTL8168-RTL8101.patch +++ /dev/null @@ -1,321 +0,0 @@ -From acf5e70f3b261a2308bb3a1db985e2f3a423a5e5 Mon Sep 17 00:00:00 2001 -From: Heiner Kallweit -Date: Sat, 16 Dec 2023 20:58:10 +0100 -Subject: [PATCH 0832/1085] r8169: add support for LED's on RTL8168/RTL8101 - -commit 18764b883e157e28126b54e7d4ba9dd487d5bf54 upstream. - -This adds support for the LED's on most chip versions. Excluded are -the old non-PCIe versions and RTL8125. RTL8125 has a different LED -register layout, support for it will follow later. - -LED's can be controlled from userspace using the netdev LED trigger. - -Tested on RTL8168h. - -Note: The driver can't know which LED's are actually physically -wired. Therefore not every LED device may represent a physically -available LED. - -Signed-off-by: Heiner Kallweit -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/realtek/Makefile | 3 + - drivers/net/ethernet/realtek/r8169.h | 7 + - drivers/net/ethernet/realtek/r8169_leds.c | 157 ++++++++++++++++++++++ - drivers/net/ethernet/realtek/r8169_main.c | 65 +++++++++ - 4 files changed, 232 insertions(+) - create mode 100644 drivers/net/ethernet/realtek/r8169_leds.c - ---- a/drivers/net/ethernet/realtek/Makefile -+++ b/drivers/net/ethernet/realtek/Makefile -@@ -7,4 +7,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o - obj-$(CONFIG_8139TOO) += 8139too.o - obj-$(CONFIG_ATP) += atp.o - r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o -+ifdef CONFIG_LEDS_TRIGGER_NETDEV -+r8169-objs += r8169_leds.o -+endif - obj-$(CONFIG_R8169) += r8169.o ---- a/drivers/net/ethernet/realtek/r8169.h -+++ b/drivers/net/ethernet/realtek/r8169.h -@@ -8,6 +8,7 @@ - * See MAINTAINERS file for support contact information. - */ - -+#include - #include - #include - -@@ -77,3 +78,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(stru - u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr); - void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, - enum mac_version ver); -+ -+void r8169_get_led_name(struct rtl8169_private *tp, int idx, -+ char *buf, int buf_len); -+int rtl8168_get_led_mode(struct rtl8169_private *tp); -+int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val); -+void rtl8168_init_leds(struct net_device *ndev); ---- /dev/null -+++ b/drivers/net/ethernet/realtek/r8169_leds.c -@@ -0,0 +1,157 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* r8169_leds.c: Realtek 8169/8168/8101/8125 ethernet driver. -+ * -+ * Copyright (c) 2023 Heiner Kallweit -+ * -+ * See MAINTAINERS file for support contact information. -+ */ -+ -+#include -+#include -+#include -+ -+#include "r8169.h" -+ -+#define RTL8168_LED_CTRL_OPTION2 BIT(15) -+#define RTL8168_LED_CTRL_ACT BIT(3) -+#define RTL8168_LED_CTRL_LINK_1000 BIT(2) -+#define RTL8168_LED_CTRL_LINK_100 BIT(1) -+#define RTL8168_LED_CTRL_LINK_10 BIT(0) -+ -+#define RTL8168_NUM_LEDS 3 -+ -+#define RTL8168_SUPPORTED_MODES \ -+ (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \ -+ BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \ -+ BIT(TRIGGER_NETDEV_TX)) -+ -+struct r8169_led_classdev { -+ struct led_classdev led; -+ struct net_device *ndev; -+ int index; -+}; -+ -+#define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led) -+ -+static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev, -+ unsigned long flags) -+{ -+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); -+ struct rtl8169_private *tp = netdev_priv(ldev->ndev); -+ int shift = ldev->index * 4; -+ bool rx, tx; -+ -+ if (flags & ~RTL8168_SUPPORTED_MODES) -+ goto nosupp; -+ -+ rx = flags & BIT(TRIGGER_NETDEV_RX); -+ tx = flags & BIT(TRIGGER_NETDEV_TX); -+ if (rx != tx) -+ goto nosupp; -+ -+ return 0; -+ -+nosupp: -+ /* Switch LED off to indicate that mode isn't supported */ -+ rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); -+ return -EOPNOTSUPP; -+} -+ -+static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev, -+ unsigned long flags) -+{ -+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); -+ struct rtl8169_private *tp = netdev_priv(ldev->ndev); -+ int shift = ldev->index * 4; -+ u16 mode = 0; -+ -+ if (flags & BIT(TRIGGER_NETDEV_LINK_10)) -+ mode |= RTL8168_LED_CTRL_LINK_10; -+ if (flags & BIT(TRIGGER_NETDEV_LINK_100)) -+ mode |= RTL8168_LED_CTRL_LINK_100; -+ if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) -+ mode |= RTL8168_LED_CTRL_LINK_1000; -+ if (flags & BIT(TRIGGER_NETDEV_TX)) -+ mode |= RTL8168_LED_CTRL_ACT; -+ -+ return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift); -+} -+ -+static int rtl8168_led_hw_control_get(struct led_classdev *led_cdev, -+ unsigned long *flags) -+{ -+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); -+ struct rtl8169_private *tp = netdev_priv(ldev->ndev); -+ int shift = ldev->index * 4; -+ int mode; -+ -+ mode = rtl8168_get_led_mode(tp); -+ if (mode < 0) -+ return mode; -+ -+ if (mode & RTL8168_LED_CTRL_OPTION2) { -+ rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0); -+ netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n"); -+ } -+ -+ mode = (mode >> shift) & 0x000f; -+ -+ if (mode & RTL8168_LED_CTRL_ACT) -+ *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); -+ -+ if (mode & RTL8168_LED_CTRL_LINK_10) -+ *flags |= BIT(TRIGGER_NETDEV_LINK_10); -+ if (mode & RTL8168_LED_CTRL_LINK_100) -+ *flags |= BIT(TRIGGER_NETDEV_LINK_100); -+ if (mode & RTL8168_LED_CTRL_LINK_1000) -+ *flags |= BIT(TRIGGER_NETDEV_LINK_1000); -+ -+ return 0; -+} -+ -+static struct device * -+ r8169_led_hw_control_get_device(struct led_classdev *led_cdev) -+{ -+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); -+ -+ return &ldev->ndev->dev; -+} -+ -+static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev, -+ struct net_device *ndev, int index) -+{ -+ struct rtl8169_private *tp = netdev_priv(ndev); -+ struct led_classdev *led_cdev = &ldev->led; -+ char led_name[LED_MAX_NAME_SIZE]; -+ -+ ldev->ndev = ndev; -+ ldev->index = index; -+ -+ r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); -+ led_cdev->name = led_name; -+ led_cdev->default_trigger = "netdev"; -+ led_cdev->hw_control_trigger = "netdev"; -+ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; -+ led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported; -+ led_cdev->hw_control_set = rtl8168_led_hw_control_set; -+ led_cdev->hw_control_get = rtl8168_led_hw_control_get; -+ led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; -+ -+ /* ignore errors */ -+ devm_led_classdev_register(&ndev->dev, led_cdev); -+} -+ -+void rtl8168_init_leds(struct net_device *ndev) -+{ -+ /* bind resource mgmt to netdev */ -+ struct device *dev = &ndev->dev; -+ struct r8169_led_classdev *leds; -+ int i; -+ -+ leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL); -+ if (!leds) -+ return; -+ -+ for (i = 0; i < RTL8168_NUM_LEDS; i++) -+ rtl8168_setup_ldev(leds + i, ndev, i); -+} ---- a/drivers/net/ethernet/realtek/r8169_main.c -+++ b/drivers/net/ethernet/realtek/r8169_main.c -@@ -289,6 +289,7 @@ enum rtl8168_8101_registers { - }; - - enum rtl8168_registers { -+ LED_CTRL = 0x18, - LED_FREQ = 0x1a, - EEE_LED = 0x1b, - ERIDR = 0x70, -@@ -620,6 +621,7 @@ struct rtl8169_private { - - raw_spinlock_t config25_lock; - raw_spinlock_t mac_ocp_lock; -+ struct mutex led_lock; /* serialize LED ctrl RMW access */ - - raw_spinlock_t cfg9346_usage_lock; - int cfg9346_usage_count; -@@ -792,6 +794,62 @@ static const struct rtl_cond name = { - \ - static bool name ## _check(struct rtl8169_private *tp) - -+int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val) -+{ -+ struct device *dev = tp_to_dev(tp); -+ int ret; -+ -+ ret = pm_runtime_resume_and_get(dev); -+ if (ret < 0) -+ return ret; -+ -+ mutex_lock(&tp->led_lock); -+ RTL_W16(tp, LED_CTRL, (RTL_R16(tp, LED_CTRL) & ~mask) | val); -+ mutex_unlock(&tp->led_lock); -+ -+ pm_runtime_put_sync(dev); -+ -+ return 0; -+} -+ -+int rtl8168_get_led_mode(struct rtl8169_private *tp) -+{ -+ struct device *dev = tp_to_dev(tp); -+ int ret; -+ -+ ret = pm_runtime_resume_and_get(dev); -+ if (ret < 0) -+ return ret; -+ -+ ret = RTL_R16(tp, LED_CTRL); -+ -+ pm_runtime_put_sync(dev); -+ -+ return ret; -+} -+ -+void r8169_get_led_name(struct rtl8169_private *tp, int idx, -+ char *buf, int buf_len) -+{ -+ struct pci_dev *pdev = tp->pci_dev; -+ char pdom[8], pfun[8]; -+ int domain; -+ -+ domain = pci_domain_nr(pdev->bus); -+ if (domain) -+ snprintf(pdom, sizeof(pdom), "P%d", domain); -+ else -+ pdom[0] = '\0'; -+ -+ if (pdev->multifunction) -+ snprintf(pfun, sizeof(pfun), "f%d", PCI_FUNC(pdev->devfn)); -+ else -+ pfun[0] = '\0'; -+ -+ snprintf(buf, buf_len, "en%sp%ds%d%s-%d::lan", pdom, pdev->bus->number, -+ PCI_SLOT(pdev->devfn), pfun, idx); -+} -+ - static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type) - { - /* based on RTL8168FP_OOBMAC_BASE in vendor driver */ -@@ -5258,6 +5316,7 @@ static int rtl_init_one(struct pci_dev * - raw_spin_lock_init(&tp->cfg9346_usage_lock); - raw_spin_lock_init(&tp->config25_lock); - raw_spin_lock_init(&tp->mac_ocp_lock); -+ mutex_init(&tp->led_lock); - - dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, - struct pcpu_sw_netstats); -@@ -5414,6 +5473,12 @@ static int rtl_init_one(struct pci_dev * - if (rc) - return rc; - -+#if IS_REACHABLE(CONFIG_LEDS_CLASS) && IS_ENABLED(CONFIG_LEDS_TRIGGER_NETDEV) -+ if (tp->mac_version > RTL_GIGA_MAC_VER_06 && -+ tp->mac_version < RTL_GIGA_MAC_VER_61) -+ rtl8168_init_leds(dev); -+#endif -+ - netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", - rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq); - diff --git a/target/linux/generic/backport-6.6/780-01-v6.8-r8169-add-support-for-LED-s-on-RTL8168-RTL8101.patch b/target/linux/generic/backport-6.6/780-01-v6.8-r8169-add-support-for-LED-s-on-RTL8168-RTL8101.patch new file mode 100644 index 0000000000..3345ebf6c6 --- /dev/null +++ b/target/linux/generic/backport-6.6/780-01-v6.8-r8169-add-support-for-LED-s-on-RTL8168-RTL8101.patch @@ -0,0 +1,319 @@ +From 18764b883e157e28126b54e7d4ba9dd487d5bf54 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 16 Dec 2023 20:58:10 +0100 +Subject: [PATCH] r8169: add support for LED's on RTL8168/RTL8101 + +This adds support for the LED's on most chip versions. Excluded are +the old non-PCIe versions and RTL8125. RTL8125 has a different LED +register layout, support for it will follow later. + +LED's can be controlled from userspace using the netdev LED trigger. + +Tested on RTL8168h. + +Note: The driver can't know which LED's are actually physically +wired. Therefore not every LED device may represent a physically +available LED. + +Signed-off-by: Heiner Kallweit +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/Makefile | 3 + + drivers/net/ethernet/realtek/r8169.h | 7 + + drivers/net/ethernet/realtek/r8169_leds.c | 157 ++++++++++++++++++++++ + drivers/net/ethernet/realtek/r8169_main.c | 65 +++++++++ + 4 files changed, 232 insertions(+) + create mode 100644 drivers/net/ethernet/realtek/r8169_leds.c + +--- a/drivers/net/ethernet/realtek/Makefile ++++ b/drivers/net/ethernet/realtek/Makefile +@@ -7,4 +7,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o + obj-$(CONFIG_8139TOO) += 8139too.o + obj-$(CONFIG_ATP) += atp.o + r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o ++ifdef CONFIG_LEDS_TRIGGER_NETDEV ++r8169-objs += r8169_leds.o ++endif + obj-$(CONFIG_R8169) += r8169.o +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -8,6 +8,7 @@ + * See MAINTAINERS file for support contact information. + */ + ++#include + #include + #include + +@@ -77,3 +78,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(stru + u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr); + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + enum mac_version ver); ++ ++void r8169_get_led_name(struct rtl8169_private *tp, int idx, ++ char *buf, int buf_len); ++int rtl8168_get_led_mode(struct rtl8169_private *tp); ++int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val); ++void rtl8168_init_leds(struct net_device *ndev); +--- /dev/null ++++ b/drivers/net/ethernet/realtek/r8169_leds.c +@@ -0,0 +1,157 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* r8169_leds.c: Realtek 8169/8168/8101/8125 ethernet driver. ++ * ++ * Copyright (c) 2023 Heiner Kallweit ++ * ++ * See MAINTAINERS file for support contact information. ++ */ ++ ++#include ++#include ++#include ++ ++#include "r8169.h" ++ ++#define RTL8168_LED_CTRL_OPTION2 BIT(15) ++#define RTL8168_LED_CTRL_ACT BIT(3) ++#define RTL8168_LED_CTRL_LINK_1000 BIT(2) ++#define RTL8168_LED_CTRL_LINK_100 BIT(1) ++#define RTL8168_LED_CTRL_LINK_10 BIT(0) ++ ++#define RTL8168_NUM_LEDS 3 ++ ++#define RTL8168_SUPPORTED_MODES \ ++ (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \ ++ BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \ ++ BIT(TRIGGER_NETDEV_TX)) ++ ++struct r8169_led_classdev { ++ struct led_classdev led; ++ struct net_device *ndev; ++ int index; ++}; ++ ++#define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led) ++ ++static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev, ++ unsigned long flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ int shift = ldev->index * 4; ++ bool rx, tx; ++ ++ if (flags & ~RTL8168_SUPPORTED_MODES) ++ goto nosupp; ++ ++ rx = flags & BIT(TRIGGER_NETDEV_RX); ++ tx = flags & BIT(TRIGGER_NETDEV_TX); ++ if (rx != tx) ++ goto nosupp; ++ ++ return 0; ++ ++nosupp: ++ /* Switch LED off to indicate that mode isn't supported */ ++ rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); ++ return -EOPNOTSUPP; ++} ++ ++static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev, ++ unsigned long flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ int shift = ldev->index * 4; ++ u16 mode = 0; ++ ++ if (flags & BIT(TRIGGER_NETDEV_LINK_10)) ++ mode |= RTL8168_LED_CTRL_LINK_10; ++ if (flags & BIT(TRIGGER_NETDEV_LINK_100)) ++ mode |= RTL8168_LED_CTRL_LINK_100; ++ if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) ++ mode |= RTL8168_LED_CTRL_LINK_1000; ++ if (flags & BIT(TRIGGER_NETDEV_TX)) ++ mode |= RTL8168_LED_CTRL_ACT; ++ ++ return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift); ++} ++ ++static int rtl8168_led_hw_control_get(struct led_classdev *led_cdev, ++ unsigned long *flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ int shift = ldev->index * 4; ++ int mode; ++ ++ mode = rtl8168_get_led_mode(tp); ++ if (mode < 0) ++ return mode; ++ ++ if (mode & RTL8168_LED_CTRL_OPTION2) { ++ rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0); ++ netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n"); ++ } ++ ++ mode = (mode >> shift) & 0x000f; ++ ++ if (mode & RTL8168_LED_CTRL_ACT) ++ *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); ++ ++ if (mode & RTL8168_LED_CTRL_LINK_10) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_10); ++ if (mode & RTL8168_LED_CTRL_LINK_100) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_100); ++ if (mode & RTL8168_LED_CTRL_LINK_1000) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_1000); ++ ++ return 0; ++} ++ ++static struct device * ++ r8169_led_hw_control_get_device(struct led_classdev *led_cdev) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ ++ return &ldev->ndev->dev; ++} ++ ++static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev, ++ struct net_device *ndev, int index) ++{ ++ struct rtl8169_private *tp = netdev_priv(ndev); ++ struct led_classdev *led_cdev = &ldev->led; ++ char led_name[LED_MAX_NAME_SIZE]; ++ ++ ldev->ndev = ndev; ++ ldev->index = index; ++ ++ r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); ++ led_cdev->name = led_name; ++ led_cdev->default_trigger = "netdev"; ++ led_cdev->hw_control_trigger = "netdev"; ++ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; ++ led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported; ++ led_cdev->hw_control_set = rtl8168_led_hw_control_set; ++ led_cdev->hw_control_get = rtl8168_led_hw_control_get; ++ led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; ++ ++ /* ignore errors */ ++ devm_led_classdev_register(&ndev->dev, led_cdev); ++} ++ ++void rtl8168_init_leds(struct net_device *ndev) ++{ ++ /* bind resource mgmt to netdev */ ++ struct device *dev = &ndev->dev; ++ struct r8169_led_classdev *leds; ++ int i; ++ ++ leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL); ++ if (!leds) ++ return; ++ ++ for (i = 0; i < RTL8168_NUM_LEDS; i++) ++ rtl8168_setup_ldev(leds + i, ndev, i); ++} +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -289,6 +289,7 @@ enum rtl8168_8101_registers { + }; + + enum rtl8168_registers { ++ LED_CTRL = 0x18, + LED_FREQ = 0x1a, + EEE_LED = 0x1b, + ERIDR = 0x70, +@@ -620,6 +621,7 @@ struct rtl8169_private { + + raw_spinlock_t config25_lock; + raw_spinlock_t mac_ocp_lock; ++ struct mutex led_lock; /* serialize LED ctrl RMW access */ + + raw_spinlock_t cfg9346_usage_lock; + int cfg9346_usage_count; +@@ -792,6 +794,62 @@ static const struct rtl_cond name = { + \ + static bool name ## _check(struct rtl8169_private *tp) + ++int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val) ++{ ++ struct device *dev = tp_to_dev(tp); ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return ret; ++ ++ mutex_lock(&tp->led_lock); ++ RTL_W16(tp, LED_CTRL, (RTL_R16(tp, LED_CTRL) & ~mask) | val); ++ mutex_unlock(&tp->led_lock); ++ ++ pm_runtime_put_sync(dev); ++ ++ return 0; ++} ++ ++int rtl8168_get_led_mode(struct rtl8169_private *tp) ++{ ++ struct device *dev = tp_to_dev(tp); ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return ret; ++ ++ ret = RTL_R16(tp, LED_CTRL); ++ ++ pm_runtime_put_sync(dev); ++ ++ return ret; ++} ++ ++void r8169_get_led_name(struct rtl8169_private *tp, int idx, ++ char *buf, int buf_len) ++{ ++ struct pci_dev *pdev = tp->pci_dev; ++ char pdom[8], pfun[8]; ++ int domain; ++ ++ domain = pci_domain_nr(pdev->bus); ++ if (domain) ++ snprintf(pdom, sizeof(pdom), "P%d", domain); ++ else ++ pdom[0] = '\0'; ++ ++ if (pdev->multifunction) ++ snprintf(pfun, sizeof(pfun), "f%d", PCI_FUNC(pdev->devfn)); ++ else ++ pfun[0] = '\0'; ++ ++ snprintf(buf, buf_len, "en%sp%ds%d%s-%d::lan", pdom, pdev->bus->number, ++ PCI_SLOT(pdev->devfn), pfun, idx); ++} ++ + static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type) + { + /* based on RTL8168FP_OOBMAC_BASE in vendor driver */ +@@ -5258,6 +5316,7 @@ static int rtl_init_one(struct pci_dev * + raw_spin_lock_init(&tp->cfg9346_usage_lock); + raw_spin_lock_init(&tp->config25_lock); + raw_spin_lock_init(&tp->mac_ocp_lock); ++ mutex_init(&tp->led_lock); + + dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, + struct pcpu_sw_netstats); +@@ -5414,6 +5473,12 @@ static int rtl_init_one(struct pci_dev * + if (rc) + return rc; + ++#if IS_REACHABLE(CONFIG_LEDS_CLASS) && IS_ENABLED(CONFIG_LEDS_TRIGGER_NETDEV) ++ if (tp->mac_version > RTL_GIGA_MAC_VER_06 && ++ tp->mac_version < RTL_GIGA_MAC_VER_61) ++ rtl8168_init_leds(dev); ++#endif ++ + netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", + rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq); + diff --git a/target/linux/generic/backport-6.6/780-02-v6.8-r8169-fix-building-with-CONFIG_LEDS_CLASS-m.patch b/target/linux/generic/backport-6.6/780-02-v6.8-r8169-fix-building-with-CONFIG_LEDS_CLASS-m.patch new file mode 100644 index 0000000000..cea88c042a --- /dev/null +++ b/target/linux/generic/backport-6.6/780-02-v6.8-r8169-fix-building-with-CONFIG_LEDS_CLASS-m.patch @@ -0,0 +1,75 @@ +From a2634a5ffcafc31c343c6153ae487eb184c433a6 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 3 Jan 2024 16:52:04 +0100 +Subject: [PATCH] r8169: fix building with CONFIG_LEDS_CLASS=m + +When r8169 is built-in but LED support is a loadable module, the new +code to drive the LED causes a link failure: + +ld: drivers/net/ethernet/realtek/r8169_leds.o: in function `rtl8168_init_leds': +r8169_leds.c:(.text+0x36c): undefined reference to `devm_led_classdev_register_ext' + +LED support is an optional feature, so fix this issue by adding a Kconfig +symbol R8169_LEDS that is guaranteed to be false if r8169 is built-in +and LED core support is a module. As a positive side effect of this change +r8169_leds.o no longer is built under this configuration. + +Fixes: 18764b883e15 ("r8169: add support for LED's on RTL8168/RTL8101") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202312281159.9TPeXbNd-lkp@intel.com/ +Suggested-by: Arnd Bergmann +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Tested-by: Simon Horman # build-tested +Tested-by: Arnd Bergmann +Link: https://lore.kernel.org/r/d055aeb5-fe5c-4ccf-987f-5af93a17537b@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/Kconfig | 7 +++++++ + drivers/net/ethernet/realtek/Makefile | 6 ++---- + drivers/net/ethernet/realtek/r8169_main.c | 5 ++--- + 3 files changed, 11 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/realtek/Kconfig ++++ b/drivers/net/ethernet/realtek/Kconfig +@@ -113,4 +113,11 @@ config R8169 + To compile this driver as a module, choose M here: the module + will be called r8169. This is recommended. + ++config R8169_LEDS ++ def_bool R8169 && LEDS_TRIGGER_NETDEV ++ depends on !(R8169=y && LEDS_CLASS=m) ++ help ++ Optional support for controlling the NIC LED's with the netdev ++ LED trigger. ++ + endif # NET_VENDOR_REALTEK +--- a/drivers/net/ethernet/realtek/Makefile ++++ b/drivers/net/ethernet/realtek/Makefile +@@ -6,8 +6,6 @@ + obj-$(CONFIG_8139CP) += 8139cp.o + obj-$(CONFIG_8139TOO) += 8139too.o + obj-$(CONFIG_ATP) += atp.o +-r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o +-ifdef CONFIG_LEDS_TRIGGER_NETDEV +-r8169-objs += r8169_leds.o +-endif ++r8169-y += r8169_main.o r8169_firmware.o r8169_phy_config.o ++r8169-$(CONFIG_R8169_LEDS) += r8169_leds.o + obj-$(CONFIG_R8169) += r8169.o +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5473,11 +5473,10 @@ static int rtl_init_one(struct pci_dev * + if (rc) + return rc; + +-#if IS_REACHABLE(CONFIG_LEDS_CLASS) && IS_ENABLED(CONFIG_LEDS_TRIGGER_NETDEV) +- if (tp->mac_version > RTL_GIGA_MAC_VER_06 && ++ if (IS_ENABLED(CONFIG_R8169_LEDS) && ++ tp->mac_version > RTL_GIGA_MAC_VER_06 && + tp->mac_version < RTL_GIGA_MAC_VER_61) + rtl8168_init_leds(dev); +-#endif + + netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", + rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq); diff --git a/target/linux/generic/backport-6.6/780-03-v6.9-r8169-add-support-for-RTL8126A.patch b/target/linux/generic/backport-6.6/780-03-v6.9-r8169-add-support-for-RTL8126A.patch new file mode 100644 index 0000000000..5ab160855a --- /dev/null +++ b/target/linux/generic/backport-6.6/780-03-v6.9-r8169-add-support-for-RTL8126A.patch @@ -0,0 +1,355 @@ +From 3907f1ffc0ecf466d5c04aadc44c4b9203f3ec9a Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Thu, 1 Feb 2024 22:38:01 +0100 +Subject: [PATCH] r8169: add support for RTL8126A + +This adds support for the RTL8126A found on Asus z790 Maximus Formula. +It was successfully tested w/o the firmware at 1000Mbps. Firmware file +has been provided by Realtek and submitted to linux-firmware. +2.5G and 5G modes are untested. + +Signed-off-by: Heiner Kallweit +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/r8169.h | 1 + + drivers/net/ethernet/realtek/r8169_main.c | 105 ++++++++++++++---- + .../net/ethernet/realtek/r8169_phy_config.c | 7 ++ + 3 files changed, 89 insertions(+), 24 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -68,6 +68,7 @@ enum mac_version { + /* support for RTL_GIGA_MAC_VER_60 has been removed */ + RTL_GIGA_MAC_VER_61, + RTL_GIGA_MAC_VER_63, ++ RTL_GIGA_MAC_VER_65, + RTL_GIGA_MAC_NONE + }; + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -55,6 +55,7 @@ + #define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw" + #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" + #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" ++#define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" + + /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The RTL chips use a 64 element hash table based on the Ethernet CRC. */ +@@ -140,6 +141,7 @@ static const struct { + [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3}, + /* reserve 62 for CFG_METHOD_4 in the vendor driver */ + [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, ++ [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2}, + }; + + static const struct pci_device_id rtl8169_pci_tbl[] = { +@@ -162,6 +164,7 @@ static const struct pci_device_id rtl816 + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024 }, + { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 }, + { PCI_VDEVICE(REALTEK, 0x8125) }, ++ { PCI_VDEVICE(REALTEK, 0x8126) }, + { PCI_VDEVICE(REALTEK, 0x3000) }, + {} + }; +@@ -331,8 +334,12 @@ enum rtl8168_registers { + }; + + enum rtl8125_registers { ++ INT_CFG0_8125 = 0x34, ++#define INT_CFG0_ENABLE_8125 BIT(0) ++#define INT_CFG0_CLKREQEN BIT(3) + IntrMask_8125 = 0x38, + IntrStatus_8125 = 0x3c, ++ INT_CFG1_8125 = 0x7a, + TxPoll_8125 = 0x90, + MAC0_BKP = 0x19e0, + EEE_TXIDLE_TIMER_8125 = 0x6048, +@@ -1144,7 +1151,7 @@ static void rtl_writephy(struct rtl8169_ + case RTL_GIGA_MAC_VER_31: + r8168dp_2_mdio_write(tp, location, val); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: + r8168g_mdio_write(tp, location, val); + break; + default: +@@ -1159,7 +1166,7 @@ static int rtl_readphy(struct rtl8169_pr + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + return r8168dp_2_mdio_read(tp, location); +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: + return r8168g_mdio_read(tp, location); + default: + return r8169_mdio_read(tp, location); +@@ -1368,7 +1375,7 @@ static void rtl_set_d3_pll_down(struct r + case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: + case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: + case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37: +- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_65: + if (enable) + RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN); + else +@@ -1535,7 +1542,7 @@ static void __rtl8169_set_wol(struct rtl + break; + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_37: +- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_65: + if (wolopts) + rtl_mod_config2(tp, 0, PME_SIGNAL); + else +@@ -2122,6 +2129,9 @@ static enum mac_version rtl8169_get_mac_ + u16 val; + enum mac_version ver; + } mac_info[] = { ++ /* 8126A family. */ ++ { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 }, ++ + /* 8125B family. */ + { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 }, + +@@ -2392,6 +2402,7 @@ static void rtl_init_rxcfg(struct rtl816 + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); + break; + case RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_65: + RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | + RX_PAUSE_SLOT_ON); + break; +@@ -2578,7 +2589,7 @@ static void rtl_wait_txrx_fifo_empty(str + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61: + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + break; +- case RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_65: + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); + rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); +@@ -2822,7 +2833,7 @@ static void rtl_enable_exit_l1(struct rt + case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38: + rtl_eri_set_bits(tp, 0xd4, 0x0c00); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: + r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80); + break; + default: +@@ -2836,7 +2847,7 @@ static void rtl_disable_exit_l1(struct r + case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: + rtl_eri_clear_bits(tp, 0xd4, 0x1f00); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: + r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0); + break; + default: +@@ -2846,6 +2857,8 @@ static void rtl_disable_exit_l1(struct r + + static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) + { ++ u8 val8; ++ + if (tp->mac_version < RTL_GIGA_MAC_VER_32) + return; + +@@ -2859,11 +2872,19 @@ static void rtl_hw_aspm_clkreq_enable(st + return; + + rtl_mod_config5(tp, 0, ASPM_en); +- rtl_mod_config2(tp, 0, ClkReqEn); ++ switch (tp->mac_version) { ++ case RTL_GIGA_MAC_VER_65: ++ val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; ++ RTL_W8(tp, INT_CFG0_8125, val8); ++ break; ++ default: ++ rtl_mod_config2(tp, 0, ClkReqEn); ++ break; ++ } + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: + /* reset ephy tx/rx disable timer */ + r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); + /* chip can trigger L1.2 */ +@@ -2875,14 +2896,22 @@ static void rtl_hw_aspm_clkreq_enable(st + } else { + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: + r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); + break; + default: + break; + } + +- rtl_mod_config2(tp, ClkReqEn, 0); ++ switch (tp->mac_version) { ++ case RTL_GIGA_MAC_VER_65: ++ val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; ++ RTL_W8(tp, INT_CFG0_8125, val8); ++ break; ++ default: ++ rtl_mod_config2(tp, ClkReqEn, 0); ++ break; ++ } + rtl_mod_config5(tp, ASPM_en, 0); + } + } +@@ -3678,10 +3707,15 @@ static void rtl_hw_start_8125_common(str + /* disable new tx descriptor format */ + r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_63) ++ if (tp->mac_version == RTL_GIGA_MAC_VER_65) ++ RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); ++ ++ if (tp->mac_version == RTL_GIGA_MAC_VER_65) ++ r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); ++ else if (tp->mac_version == RTL_GIGA_MAC_VER_63) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); + else +- r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); ++ r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0300); + + if (tp->mac_version == RTL_GIGA_MAC_VER_63) + r8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0000); +@@ -3694,6 +3728,10 @@ static void rtl_hw_start_8125_common(str + r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); + r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); + r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); ++ if (tp->mac_version == RTL_GIGA_MAC_VER_65) ++ r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); ++ else ++ r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); + r8168_mac_ocp_modify(tp, 0xe0c0, 0x4f0f, 0x4403); + r8168_mac_ocp_modify(tp, 0xe052, 0x0080, 0x0068); + r8168_mac_ocp_modify(tp, 0xd430, 0x0fff, 0x047f); +@@ -3708,10 +3746,10 @@ static void rtl_hw_start_8125_common(str + + rtl_loop_wait_low(tp, &rtl_mac_ocp_e00e_cond, 1000, 10); + +- if (tp->mac_version == RTL_GIGA_MAC_VER_63) +- rtl8125b_config_eee_mac(tp); +- else ++ if (tp->mac_version == RTL_GIGA_MAC_VER_61) + rtl8125a_config_eee_mac(tp); ++ else ++ rtl8125b_config_eee_mac(tp); + + rtl_disable_rxdvgate(tp); + } +@@ -3755,6 +3793,12 @@ static void rtl_hw_start_8125b(struct rt + rtl_hw_start_8125_common(tp); + } + ++static void rtl_hw_start_8126a(struct rtl8169_private *tp) ++{ ++ rtl_set_def_aspm_entry_latency(tp); ++ rtl_hw_start_8125_common(tp); ++} ++ + static void rtl_hw_config(struct rtl8169_private *tp) + { + static const rtl_generic_fct hw_configs[] = { +@@ -3797,6 +3841,7 @@ static void rtl_hw_config(struct rtl8169 + [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117, + [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, + [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, ++ [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a, + }; + + if (hw_configs[tp->mac_version]) +@@ -3807,9 +3852,23 @@ static void rtl_hw_start_8125(struct rtl + { + int i; + ++ RTL_W8(tp, INT_CFG0_8125, 0x00); ++ + /* disable interrupt coalescing */ +- for (i = 0xa00; i < 0xb00; i += 4) +- RTL_W32(tp, i, 0); ++ switch (tp->mac_version) { ++ case RTL_GIGA_MAC_VER_61: ++ for (i = 0xa00; i < 0xb00; i += 4) ++ RTL_W32(tp, i, 0); ++ break; ++ case RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_65: ++ for (i = 0xa00; i < 0xa80; i += 4) ++ RTL_W32(tp, i, 0); ++ RTL_W16(tp, INT_CFG1_8125, 0x0000); ++ break; ++ default: ++ break; ++ } + + rtl_hw_config(tp); + } +@@ -3887,8 +3946,7 @@ static int rtl8169_change_mtu(struct net + rtl_jumbo_config(tp); + + switch (tp->mac_version) { +- case RTL_GIGA_MAC_VER_61: +- case RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: + rtl8125_set_eee_txidle_timer(tp); + break; + default: +@@ -4037,7 +4095,7 @@ static void rtl8169_cleanup(struct rtl81 + RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); + rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); + break; +- case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_65: + rtl_enable_rxdvgate(tp); + fsleep(2000); + break; +@@ -4188,8 +4246,7 @@ static unsigned int rtl_quirk_packet_pad + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: +- case RTL_GIGA_MAC_VER_61: +- case RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: + padto = max_t(unsigned int, padto, ETH_ZLEN); + break; + default: +@@ -5225,7 +5282,7 @@ static void rtl_hw_initialize(struct rtl + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: + rtl_hw_init_8168g(tp); + break; +- case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: ++ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_65: + rtl_hw_init_8125(tp); + break; + default: +--- a/drivers/net/ethernet/realtek/r8169_phy_config.c ++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c +@@ -1102,6 +1102,12 @@ static void rtl8125b_hw_phy_config(struc + rtl8125b_config_eee_phy(phydev); + } + ++static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, ++ struct phy_device *phydev) ++{ ++ r8169_apply_firmware(tp); ++} ++ + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, + enum mac_version ver) + { +@@ -1152,6 +1158,7 @@ void r8169_hw_phy_config(struct rtl8169_ + [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config, + [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, + [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, ++ [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config, + }; + + if (phy_configs[ver]) diff --git a/target/linux/generic/backport-6.6/780-04-v6.9-r8169-improve-checking-for-valid-LED-modes.patch b/target/linux/generic/backport-6.6/780-04-v6.9-r8169-improve-checking-for-valid-LED-modes.patch new file mode 100644 index 0000000000..ae0c821267 --- /dev/null +++ b/target/linux/generic/backport-6.6/780-04-v6.9-r8169-improve-checking-for-valid-LED-modes.patch @@ -0,0 +1,81 @@ +From 4c49b6824a607af4760fac4f5c0b9954ab902cef Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 7 Feb 2024 08:16:40 +0100 +Subject: [PATCH] r8169: improve checking for valid LED modes + +After 3a2746320403 ("leds: trigger: netdev: Display only supported link +speed attribute") the check for valid link modes can be simplified. +In addition factor it out, so that it can be re-used by the upcoming +LED support for RTL8125. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://lore.kernel.org/r/8876a9f4-7a2d-48c3-8eae-0d834f5c27c5@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_leds.c | 38 ++++++++++++----------- + 1 file changed, 20 insertions(+), 18 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169_leds.c ++++ b/drivers/net/ethernet/realtek/r8169_leds.c +@@ -20,11 +20,6 @@ + + #define RTL8168_NUM_LEDS 3 + +-#define RTL8168_SUPPORTED_MODES \ +- (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \ +- BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \ +- BIT(TRIGGER_NETDEV_TX)) +- + struct r8169_led_classdev { + struct led_classdev led; + struct net_device *ndev; +@@ -33,28 +28,35 @@ struct r8169_led_classdev { + + #define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led) + ++static bool r8169_trigger_mode_is_valid(unsigned long flags) ++{ ++ bool rx, tx; ++ ++ if (flags & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) ++ return false; ++ if (flags & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) ++ return false; ++ ++ rx = flags & BIT(TRIGGER_NETDEV_RX); ++ tx = flags & BIT(TRIGGER_NETDEV_TX); ++ ++ return rx == tx; ++} ++ + static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev, + unsigned long flags) + { + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); + struct rtl8169_private *tp = netdev_priv(ldev->ndev); + int shift = ldev->index * 4; +- bool rx, tx; + +- if (flags & ~RTL8168_SUPPORTED_MODES) +- goto nosupp; +- +- rx = flags & BIT(TRIGGER_NETDEV_RX); +- tx = flags & BIT(TRIGGER_NETDEV_TX); +- if (rx != tx) +- goto nosupp; ++ if (!r8169_trigger_mode_is_valid(flags)) { ++ /* Switch LED off to indicate that mode isn't supported */ ++ rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); ++ return -EOPNOTSUPP; ++ } + + return 0; +- +-nosupp: +- /* Switch LED off to indicate that mode isn't supported */ +- rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); +- return -EOPNOTSUPP; + } + + static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev, diff --git a/target/linux/generic/backport-6.6/780-05-v6.9-r8169-add-LED-support-for-RTL8125-RTL8126.patch b/target/linux/generic/backport-6.6/780-05-v6.9-r8169-add-LED-support-for-RTL8125-RTL8126.patch new file mode 100644 index 0000000000..742ee578b2 --- /dev/null +++ b/target/linux/generic/backport-6.6/780-05-v6.9-r8169-add-LED-support-for-RTL8125-RTL8126.patch @@ -0,0 +1,244 @@ +From be51ed104ba9929c741afb718ef7198dbcecef94 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 12 Feb 2024 19:44:11 +0100 +Subject: [PATCH] r8169: add LED support for RTL8125/RTL8126 + +This adds LED support for RTL8125/RTL8126. + +Note: Due to missing datasheets changing the 5Gbps link mode isn't +supported for RTL8126. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/f982602c-9de3-4ca6-85a3-2c1d118dcb15@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169.h | 3 + + drivers/net/ethernet/realtek/r8169_leds.c | 106 ++++++++++++++++++++++ + drivers/net/ethernet/realtek/r8169_main.c | 61 ++++++++++++- + 3 files changed, 166 insertions(+), 4 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -85,3 +85,6 @@ void r8169_get_led_name(struct rtl8169_p + int rtl8168_get_led_mode(struct rtl8169_private *tp); + int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val); + void rtl8168_init_leds(struct net_device *ndev); ++int rtl8125_get_led_mode(struct rtl8169_private *tp, int index); ++int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode); ++void rtl8125_init_leds(struct net_device *ndev); +--- a/drivers/net/ethernet/realtek/r8169_leds.c ++++ b/drivers/net/ethernet/realtek/r8169_leds.c +@@ -18,7 +18,14 @@ + #define RTL8168_LED_CTRL_LINK_100 BIT(1) + #define RTL8168_LED_CTRL_LINK_10 BIT(0) + ++#define RTL8125_LED_CTRL_ACT BIT(9) ++#define RTL8125_LED_CTRL_LINK_2500 BIT(5) ++#define RTL8125_LED_CTRL_LINK_1000 BIT(3) ++#define RTL8125_LED_CTRL_LINK_100 BIT(1) ++#define RTL8125_LED_CTRL_LINK_10 BIT(0) ++ + #define RTL8168_NUM_LEDS 3 ++#define RTL8125_NUM_LEDS 4 + + struct r8169_led_classdev { + struct led_classdev led; +@@ -157,3 +164,102 @@ void rtl8168_init_leds(struct net_device + for (i = 0; i < RTL8168_NUM_LEDS; i++) + rtl8168_setup_ldev(leds + i, ndev, i); + } ++ ++static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev, ++ unsigned long flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ ++ if (!r8169_trigger_mode_is_valid(flags)) { ++ /* Switch LED off to indicate that mode isn't supported */ ++ rtl8125_set_led_mode(tp, ldev->index, 0); ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int rtl8125_led_hw_control_set(struct led_classdev *led_cdev, ++ unsigned long flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ u16 mode = 0; ++ ++ if (flags & BIT(TRIGGER_NETDEV_LINK_10)) ++ mode |= RTL8125_LED_CTRL_LINK_10; ++ if (flags & BIT(TRIGGER_NETDEV_LINK_100)) ++ mode |= RTL8125_LED_CTRL_LINK_100; ++ if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) ++ mode |= RTL8125_LED_CTRL_LINK_1000; ++ if (flags & BIT(TRIGGER_NETDEV_LINK_2500)) ++ mode |= RTL8125_LED_CTRL_LINK_2500; ++ if (flags & (BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX))) ++ mode |= RTL8125_LED_CTRL_ACT; ++ ++ return rtl8125_set_led_mode(tp, ldev->index, mode); ++} ++ ++static int rtl8125_led_hw_control_get(struct led_classdev *led_cdev, ++ unsigned long *flags) ++{ ++ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); ++ struct rtl8169_private *tp = netdev_priv(ldev->ndev); ++ int mode; ++ ++ mode = rtl8125_get_led_mode(tp, ldev->index); ++ if (mode < 0) ++ return mode; ++ ++ if (mode & RTL8125_LED_CTRL_LINK_10) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_10); ++ if (mode & RTL8125_LED_CTRL_LINK_100) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_100); ++ if (mode & RTL8125_LED_CTRL_LINK_1000) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_1000); ++ if (mode & RTL8125_LED_CTRL_LINK_2500) ++ *flags |= BIT(TRIGGER_NETDEV_LINK_2500); ++ if (mode & RTL8125_LED_CTRL_ACT) ++ *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); ++ ++ return 0; ++} ++ ++static void rtl8125_setup_led_ldev(struct r8169_led_classdev *ldev, ++ struct net_device *ndev, int index) ++{ ++ struct rtl8169_private *tp = netdev_priv(ndev); ++ struct led_classdev *led_cdev = &ldev->led; ++ char led_name[LED_MAX_NAME_SIZE]; ++ ++ ldev->ndev = ndev; ++ ldev->index = index; ++ ++ r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); ++ led_cdev->name = led_name; ++ led_cdev->hw_control_trigger = "netdev"; ++ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; ++ led_cdev->hw_control_is_supported = rtl8125_led_hw_control_is_supported; ++ led_cdev->hw_control_set = rtl8125_led_hw_control_set; ++ led_cdev->hw_control_get = rtl8125_led_hw_control_get; ++ led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; ++ ++ /* ignore errors */ ++ devm_led_classdev_register(&ndev->dev, led_cdev); ++} ++ ++void rtl8125_init_leds(struct net_device *ndev) ++{ ++ /* bind resource mgmt to netdev */ ++ struct device *dev = &ndev->dev; ++ struct r8169_led_classdev *leds; ++ int i; ++ ++ leds = devm_kcalloc(dev, RTL8125_NUM_LEDS, sizeof(*leds), GFP_KERNEL); ++ if (!leds) ++ return; ++ ++ for (i = 0; i < RTL8125_NUM_LEDS; i++) ++ rtl8125_setup_led_ldev(leds + i, ndev, i); ++} +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -334,17 +334,23 @@ enum rtl8168_registers { + }; + + enum rtl8125_registers { ++ LEDSEL0 = 0x18, + INT_CFG0_8125 = 0x34, + #define INT_CFG0_ENABLE_8125 BIT(0) + #define INT_CFG0_CLKREQEN BIT(3) + IntrMask_8125 = 0x38, + IntrStatus_8125 = 0x3c, + INT_CFG1_8125 = 0x7a, ++ LEDSEL2 = 0x84, ++ LEDSEL1 = 0x86, + TxPoll_8125 = 0x90, ++ LEDSEL3 = 0x96, + MAC0_BKP = 0x19e0, + EEE_TXIDLE_TIMER_8125 = 0x6048, + }; + ++#define LEDSEL_MASK_8125 0x23f ++ + #define RX_VLAN_INNER_8125 BIT(22) + #define RX_VLAN_OUTER_8125 BIT(23) + #define RX_VLAN_8125 (RX_VLAN_INNER_8125 | RX_VLAN_OUTER_8125) +@@ -835,6 +841,51 @@ int rtl8168_get_led_mode(struct rtl8169_ + return ret; + } + ++static int rtl8125_get_led_reg(int index) ++{ ++ static const int led_regs[] = { LEDSEL0, LEDSEL1, LEDSEL2, LEDSEL3 }; ++ ++ return led_regs[index]; ++} ++ ++int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode) ++{ ++ int reg = rtl8125_get_led_reg(index); ++ struct device *dev = tp_to_dev(tp); ++ int ret; ++ u16 val; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return ret; ++ ++ mutex_lock(&tp->led_lock); ++ val = RTL_R16(tp, reg) & ~LEDSEL_MASK_8125; ++ RTL_W16(tp, reg, val | mode); ++ mutex_unlock(&tp->led_lock); ++ ++ pm_runtime_put_sync(dev); ++ ++ return 0; ++} ++ ++int rtl8125_get_led_mode(struct rtl8169_private *tp, int index) ++{ ++ int reg = rtl8125_get_led_reg(index); ++ struct device *dev = tp_to_dev(tp); ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(dev); ++ if (ret < 0) ++ return ret; ++ ++ ret = RTL_R16(tp, reg); ++ ++ pm_runtime_put_sync(dev); ++ ++ return ret; ++} ++ + void r8169_get_led_name(struct rtl8169_private *tp, int idx, + char *buf, int buf_len) + { +@@ -5530,10 +5581,12 @@ static int rtl_init_one(struct pci_dev * + if (rc) + return rc; + +- if (IS_ENABLED(CONFIG_R8169_LEDS) && +- tp->mac_version > RTL_GIGA_MAC_VER_06 && +- tp->mac_version < RTL_GIGA_MAC_VER_61) +- rtl8168_init_leds(dev); ++ if (IS_ENABLED(CONFIG_R8169_LEDS)) { ++ if (rtl_is_8125(tp)) ++ rtl8125_init_leds(dev); ++ else if (tp->mac_version > RTL_GIGA_MAC_VER_06) ++ rtl8168_init_leds(dev); ++ } + + netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", + rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq); diff --git a/target/linux/generic/backport-6.6/780-06-v6.9-r8169-add-MODULE_FIRMWARE-entry-for-RTL8126A.patch b/target/linux/generic/backport-6.6/780-06-v6.9-r8169-add-MODULE_FIRMWARE-entry-for-RTL8126A.patch new file mode 100644 index 0000000000..a6175c824e --- /dev/null +++ b/target/linux/generic/backport-6.6/780-06-v6.9-r8169-add-MODULE_FIRMWARE-entry-for-RTL8126A.patch @@ -0,0 +1,25 @@ +From f4d3e595c0000ce39dec7e4799ea42ce42ab6867 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sat, 17 Feb 2024 15:48:23 +0100 +Subject: [PATCH] r8169: add MODULE_FIRMWARE entry for RTL8126A + +Add the missing MODULE_FIRMWARE entry for RTL8126A. + +Signed-off-by: Heiner Kallweit +Reviewed-by: Simon Horman +Link: https://lore.kernel.org/r/47ef79d2-59c4-4d44-9595-366c70c4ad87@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -680,6 +680,7 @@ MODULE_FIRMWARE(FIRMWARE_8168FP_3); + MODULE_FIRMWARE(FIRMWARE_8107E_2); + MODULE_FIRMWARE(FIRMWARE_8125A_3); + MODULE_FIRMWARE(FIRMWARE_8125B_2); ++MODULE_FIRMWARE(FIRMWARE_8126A_2); + + static inline struct device *tp_to_dev(struct rtl8169_private *tp) + { diff --git a/target/linux/generic/backport-6.6/780-07-v6.10-r8169-add-support-for-RTL8168M.patch b/target/linux/generic/backport-6.6/780-07-v6.10-r8169-add-support-for-RTL8168M.patch new file mode 100644 index 0000000000..557b8b1491 --- /dev/null +++ b/target/linux/generic/backport-6.6/780-07-v6.10-r8169-add-support-for-RTL8168M.patch @@ -0,0 +1,30 @@ +From 39f59c72ad3a1eaab9a60f0671bc94d2bc826d21 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Sun, 7 Apr 2024 23:19:25 +0200 +Subject: [PATCH] r8169: add support for RTL8168M +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A user reported an unknown chip version. According to the r8168 vendor +driver it's called RTL8168M, but handling is identical to RTL8168H. +So let's simply treat it as RTL8168H. + +Tested-by: Евгений +Signed-off-by: Heiner Kallweit +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/r8169_main.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -2212,6 +2212,8 @@ static enum mac_version rtl8169_get_mac_ + * the wild. Let's disable detection. + * { 0x7cf, 0x540, RTL_GIGA_MAC_VER_45 }, + */ ++ /* Realtek calls it RTL8168M, but it's handled like RTL8168H */ ++ { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46 }, + + /* 8168G family. */ + { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44 }, diff --git a/target/linux/generic/backport-6.6/780-08-v6.10-r8169-fix-LED-related-deadlock-on-module-removal.patch b/target/linux/generic/backport-6.6/780-08-v6.10-r8169-fix-LED-related-deadlock-on-module-removal.patch new file mode 100644 index 0000000000..52019869a8 --- /dev/null +++ b/target/linux/generic/backport-6.6/780-08-v6.10-r8169-fix-LED-related-deadlock-on-module-removal.patch @@ -0,0 +1,147 @@ +From 19fa4f2a85d777a8052e869c1b892a2f7556569d Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Mon, 8 Apr 2024 20:47:40 +0200 +Subject: [PATCH] r8169: fix LED-related deadlock on module removal + +Binding devm_led_classdev_register() to the netdev is problematic +because on module removal we get a RTNL-related deadlock. Fix this +by avoiding the device-managed LED functions. + +Note: We can safely call led_classdev_unregister() for a LED even +if registering it failed, because led_classdev_unregister() detects +this and is a no-op in this case. + +Fixes: 18764b883e15 ("r8169: add support for LED's on RTL8168/RTL8101") +Cc: stable@vger.kernel.org +Reported-by: Lukas Wunner +Signed-off-by: Heiner Kallweit +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/r8169.h | 6 ++-- + drivers/net/ethernet/realtek/r8169_leds.c | 35 +++++++++++++++-------- + drivers/net/ethernet/realtek/r8169_main.c | 8 ++++-- + 3 files changed, 33 insertions(+), 16 deletions(-) + +--- a/drivers/net/ethernet/realtek/r8169.h ++++ b/drivers/net/ethernet/realtek/r8169.h +@@ -73,6 +73,7 @@ enum mac_version { + }; + + struct rtl8169_private; ++struct r8169_led_classdev; + + void r8169_apply_firmware(struct rtl8169_private *tp); + u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp); +@@ -84,7 +85,8 @@ void r8169_get_led_name(struct rtl8169_p + char *buf, int buf_len); + int rtl8168_get_led_mode(struct rtl8169_private *tp); + int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val); +-void rtl8168_init_leds(struct net_device *ndev); ++struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev); + int rtl8125_get_led_mode(struct rtl8169_private *tp, int index); + int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode); +-void rtl8125_init_leds(struct net_device *ndev); ++struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev); ++void r8169_remove_leds(struct r8169_led_classdev *leds); +--- a/drivers/net/ethernet/realtek/r8169_leds.c ++++ b/drivers/net/ethernet/realtek/r8169_leds.c +@@ -147,22 +147,22 @@ static void rtl8168_setup_ldev(struct r8 + led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; + + /* ignore errors */ +- devm_led_classdev_register(&ndev->dev, led_cdev); ++ led_classdev_register(&ndev->dev, led_cdev); + } + +-void rtl8168_init_leds(struct net_device *ndev) ++struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev) + { +- /* bind resource mgmt to netdev */ +- struct device *dev = &ndev->dev; + struct r8169_led_classdev *leds; + int i; + +- leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL); ++ leds = kcalloc(RTL8168_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL); + if (!leds) +- return; ++ return NULL; + + for (i = 0; i < RTL8168_NUM_LEDS; i++) + rtl8168_setup_ldev(leds + i, ndev, i); ++ ++ return leds; + } + + static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev, +@@ -246,20 +246,31 @@ static void rtl8125_setup_led_ldev(struc + led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; + + /* ignore errors */ +- devm_led_classdev_register(&ndev->dev, led_cdev); ++ led_classdev_register(&ndev->dev, led_cdev); + } + +-void rtl8125_init_leds(struct net_device *ndev) ++struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev) + { +- /* bind resource mgmt to netdev */ +- struct device *dev = &ndev->dev; + struct r8169_led_classdev *leds; + int i; + +- leds = devm_kcalloc(dev, RTL8125_NUM_LEDS, sizeof(*leds), GFP_KERNEL); ++ leds = kcalloc(RTL8125_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL); + if (!leds) +- return; ++ return NULL; + + for (i = 0; i < RTL8125_NUM_LEDS; i++) + rtl8125_setup_led_ldev(leds + i, ndev, i); ++ ++ return leds; ++} ++ ++void r8169_remove_leds(struct r8169_led_classdev *leds) ++{ ++ if (!leds) ++ return; ++ ++ for (struct r8169_led_classdev *l = leds; l->ndev; l++) ++ led_classdev_unregister(&l->led); ++ ++ kfree(leds); + } +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -651,6 +651,8 @@ struct rtl8169_private { + const char *fw_name; + struct rtl_fw *rtl_fw; + ++ struct r8169_led_classdev *leds; ++ + u32 ocp_base; + }; + +@@ -5126,6 +5128,8 @@ static void rtl_remove_one(struct pci_de + + cancel_work_sync(&tp->wk.work); + ++ r8169_remove_leds(tp->leds); ++ + unregister_netdev(tp->dev); + + if (tp->dash_type != RTL_DASH_NONE) +@@ -5586,9 +5590,9 @@ static int rtl_init_one(struct pci_dev * + + if (IS_ENABLED(CONFIG_R8169_LEDS)) { + if (rtl_is_8125(tp)) +- rtl8125_init_leds(dev); ++ tp->leds = rtl8125_init_leds(dev); + else if (tp->mac_version > RTL_GIGA_MAC_VER_06) +- rtl8168_init_leds(dev); ++ tp->leds = rtl8168_init_leds(dev); + } + + netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", diff --git a/target/linux/generic/backport-6.6/780-09-v6.10-r8169-add-missing-conditional-compiling-for-call-to-.patch b/target/linux/generic/backport-6.6/780-09-v6.10-r8169-add-missing-conditional-compiling-for-call-to-.patch new file mode 100644 index 0000000000..cfe552046e --- /dev/null +++ b/target/linux/generic/backport-6.6/780-09-v6.10-r8169-add-missing-conditional-compiling-for-call-to-.patch @@ -0,0 +1,31 @@ +From 97e176fcbbf3c0f2bd410c9b241177c051f57176 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Wed, 10 Apr 2024 15:11:28 +0200 +Subject: [PATCH] r8169: add missing conditional compiling for call to + r8169_remove_leds + +Add missing dependency on CONFIG_R8169_LEDS. As-is a link error occurs +if config option CONFIG_R8169_LEDS isn't enabled. + +Fixes: 19fa4f2a85d7 ("r8169: fix LED-related deadlock on module removal") +Reported-by: Venkat Rao Bagalkote +Signed-off-by: Heiner Kallweit +Tested-By: Venkat Rao Bagalkote +Link: https://lore.kernel.org/r/d080038c-eb6b-45ac-9237-b8c1cdd7870f@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/realtek/r8169_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -5128,7 +5128,8 @@ static void rtl_remove_one(struct pci_de + + cancel_work_sync(&tp->wk.work); + +- r8169_remove_leds(tp->leds); ++ if (IS_ENABLED(CONFIG_R8169_LEDS)) ++ r8169_remove_leds(tp->leds); + + unregister_netdev(tp->dev); + diff --git a/target/linux/generic/config-6.6 b/target/linux/generic/config-6.6 index c51cc3b0ce..20fe98099f 100644 --- a/target/linux/generic/config-6.6 +++ b/target/linux/generic/config-6.6 @@ -4813,6 +4813,7 @@ CONFIG_PWRSEQ_SIMPLE=y # CONFIG_QUOTA_NETLINK_INTERFACE is not set # CONFIG_R6040 is not set # CONFIG_R8169 is not set +# CONFIG_R8169_LEDS is not set # CONFIG_R8712U is not set # CONFIG_RADIO_ADAPTERS is not set # CONFIG_RADIO_AZTECH is not set