FILE
r8169_leds.c
File preview with syntax highlighting.
linux-6.19.14/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 RTL8125_LED_CTRL_ACT BIT(9) 22#define RTL8125_LED_CTRL_LINK_2500 BIT(5) 23#define RTL8125_LED_CTRL_LINK_1000 BIT(3) 24#define RTL8125_LED_CTRL_LINK_100 BIT(1) 25#define RTL8125_LED_CTRL_LINK_10 BIT(0) 26 27#define RTL8168_NUM_LEDS 3 28#define RTL8125_NUM_LEDS 4 29 30struct r8169_led_classdev { 31 struct led_classdev led; 32 struct net_device *ndev; 33 int index; 34}; 35 36#define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led) 37 38static bool r8169_trigger_mode_is_valid(unsigned long flags) 39{ 40 bool rx, tx; 41 42 if (flags & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) 43 return false; 44 if (flags & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) 45 return false; 46 47 rx = flags & BIT(TRIGGER_NETDEV_RX); 48 tx = flags & BIT(TRIGGER_NETDEV_TX); 49 50 return rx == tx; 51} 52 53static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev, 54 unsigned long flags) 55{ 56 struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 57 struct rtl8169_private *tp = netdev_priv(ldev->ndev); 58 int shift = ldev->index * 4; 59 60 if (!r8169_trigger_mode_is_valid(flags)) { 61 /* Switch LED off to indicate that mode isn't supported */ 62 rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); 63 return -EOPNOTSUPP; 64 } 65 66 return 0; 67} 68 69static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev, 70 unsigned long flags) 71{ 72 struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 73 struct rtl8169_private *tp = netdev_priv(ldev->ndev); 74 int shift = ldev->index * 4; 75 u16 mode = 0; 76 77 if (flags & BIT(TRIGGER_NETDEV_LINK_10)) 78 mode |= RTL8168_LED_CTRL_LINK_10; 79 if (flags & BIT(TRIGGER_NETDEV_LINK_100)) 80 mode |= RTL8168_LED_CTRL_LINK_100; 81 if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) 82 mode |= RTL8168_LED_CTRL_LINK_1000; 83 if (flags & BIT(TRIGGER_NETDEV_TX)) 84 mode |= RTL8168_LED_CTRL_ACT; 85 86 return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift); 87} 88 89static int rtl8168_led_hw_control_get(struct led_classdev *led_cdev, 90 unsigned long *flags) 91{ 92 struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 93 struct rtl8169_private *tp = netdev_priv(ldev->ndev); 94 int shift = ldev->index * 4; 95 int mode; 96 97 mode = rtl8168_get_led_mode(tp); 98 if (mode < 0) 99 return mode; 100 101 if (mode & RTL8168_LED_CTRL_OPTION2) { 102 rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0); 103 netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n"); 104 } 105 106 mode = (mode >> shift) & 0x000f; 107 108 if (mode & RTL8168_LED_CTRL_ACT) 109 *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); 110 111 if (mode & RTL8168_LED_CTRL_LINK_10) 112 *flags |= BIT(TRIGGER_NETDEV_LINK_10); 113 if (mode & RTL8168_LED_CTRL_LINK_100) 114 *flags |= BIT(TRIGGER_NETDEV_LINK_100); 115 if (mode & RTL8168_LED_CTRL_LINK_1000) 116 *flags |= BIT(TRIGGER_NETDEV_LINK_1000); 117 118 return 0; 119} 120 121static struct device * 122 r8169_led_hw_control_get_device(struct led_classdev *led_cdev) 123{ 124 struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 125 126 return &ldev->ndev->dev; 127} 128 129static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev, 130 struct net_device *ndev, int index) 131{ 132 struct rtl8169_private *tp = netdev_priv(ndev); 133 struct led_classdev *led_cdev = &ldev->led; 134 char led_name[LED_MAX_NAME_SIZE]; 135 136 ldev->ndev = ndev; 137 ldev->index = index; 138 139 r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); 140 led_cdev->name = led_name; 141 led_cdev->hw_control_trigger = "netdev"; 142 led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; 143 led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported; 144 led_cdev->hw_control_set = rtl8168_led_hw_control_set; 145 led_cdev->hw_control_get = rtl8168_led_hw_control_get; 146 led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; 147 148 /* ignore errors */ 149 led_classdev_register(&ndev->dev, led_cdev); 150} 151 152struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev) 153{ 154 struct r8169_led_classdev *leds; 155 int i; 156 157 leds = kcalloc(RTL8168_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL); 158 if (!leds) 159 return NULL; 160 161 for (i = 0; i < RTL8168_NUM_LEDS; i++) 162 rtl8168_setup_ldev(leds + i, ndev, i); 163 164 return leds; 165} 166 167static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev, 168 unsigned long flags) 169{ 170 struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 171 struct rtl8169_private *tp = netdev_priv(ldev->ndev); 172 173 if (!r8169_trigger_mode_is_valid(flags)) { 174 /* Switch LED off to indicate that mode isn't supported */ 175 rtl8125_set_led_mode(tp, ldev->index, 0); 176 return -EOPNOTSUPP; 177 } 178 179 return 0; 180} 181 182static int rtl8125_led_hw_control_set(struct led_classdev *led_cdev, 183 unsigned long flags) 184{ 185 struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 186 struct rtl8169_private *tp = netdev_priv(ldev->ndev); 187 u16 mode = 0; 188 189 if (flags & BIT(TRIGGER_NETDEV_LINK_10)) 190 mode |= RTL8125_LED_CTRL_LINK_10; 191 if (flags & BIT(TRIGGER_NETDEV_LINK_100)) 192 mode |= RTL8125_LED_CTRL_LINK_100; 193 if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) 194 mode |= RTL8125_LED_CTRL_LINK_1000; 195 if (flags & BIT(TRIGGER_NETDEV_LINK_2500)) 196 mode |= RTL8125_LED_CTRL_LINK_2500; 197 if (flags & (BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX))) 198 mode |= RTL8125_LED_CTRL_ACT; 199 200 return rtl8125_set_led_mode(tp, ldev->index, mode); 201} 202 203static int rtl8125_led_hw_control_get(struct led_classdev *led_cdev, 204 unsigned long *flags) 205{ 206 struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); 207 struct rtl8169_private *tp = netdev_priv(ldev->ndev); 208 int mode; 209 210 mode = rtl8125_get_led_mode(tp, ldev->index); 211 if (mode < 0) 212 return mode; 213 214 if (mode & RTL8125_LED_CTRL_LINK_10) 215 *flags |= BIT(TRIGGER_NETDEV_LINK_10); 216 if (mode & RTL8125_LED_CTRL_LINK_100) 217 *flags |= BIT(TRIGGER_NETDEV_LINK_100); 218 if (mode & RTL8125_LED_CTRL_LINK_1000) 219 *flags |= BIT(TRIGGER_NETDEV_LINK_1000); 220 if (mode & RTL8125_LED_CTRL_LINK_2500) 221 *flags |= BIT(TRIGGER_NETDEV_LINK_2500); 222 if (mode & RTL8125_LED_CTRL_ACT) 223 *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); 224 225 return 0; 226} 227 228static void rtl8125_setup_led_ldev(struct r8169_led_classdev *ldev, 229 struct net_device *ndev, int index) 230{ 231 struct rtl8169_private *tp = netdev_priv(ndev); 232 struct led_classdev *led_cdev = &ldev->led; 233 char led_name[LED_MAX_NAME_SIZE]; 234 235 ldev->ndev = ndev; 236 ldev->index = index; 237 238 r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); 239 led_cdev->name = led_name; 240 led_cdev->hw_control_trigger = "netdev"; 241 led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; 242 led_cdev->hw_control_is_supported = rtl8125_led_hw_control_is_supported; 243 led_cdev->hw_control_set = rtl8125_led_hw_control_set; 244 led_cdev->hw_control_get = rtl8125_led_hw_control_get; 245 led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; 246 247 /* ignore errors */ 248 led_classdev_register(&ndev->dev, led_cdev); 249} 250 251struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev) 252{ 253 struct r8169_led_classdev *leds; 254 int i; 255 256 leds = kcalloc(RTL8125_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL); 257 if (!leds) 258 return NULL; 259 260 for (i = 0; i < RTL8125_NUM_LEDS; i++) 261 rtl8125_setup_led_ldev(leds + i, ndev, i); 262 263 return leds; 264} 265 266void r8169_remove_leds(struct r8169_led_classdev *leds) 267{ 268 if (!leds) 269 return; 270 271 for (struct r8169_led_classdev *l = leds; l->ndev; l++) 272 led_classdev_unregister(&l->led); 273 274 kfree(leds); 275}
~/
Read-only file preview.