Merge branches 'pm-cpuidle', 'pm-sleep' and 'pm-powercap'
[linux-block.git] / drivers / net / ethernet / intel / igc / igc_leds.c
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 }