igc_leds.c 7.6 KB

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