1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2024 Linutronix GmbH */ 3 4 #include <linux/bits.h> 5 #include <linux/leds.h> 6 #include <linux/netdevice.h> 7 #include <linux/pm_runtime.h> 8 #include <uapi/linux/uleds.h> 9 10 #include "igc.h" 11 12 #define IGC_NUM_LEDS 3 13 14 #define IGC_LEDCTL_LED0_MODE_SHIFT 0 15 #define IGC_LEDCTL_LED0_MODE_MASK GENMASK(3, 0) 16 #define IGC_LEDCTL_LED0_BLINK BIT(7) 17 #define IGC_LEDCTL_LED1_MODE_SHIFT 8 18 #define IGC_LEDCTL_LED1_MODE_MASK GENMASK(11, 8) 19 #define IGC_LEDCTL_LED1_BLINK BIT(15) 20 #define IGC_LEDCTL_LED2_MODE_SHIFT 16 21 #define IGC_LEDCTL_LED2_MODE_MASK GENMASK(19, 16) 22 #define IGC_LEDCTL_LED2_BLINK BIT(23) 23 24 #define IGC_LEDCTL_MODE_ON 0x00 25 #define IGC_LEDCTL_MODE_OFF 0x01 26 #define IGC_LEDCTL_MODE_LINK_10 0x05 27 #define IGC_LEDCTL_MODE_LINK_100 0x06 28 #define IGC_LEDCTL_MODE_LINK_1000 0x07 29 #define IGC_LEDCTL_MODE_LINK_2500 0x08 30 #define IGC_LEDCTL_MODE_ACTIVITY 0x0b 31 32 #define IGC_SUPPORTED_MODES \ 33 (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK_1000) | \ 34 BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_10) | \ 35 BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) 36 37 #define IGC_ACTIVITY_MODES \ 38 (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) 39 40 struct igc_led_classdev { 41 struct net_device *netdev; 42 struct led_classdev led; 43 int index; 44 }; 45 46 #define lcdev_to_igc_ldev(lcdev) \ 47 container_of(lcdev, struct igc_led_classdev, led) 48 49 static void igc_led_select(struct igc_adapter *adapter, int led, 50 u32 *mask, u32 *shift, u32 *blink) 51 { 52 switch (led) { 53 case 0: 54 *mask = IGC_LEDCTL_LED0_MODE_MASK; 55 *shift = IGC_LEDCTL_LED0_MODE_SHIFT; 56 *blink = IGC_LEDCTL_LED0_BLINK; 57 break; 58 case 1: 59 *mask = IGC_LEDCTL_LED1_MODE_MASK; 60 *shift = IGC_LEDCTL_LED1_MODE_SHIFT; 61 *blink = IGC_LEDCTL_LED1_BLINK; 62 break; 63 case 2: 64 *mask = IGC_LEDCTL_LED2_MODE_MASK; 65 *shift = IGC_LEDCTL_LED2_MODE_SHIFT; 66 *blink = IGC_LEDCTL_LED2_BLINK; 67 break; 68 default: 69 *mask = *shift = *blink = 0; 70 netdev_err(adapter->netdev, "Unknown LED %d selected!\n", led); 71 } 72 } 73 74 static void igc_led_set(struct igc_adapter *adapter, int led, u32 mode, 75 bool blink) 76 { 77 u32 shift, mask, blink_bit, ledctl; 78 struct igc_hw *hw = &adapter->hw; 79 80 igc_led_select(adapter, led, &mask, &shift, &blink_bit); 81 82 pm_runtime_get_sync(&adapter->pdev->dev); 83 mutex_lock(&adapter->led_mutex); 84 85 /* Set mode */ 86 ledctl = rd32(IGC_LEDCTL); 87 ledctl &= ~mask; 88 ledctl |= mode << shift; 89 90 /* Configure blinking */ 91 if (blink) 92 ledctl |= blink_bit; 93 else 94 ledctl &= ~blink_bit; 95 wr32(IGC_LEDCTL, ledctl); 96 97 mutex_unlock(&adapter->led_mutex); 98 pm_runtime_put(&adapter->pdev->dev); 99 } 100 101 static u32 igc_led_get(struct igc_adapter *adapter, int led) 102 { 103 u32 shift, mask, blink_bit, ledctl; 104 struct igc_hw *hw = &adapter->hw; 105 106 igc_led_select(adapter, led, &mask, &shift, &blink_bit); 107 108 pm_runtime_get_sync(&adapter->pdev->dev); 109 mutex_lock(&adapter->led_mutex); 110 ledctl = rd32(IGC_LEDCTL); 111 mutex_unlock(&adapter->led_mutex); 112 pm_runtime_put(&adapter->pdev->dev); 113 114 return (ledctl & mask) >> shift; 115 } 116 117 static int igc_led_brightness_set_blocking(struct led_classdev *led_cdev, 118 enum led_brightness brightness) 119 { 120 struct igc_led_classdev *ldev = lcdev_to_igc_ldev(led_cdev); 121 struct igc_adapter *adapter = netdev_priv(ldev->netdev); 122 u32 mode; 123 124 if (brightness) 125 mode = IGC_LEDCTL_MODE_ON; 126 else 127 mode = IGC_LEDCTL_MODE_OFF; 128 129 netdev_dbg(adapter->netdev, "Set brightness for LED %d to mode %u!\n", 130 ldev->index, mode); 131 132 igc_led_set(adapter, ldev->index, mode, false); 133 134 return 0; 135 } 136 137 static int igc_led_hw_control_is_supported(struct led_classdev *led_cdev, 138 unsigned long flags) 139 { 140 if (flags & ~IGC_SUPPORTED_MODES) 141 return -EOPNOTSUPP; 142 143 /* If Tx and Rx selected, activity can be offloaded unless some other 144 * mode is selected as well. 145 */ 146 if ((flags & BIT(TRIGGER_NETDEV_TX)) && 147 (flags & BIT(TRIGGER_NETDEV_RX)) && 148 !(flags & ~IGC_ACTIVITY_MODES)) 149 return 0; 150 151 /* Single Rx or Tx activity is not supported. */ 152 if (flags & IGC_ACTIVITY_MODES) 153 return -EOPNOTSUPP; 154 155 /* Only one mode can be active at a given time. */ 156 if (flags & (flags - 1)) 157 return -EOPNOTSUPP; 158 159 return 0; 160 } 161 162 static int igc_led_hw_control_set(struct led_classdev *led_cdev, 163 unsigned long flags) 164 { 165 struct igc_led_classdev *ldev = lcdev_to_igc_ldev(led_cdev); 166 struct igc_adapter *adapter = netdev_priv(ldev->netdev); 167 u32 mode = IGC_LEDCTL_MODE_OFF; 168 bool blink = false; 169 170 if (flags & BIT(TRIGGER_NETDEV_LINK_10)) 171 mode = IGC_LEDCTL_MODE_LINK_10; 172 if (flags & BIT(TRIGGER_NETDEV_LINK_100)) 173 mode = IGC_LEDCTL_MODE_LINK_100; 174 if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) 175 mode = IGC_LEDCTL_MODE_LINK_1000; 176 if (flags & BIT(TRIGGER_NETDEV_LINK_2500)) 177 mode = IGC_LEDCTL_MODE_LINK_2500; 178 if ((flags & BIT(TRIGGER_NETDEV_TX)) && 179 (flags & BIT(TRIGGER_NETDEV_RX))) 180 mode = IGC_LEDCTL_MODE_ACTIVITY; 181 182 netdev_dbg(adapter->netdev, "Set HW control for LED %d to mode %u!\n", 183 ldev->index, mode); 184 185 /* blink is recommended for activity */ 186 if (mode == IGC_LEDCTL_MODE_ACTIVITY) 187 blink = true; 188 189 igc_led_set(adapter, ldev->index, mode, blink); 190 191 return 0; 192 } 193 194 static int igc_led_hw_control_get(struct led_classdev *led_cdev, 195 unsigned long *flags) 196 { 197 struct igc_led_classdev *ldev = lcdev_to_igc_ldev(led_cdev); 198 struct igc_adapter *adapter = netdev_priv(ldev->netdev); 199 u32 mode; 200 201 mode = igc_led_get(adapter, ldev->index); 202 203 switch (mode) { 204 case IGC_LEDCTL_MODE_ACTIVITY: 205 *flags = BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); 206 break; 207 case IGC_LEDCTL_MODE_LINK_10: 208 *flags = BIT(TRIGGER_NETDEV_LINK_10); 209 break; 210 case IGC_LEDCTL_MODE_LINK_100: 211 *flags = BIT(TRIGGER_NETDEV_LINK_100); 212 break; 213 case IGC_LEDCTL_MODE_LINK_1000: 214 *flags = BIT(TRIGGER_NETDEV_LINK_1000); 215 break; 216 case IGC_LEDCTL_MODE_LINK_2500: 217 *flags = BIT(TRIGGER_NETDEV_LINK_2500); 218 break; 219 } 220 221 return 0; 222 } 223 224 static struct device *igc_led_hw_control_get_device(struct led_classdev *led_cdev) 225 { 226 struct igc_led_classdev *ldev = lcdev_to_igc_ldev(led_cdev); 227 228 return &ldev->netdev->dev; 229 } 230 231 static void igc_led_get_name(struct igc_adapter *adapter, int index, char *buf, 232 size_t buf_len) 233 { 234 snprintf(buf, buf_len, "igc-%x%x-led%d", 235 pci_domain_nr(adapter->pdev->bus), 236 pci_dev_id(adapter->pdev), index); 237 } 238 239 static int igc_setup_ldev(struct igc_led_classdev *ldev, 240 struct net_device *netdev, int index) 241 { 242 struct igc_adapter *adapter = netdev_priv(netdev); 243 struct led_classdev *led_cdev = &ldev->led; 244 char led_name[LED_MAX_NAME_SIZE]; 245 246 ldev->netdev = netdev; 247 ldev->index = index; 248 249 igc_led_get_name(adapter, index, led_name, LED_MAX_NAME_SIZE); 250 led_cdev->name = led_name; 251 led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; 252 led_cdev->max_brightness = 1; 253 led_cdev->brightness_set_blocking = igc_led_brightness_set_blocking; 254 led_cdev->hw_control_trigger = "netdev"; 255 led_cdev->hw_control_is_supported = igc_led_hw_control_is_supported; 256 led_cdev->hw_control_set = igc_led_hw_control_set; 257 led_cdev->hw_control_get = igc_led_hw_control_get; 258 led_cdev->hw_control_get_device = igc_led_hw_control_get_device; 259 260 return led_classdev_register(&netdev->dev, led_cdev); 261 } 262 263 int igc_led_setup(struct igc_adapter *adapter) 264 { 265 struct net_device *netdev = adapter->netdev; 266 struct igc_led_classdev *leds; 267 int i, err; 268 269 mutex_init(&adapter->led_mutex); 270 271 leds = kcalloc(IGC_NUM_LEDS, sizeof(*leds), GFP_KERNEL); 272 if (!leds) 273 return -ENOMEM; 274 275 for (i = 0; i < IGC_NUM_LEDS; i++) { 276 err = igc_setup_ldev(leds + i, netdev, i); 277 if (err) 278 goto err; 279 } 280 281 adapter->leds = leds; 282 283 return 0; 284 285 err: 286 for (i--; i >= 0; i--) 287 led_classdev_unregister(&((leds + i)->led)); 288 289 kfree(leds); 290 return err; 291 } 292 293 void igc_led_free(struct igc_adapter *adapter) 294 { 295 struct igc_led_classdev *leds = adapter->leds; 296 int i; 297 298 for (i = 0; i < IGC_NUM_LEDS; i++) 299 led_classdev_unregister(&((leds + i)->led)); 300 301 kfree(leds); 302 } 303