hibmcge is a PCIE EP device, and its controller is not on the board. And board uses ACPI not DTS to create the device tree. So, this makes it impossible to add a "reg" property(used in of_phy_led()) for hibmcge. Therefore, the PHY_LED framework cannot be used directly. This patch creates a separate LED device for hibmcge and directly calls the phy->drv->led_hw**() function to operate the related LEDs. Signed-off-by: Jijie Shao --- drivers/net/ethernet/hisilicon/Kconfig | 8 ++ .../net/ethernet/hisilicon/hibmcge/Makefile | 1 + .../net/ethernet/hisilicon/hibmcge/hbg_led.c | 132 ++++++++++++++++++ .../net/ethernet/hisilicon/hibmcge/hbg_led.h | 17 +++ .../net/ethernet/hisilicon/hibmcge/hbg_main.c | 7 + 5 files changed, 165 insertions(+) create mode 100644 drivers/net/ethernet/hisilicon/hibmcge/hbg_led.c create mode 100644 drivers/net/ethernet/hisilicon/hibmcge/hbg_led.h diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index 65302c41bfb1..143b25f329c7 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -157,4 +157,12 @@ config HIBMCGE If you are unsure, say N. +config HIBMCGE_LEDS + def_bool LEDS_TRIGGER_NETDEV + depends on HIBMCGE && LEDS_CLASS + depends on LEDS_CLASS=y || HIBMCGE=m + help + Optional support for controlling the NIC LED's with the netdev + LED trigger. + endif # NET_VENDOR_HISILICON diff --git a/drivers/net/ethernet/hisilicon/hibmcge/Makefile b/drivers/net/ethernet/hisilicon/hibmcge/Makefile index 1a9da564b306..a78057208064 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/Makefile +++ b/drivers/net/ethernet/hisilicon/hibmcge/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_HIBMCGE) += hibmcge.o hibmcge-objs = hbg_main.o hbg_hw.o hbg_mdio.o hbg_irq.o hbg_txrx.o hbg_ethtool.o \ hbg_debugfs.o hbg_err.o hbg_diagnose.o +hibmcge-$(CONFIG_HIBMCGE_LEDS) += hbg_led.o diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_led.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_led.c new file mode 100644 index 000000000000..013eae1c54f2 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_led.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2025 Hisilicon Limited. + +#include +#include +#include +#include "hbg_common.h" +#include "hbg_led.h" + +#define PHY_ID_YT8521 0x0000011a + +#define to_hbg_led(lcdev) container_of(lcdev, struct hbg_led_classdev, led) +#define to_hbg_phy_dev(lcdev) \ + (((struct hbg_led_classdev *)to_hbg_led(lcdev))->priv->mac.phydev) + +static int hbg_led_hw_control_set(struct led_classdev *led_cdev, + unsigned long rules) +{ + struct hbg_led_classdev *hbg_led = to_hbg_led(led_cdev); + struct phy_device *phydev = to_hbg_phy_dev(led_cdev); + int ret; + + mutex_lock(&phydev->lock); + ret = phydev->drv->led_hw_control_set(phydev, hbg_led->index, rules); + mutex_unlock(&phydev->lock); + + return ret; +} + +static int hbg_led_hw_control_get(struct led_classdev *led_cdev, + unsigned long *rules) +{ + struct hbg_led_classdev *hbg_led = to_hbg_led(led_cdev); + struct phy_device *phydev = to_hbg_phy_dev(led_cdev); + int ret; + + mutex_lock(&phydev->lock); + ret = phydev->drv->led_hw_control_get(phydev, hbg_led->index, rules); + mutex_unlock(&phydev->lock); + + return ret; +} + +static int hbg_led_hw_is_supported(struct led_classdev *led_cdev, + unsigned long rules) +{ + struct hbg_led_classdev *hbg_led = to_hbg_led(led_cdev); + struct phy_device *phydev = to_hbg_phy_dev(led_cdev); + int ret; + + mutex_lock(&phydev->lock); + ret = phydev->drv->led_hw_is_supported(phydev, hbg_led->index, rules); + mutex_unlock(&phydev->lock); + + return ret; +} + +static struct device * + hbg_led_hw_control_get_device(struct led_classdev *led_cdev) +{ + struct hbg_led_classdev *hbg_led = to_hbg_led(led_cdev); + + return &hbg_led->priv->netdev->dev; +} + +static int hbg_setup_ldev(struct hbg_led_classdev *hbg_led) +{ + struct led_classdev *ldev = &hbg_led->led; + struct hbg_priv *priv = hbg_led->priv; + struct device *dev = &priv->pdev->dev; + + ldev->name = devm_kasprintf(dev, GFP_KERNEL, "%s-%s-%d", + dev_driver_string(dev), + pci_name(priv->pdev), hbg_led->index); + if (!ldev->name) + return -ENOMEM; + + ldev->hw_control_trigger = "netdev"; + ldev->hw_control_set = hbg_led_hw_control_set; + ldev->hw_control_get = hbg_led_hw_control_get; + ldev->hw_control_is_supported = hbg_led_hw_is_supported; + ldev->hw_control_get_device = hbg_led_hw_control_get_device; + + return devm_led_classdev_register(dev, ldev); +} + +static u32 hbg_get_phy_max_led_count(struct hbg_priv *priv) +{ + struct phy_device *phydev = priv->mac.phydev; + + if (!phydev->drv->led_hw_is_supported || + !phydev->drv->led_hw_control_set || + !phydev->drv->led_hw_control_get) + return 0; + + /* YT8521, support 3 leds */ + if (phydev->drv->phy_id == PHY_ID_YT8521) + return 3; + + return 0; +} + +int hbg_leds_init(struct hbg_priv *priv) +{ + u32 led_count = hbg_get_phy_max_led_count(priv); + struct phy_device *phydev = priv->mac.phydev; + struct hbg_led_classdev *leds; + int ret; + int i; + + if (!led_count) + return 0; + + leds = devm_kcalloc(&priv->pdev->dev, led_count, + sizeof(*leds), GFP_KERNEL); + if (!leds) + return -ENOMEM; + + for (i = 0; i < led_count; i++) { + /* for YT8521, we only have two lights, 0 and 2. */ + if (phydev->drv->phy_id == PHY_ID_YT8521 && i == 1) + continue; + + leds[i].priv = priv; + leds[i].index = i; + ret = hbg_setup_ldev(&leds[i]); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_led.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_led.h new file mode 100644 index 000000000000..463285077c91 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_led.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2025 Hisilicon Limited. */ + +#ifndef __HBG_LED_H +#define __HBG_LED_H + +#include "hbg_common.h" + +struct hbg_led_classdev { + struct hbg_priv *priv; + struct led_classdev led; + u32 index; +}; + +int hbg_leds_init(struct hbg_priv *priv); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c index 2e64dc1ab355..f2f8f651f3d2 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c @@ -12,6 +12,7 @@ #include "hbg_ethtool.h" #include "hbg_hw.h" #include "hbg_irq.h" +#include "hbg_led.h" #include "hbg_mdio.h" #include "hbg_txrx.h" #include "hbg_debugfs.h" @@ -383,6 +384,12 @@ static int hbg_init(struct hbg_priv *priv) if (ret) return ret; + if (IS_ENABLED(CONFIG_HIBMCGE_LEDS)) { + ret = hbg_leds_init(priv); + if (ret) + return ret; + } + ret = hbg_mac_filter_init(priv); if (ret) return ret; -- 2.33.0