xref: /linux/drivers/net/ethernet/intel/igc/igc_leds.c (revision 2697b79a469b68e3ad3640f55284359c1396278d)
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