Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <hkallweit1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Heiner Kallweit and committed by
David S. Miller
18764b88 d7a39d39

+232
+3
drivers/net/ethernet/realtek/Makefile
··· 7 7 obj-$(CONFIG_8139TOO) += 8139too.o 8 8 obj-$(CONFIG_ATP) += atp.o 9 9 r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o 10 + ifdef CONFIG_LEDS_TRIGGER_NETDEV 11 + r8169-objs += r8169_leds.o 12 + endif 10 13 obj-$(CONFIG_R8169) += r8169.o
+7
drivers/net/ethernet/realtek/r8169.h
··· 8 8 * See MAINTAINERS file for support contact information. 9 9 */ 10 10 11 + #include <linux/netdevice.h> 11 12 #include <linux/types.h> 12 13 #include <linux/phy.h> 13 14 ··· 78 77 u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr); 79 78 void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, 80 79 enum mac_version ver); 80 + 81 + void r8169_get_led_name(struct rtl8169_private *tp, int idx, 82 + char *buf, int buf_len); 83 + int rtl8168_get_led_mode(struct rtl8169_private *tp); 84 + int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val); 85 + void rtl8168_init_leds(struct net_device *ndev);
+157
drivers/net/ethernet/realtek/r8169_leds.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* r8169_leds.c: Realtek 8169/8168/8101/8125 ethernet driver. 3 + * 4 + * Copyright (c) 2023 Heiner Kallweit <hkallweit1@gmail.com> 5 + * 6 + * See MAINTAINERS file for support contact information. 7 + */ 8 + 9 + #include <linux/leds.h> 10 + #include <linux/netdevice.h> 11 + #include <uapi/linux/uleds.h> 12 + 13 + #include "r8169.h" 14 + 15 + #define RTL8168_LED_CTRL_OPTION2 BIT(15) 16 + #define RTL8168_LED_CTRL_ACT BIT(3) 17 + #define RTL8168_LED_CTRL_LINK_1000 BIT(2) 18 + #define RTL8168_LED_CTRL_LINK_100 BIT(1) 19 + #define RTL8168_LED_CTRL_LINK_10 BIT(0) 20 + 21 + #define RTL8168_NUM_LEDS 3 22 + 23 + #define RTL8168_SUPPORTED_MODES \ 24 + (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \ 25 + BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \ 26 + BIT(TRIGGER_NETDEV_TX)) 27 + 28 + struct r8169_led_classdev { 29 + struct led_classdev led; 30 + struct net_device *ndev; 31 + int index; 32 + }; 33 + 34 + #define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led) 35 + 36 + static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev, 37 + unsigned long flags) 38 + { 39 + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 40 + struct rtl8169_private *tp = netdev_priv(ldev->ndev); 41 + int shift = ldev->index * 4; 42 + bool rx, tx; 43 + 44 + if (flags & ~RTL8168_SUPPORTED_MODES) 45 + goto nosupp; 46 + 47 + rx = flags & BIT(TRIGGER_NETDEV_RX); 48 + tx = flags & BIT(TRIGGER_NETDEV_TX); 49 + if (rx != tx) 50 + goto nosupp; 51 + 52 + return 0; 53 + 54 + nosupp: 55 + /* Switch LED off to indicate that mode isn't supported */ 56 + rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); 57 + return -EOPNOTSUPP; 58 + } 59 + 60 + static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev, 61 + unsigned long flags) 62 + { 63 + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 64 + struct rtl8169_private *tp = netdev_priv(ldev->ndev); 65 + int shift = ldev->index * 4; 66 + u16 mode = 0; 67 + 68 + if (flags & BIT(TRIGGER_NETDEV_LINK_10)) 69 + mode |= RTL8168_LED_CTRL_LINK_10; 70 + if (flags & BIT(TRIGGER_NETDEV_LINK_100)) 71 + mode |= RTL8168_LED_CTRL_LINK_100; 72 + if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) 73 + mode |= RTL8168_LED_CTRL_LINK_1000; 74 + if (flags & BIT(TRIGGER_NETDEV_TX)) 75 + mode |= RTL8168_LED_CTRL_ACT; 76 + 77 + return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift); 78 + } 79 + 80 + static int rtl8168_led_hw_control_get(struct led_classdev *led_cdev, 81 + unsigned long *flags) 82 + { 83 + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 84 + struct rtl8169_private *tp = netdev_priv(ldev->ndev); 85 + int shift = ldev->index * 4; 86 + int mode; 87 + 88 + mode = rtl8168_get_led_mode(tp); 89 + if (mode < 0) 90 + return mode; 91 + 92 + if (mode & RTL8168_LED_CTRL_OPTION2) { 93 + rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0); 94 + netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n"); 95 + } 96 + 97 + mode = (mode >> shift) & 0x000f; 98 + 99 + if (mode & RTL8168_LED_CTRL_ACT) 100 + *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); 101 + 102 + if (mode & RTL8168_LED_CTRL_LINK_10) 103 + *flags |= BIT(TRIGGER_NETDEV_LINK_10); 104 + if (mode & RTL8168_LED_CTRL_LINK_100) 105 + *flags |= BIT(TRIGGER_NETDEV_LINK_100); 106 + if (mode & RTL8168_LED_CTRL_LINK_1000) 107 + *flags |= BIT(TRIGGER_NETDEV_LINK_1000); 108 + 109 + return 0; 110 + } 111 + 112 + static struct device * 113 + r8169_led_hw_control_get_device(struct led_classdev *led_cdev) 114 + { 115 + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 116 + 117 + return &ldev->ndev->dev; 118 + } 119 + 120 + static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev, 121 + struct net_device *ndev, int index) 122 + { 123 + struct rtl8169_private *tp = netdev_priv(ndev); 124 + struct led_classdev *led_cdev = &ldev->led; 125 + char led_name[LED_MAX_NAME_SIZE]; 126 + 127 + ldev->ndev = ndev; 128 + ldev->index = index; 129 + 130 + r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); 131 + led_cdev->name = led_name; 132 + led_cdev->default_trigger = "netdev"; 133 + led_cdev->hw_control_trigger = "netdev"; 134 + led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; 135 + led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported; 136 + led_cdev->hw_control_set = rtl8168_led_hw_control_set; 137 + led_cdev->hw_control_get = rtl8168_led_hw_control_get; 138 + led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; 139 + 140 + /* ignore errors */ 141 + devm_led_classdev_register(&ndev->dev, led_cdev); 142 + } 143 + 144 + void rtl8168_init_leds(struct net_device *ndev) 145 + { 146 + /* bind resource mgmt to netdev */ 147 + struct device *dev = &ndev->dev; 148 + struct r8169_led_classdev *leds; 149 + int i; 150 + 151 + leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL); 152 + if (!leds) 153 + return; 154 + 155 + for (i = 0; i < RTL8168_NUM_LEDS; i++) 156 + rtl8168_setup_ldev(leds + i, ndev, i); 157 + }
+65
drivers/net/ethernet/realtek/r8169_main.c
··· 285 285 }; 286 286 287 287 enum rtl8168_registers { 288 + LED_CTRL = 0x18, 288 289 LED_FREQ = 0x1a, 289 290 EEE_LED = 0x1b, 290 291 ERIDR = 0x70, ··· 617 616 618 617 raw_spinlock_t config25_lock; 619 618 raw_spinlock_t mac_ocp_lock; 619 + struct mutex led_lock; /* serialize LED ctrl RMW access */ 620 620 621 621 raw_spinlock_t cfg9346_usage_lock; 622 622 int cfg9346_usage_count; ··· 789 787 }; \ 790 788 \ 791 789 static bool name ## _check(struct rtl8169_private *tp) 790 + 791 + int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val) 792 + { 793 + struct device *dev = tp_to_dev(tp); 794 + int ret; 795 + 796 + ret = pm_runtime_resume_and_get(dev); 797 + if (ret < 0) 798 + return ret; 799 + 800 + mutex_lock(&tp->led_lock); 801 + RTL_W16(tp, LED_CTRL, (RTL_R16(tp, LED_CTRL) & ~mask) | val); 802 + mutex_unlock(&tp->led_lock); 803 + 804 + pm_runtime_put_sync(dev); 805 + 806 + return 0; 807 + } 808 + 809 + int rtl8168_get_led_mode(struct rtl8169_private *tp) 810 + { 811 + struct device *dev = tp_to_dev(tp); 812 + int ret; 813 + 814 + ret = pm_runtime_resume_and_get(dev); 815 + if (ret < 0) 816 + return ret; 817 + 818 + ret = RTL_R16(tp, LED_CTRL); 819 + 820 + pm_runtime_put_sync(dev); 821 + 822 + return ret; 823 + } 824 + 825 + void r8169_get_led_name(struct rtl8169_private *tp, int idx, 826 + char *buf, int buf_len) 827 + { 828 + struct pci_dev *pdev = tp->pci_dev; 829 + char pdom[8], pfun[8]; 830 + int domain; 831 + 832 + domain = pci_domain_nr(pdev->bus); 833 + if (domain) 834 + snprintf(pdom, sizeof(pdom), "P%d", domain); 835 + else 836 + pdom[0] = '\0'; 837 + 838 + if (pdev->multifunction) 839 + snprintf(pfun, sizeof(pfun), "f%d", PCI_FUNC(pdev->devfn)); 840 + else 841 + pfun[0] = '\0'; 842 + 843 + snprintf(buf, buf_len, "en%sp%ds%d%s-%d::lan", pdom, pdev->bus->number, 844 + PCI_SLOT(pdev->devfn), pfun, idx); 845 + } 792 846 793 847 static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type) 794 848 { ··· 5199 5141 raw_spin_lock_init(&tp->cfg9346_usage_lock); 5200 5142 raw_spin_lock_init(&tp->config25_lock); 5201 5143 raw_spin_lock_init(&tp->mac_ocp_lock); 5144 + mutex_init(&tp->led_lock); 5202 5145 5203 5146 dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, 5204 5147 struct pcpu_sw_netstats); ··· 5355 5296 rc = register_netdev(dev); 5356 5297 if (rc) 5357 5298 return rc; 5299 + 5300 + #if IS_REACHABLE(CONFIG_LEDS_CLASS) && IS_ENABLED(CONFIG_LEDS_TRIGGER_NETDEV) 5301 + if (tp->mac_version > RTL_GIGA_MAC_VER_06 && 5302 + tp->mac_version < RTL_GIGA_MAC_VER_61) 5303 + rtl8168_init_leds(dev); 5304 + #endif 5358 5305 5359 5306 netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", 5360 5307 rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq);