276 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 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 328#define RTL8125_NUM_LEDS 429 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}276