generic: 6.1: backport patch adding support for LED PHY

Backport patch adding support for LED PHY directly in PHY ops struct.
Add new PHYLIB_LEDS config and refresh patches.
Signed-off-by: NChristian Marangi <ansuelsmth@gmail.com>
上级 c46ac89e
From 4bb7aac70b5d8a4bddf4ee0791b834f9f56883d2 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Thu, 20 Apr 2023 10:45:51 +0200
Subject: [PATCH] net: phy: fix circular LEDS_CLASS dependencies
The CONFIG_PHYLIB symbol is selected by a number of device drivers that
need PHY support, but it now has a dependency on CONFIG_LEDS_CLASS,
which may not be enabled, causing build failures.
Avoid the risk of missing and circular dependencies by guarding the
phylib LED support itself in another Kconfig symbol that can only be
enabled if the dependency is met.
This could be made a hidden symbol and always enabled when both CONFIG_OF
and CONFIG_LEDS_CLASS are reachable from the phylib, but there may be an
advantage in having users see this option when they have a misconfigured
kernel without built-in LED support.
Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20230420084624.3005701-1-arnd@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/Kconfig | 9 ++++++++-
drivers/net/phy/phy_device.c | 3 ++-
2 files changed, 10 insertions(+), 2 deletions(-)
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -18,7 +18,6 @@ menuconfig PHYLIB
depends on NETDEVICES
select MDIO_DEVICE
select MDIO_DEVRES
- depends on LEDS_CLASS || LEDS_CLASS=n
help
Ethernet controllers are usually attached to PHY
devices. This option provides infrastructure for
@@ -45,6 +44,14 @@ config LED_TRIGGER_PHY
<Speed in megabits>Mbps OR <Speed in gigabits>Gbps OR link
for any speed known to the PHY.
+config PHYLIB_LEDS
+ bool "Support probing LEDs from device tree"
+ depends on LEDS_CLASS=y || LEDS_CLASS=PHYLIB
+ depends on OF
+ default y
+ help
+ When LED class support is enabled, phylib can automatically
+ probe LED setting from device tree.
config FIXED_PHY
tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs"
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3208,7 +3208,8 @@ static int phy_probe(struct device *dev)
/* Get the LEDs from the device tree, and instantiate standard
* LEDs for them.
*/
- err = of_phy_leds(phydev);
+ if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
+ err = of_phy_leds(phydev);
out:
/* Re-assert the reset signal on error */
From aed8fdad2152d946add50bec00a6b07c457bdcdf Mon Sep 17 00:00:00 2001
From: Alexander Stein <alexander.stein@ew.tq-group.com>
Date: Mon, 24 Apr 2023 16:16:48 +0200
Subject: [PATCH] net: phy: Fix reading LED reg property
'reg' is always encoded in 32 bits, thus it has to be read using the
function with the corresponding bit width.
Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Link: https://lore.kernel.org/r/20230424141648.317944-1-alexander.stein@ew.tq-group.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/phy_device.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2971,6 +2971,7 @@ static int of_phy_led(struct phy_device
struct led_init_data init_data = {};
struct led_classdev *cdev;
struct phy_led *phyled;
+ u32 index;
int err;
phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL);
@@ -2980,10 +2981,13 @@ static int of_phy_led(struct phy_device
cdev = &phyled->led_cdev;
phyled->phydev = phydev;
- err = of_property_read_u8(led, "reg", &phyled->index);
+ err = of_property_read_u32(led, "reg", &index);
if (err)
return err;
+ if (index > U8_MAX)
+ return -EINVAL;
+ phyled->index = index;
if (phydev->drv->led_brightness_set)
cdev->brightness_set_blocking = phy_led_set_brightness;
if (phydev->drv->led_blink_set)
From c938ab4da0eb1620ae3243b0b24c572ddfc318fc Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Sat, 17 Jun 2023 17:55:00 +0200
Subject: [PATCH] net: phy: Manual remove LEDs to ensure correct ordering
If the core is left to remove the LEDs via devm_, it is performed too
late, after the PHY driver is removed from the PHY. This results in
dereferencing a NULL pointer when the LED core tries to turn the LED
off before destroying the LED.
Manually unregister the LEDs at a safe point in phy_remove.
Cc: stable@vger.kernel.org
Reported-by: Florian Fainelli <f.fainelli@gmail.com>
Suggested-by: Florian Fainelli <f.fainelli@gmail.com>
Fixes: 01e5b728e9e4 ("net: phy: Add a binding for PHY LEDs")
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/phy_device.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2964,6 +2964,15 @@ static int phy_led_blink_set(struct led_
return err;
}
+static void phy_leds_unregister(struct phy_device *phydev)
+{
+ struct phy_led *phyled;
+
+ list_for_each_entry(phyled, &phydev->leds, list) {
+ led_classdev_unregister(&phyled->led_cdev);
+ }
+}
+
static int of_phy_led(struct phy_device *phydev,
struct device_node *led)
{
@@ -2997,7 +3006,7 @@ static int of_phy_led(struct phy_device
init_data.fwnode = of_fwnode_handle(led);
init_data.devname_mandatory = true;
- err = devm_led_classdev_register_ext(dev, cdev, &init_data);
+ err = led_classdev_register_ext(dev, cdev, &init_data);
if (err)
return err;
@@ -3026,6 +3035,7 @@ static int of_phy_leds(struct phy_device
err = of_phy_led(phydev, led);
if (err) {
of_node_put(led);
+ phy_leds_unregister(phydev);
return err;
}
}
@@ -3229,6 +3239,9 @@ static int phy_remove(struct device *dev
cancel_delayed_work_sync(&phydev->state_queue);
+ if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
+ phy_leds_unregister(phydev);
+
phydev->state = PHY_DOWN;
sfp_bus_del_upstream(phydev->sfp_bus);
From af7320ecae0ce646fd2c4a88341a3fbc243553da Mon Sep 17 00:00:00 2001
From: Yang Li <yang.lee@linux.alibaba.com>
Date: Thu, 11 May 2023 15:08:20 +0800
Subject: [PATCH] leds: trigger: netdev: Remove NULL check before dev_{put,
hold}
The call netdev_{put, hold} of dev_{put, hold} will check NULL,
so there is no need to check before using dev_{put, hold},
remove it to silence the warnings:
./drivers/leds/trigger/ledtrig-netdev.c:291:3-10: WARNING: NULL check before dev_{put, hold} functions is not needed.
./drivers/leds/trigger/ledtrig-netdev.c:401:2-9: WARNING: NULL check before dev_{put, hold} functions is not needed.
Reported-by: Abaci Robot <abaci@linux.alibaba.com>
Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=4929
Signed-off-by: Yang Li <yang.lee@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230511070820.52731-1-yang.lee@linux.alibaba.com
Signed-off-by: Lee Jones <lee@kernel.org>
---
drivers/leds/trigger/ledtrig-netdev.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -462,8 +462,7 @@ static int netdev_trig_notify(struct not
get_device_state(trigger_data);
fallthrough;
case NETDEV_REGISTER:
- if (trigger_data->net_dev)
- dev_put(trigger_data->net_dev);
+ dev_put(trigger_data->net_dev);
dev_hold(dev);
trigger_data->net_dev = dev;
break;
@@ -594,8 +593,7 @@ static void netdev_trig_deactivate(struc
cancel_delayed_work_sync(&trigger_data->work);
- if (trigger_data->net_dev)
- dev_put(trigger_data->net_dev);
+ dev_put(trigger_data->net_dev);
kfree(trigger_data);
}
From 97c5209b3d374a25ebdb4c2ea9e9c1b121768da0 Mon Sep 17 00:00:00 2001
From: Dan Carpenter <dan.carpenter@linaro.org>
Date: Wed, 14 Jun 2023 10:03:59 +0300
Subject: [PATCH] leds: trigger: netdev: uninitialized variable in
netdev_trig_activate()
The qca8k_cled_hw_control_get() function which implements ->hw_control_get
sets the appropriate bits but does not clear them. This leads to an
uninitialized variable bug. Fix this by setting mode to zero at the
start.
Fixes: e0256648c831 ("net: dsa: qca8k: implement hw_control ops")
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Acked-by: Lee Jones <lee@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/leds/trigger/ledtrig-netdev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -538,7 +538,7 @@ static void netdev_trig_work(struct work
static int netdev_trig_activate(struct led_classdev *led_cdev)
{
struct led_netdev_data *trigger_data;
- unsigned long mode;
+ unsigned long mode = 0;
struct device *dev;
int rc;
From 7df1f14c04cbb1950e79c19793420f87227c3e80 Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:33 +0200
Subject: [PATCH 1/4] led: trig: netdev: Fix requesting offload device
When the netdev trigger is activates, it tries to determine what
device the LED blinks for, and what the current blink mode is.
The documentation for hw_control_get() says:
* Return 0 on success, a negative error number on failing parsing the
* initial mode. Error from this function is NOT FATAL as the device
* may be in a not supported initial state by the attached LED trigger.
*/
For the Marvell PHY and the Armada 370-rd board, the initial LED blink
mode is not supported by the trigger, so it returns an error. This
resulted in not getting the device the LED is blinking for. As a
result, the device is unknown and offloaded is never performed.
Change to condition to always get the device if offloading is
supported, and reduce the scope of testing for an error from
hw_control_get() to skip setting trigger internal state if there is an
error.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-2-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/leds/trigger/ledtrig-netdev.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -564,15 +564,17 @@ static int netdev_trig_activate(struct l
/* Check if hw control is active by default on the LED.
* Init already enabled mode in hw control.
*/
- if (supports_hw_control(led_cdev) &&
- !led_cdev->hw_control_get(led_cdev, &mode)) {
+ if (supports_hw_control(led_cdev)) {
dev = led_cdev->hw_control_get_device(led_cdev);
if (dev) {
const char *name = dev_name(dev);
set_device_name(trigger_data, name, strlen(name));
trigger_data->hw_control = true;
- trigger_data->mode = mode;
+
+ rc = led_cdev->hw_control_get(led_cdev, &mode);
+ if (!rc)
+ trigger_data->mode = mode;
}
}
From 1dcc03c9a7a824a31eaaecdfaa03542fb25feb6c Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:34 +0200
Subject: [PATCH 2/4] net: phy: phy_device: Call into the PHY driver to set LED
offload
Linux LEDs can be requested to perform hardware accelerated blinking
to indicate link, RX, TX etc. Pass the rules for blinking to the PHY
driver, if it implements the ops needed to determine if a given
pattern can be offloaded, to offload it, and what the current offload
is. Additionally implement the op needed to get what device the LED is
for.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-3-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/phy_device.c | 68 ++++++++++++++++++++++++++++++++++++
include/linux/phy.h | 33 +++++++++++++++++
2 files changed, 101 insertions(+)
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2964,6 +2964,61 @@ static int phy_led_blink_set(struct led_
return err;
}
+static __maybe_unused struct device *
+phy_led_hw_control_get_device(struct led_classdev *led_cdev)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+
+ if (phydev->attached_dev)
+ return &phydev->attached_dev->dev;
+ return NULL;
+}
+
+static int __maybe_unused
+phy_led_hw_control_get(struct led_classdev *led_cdev,
+ unsigned long *rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_get(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static int __maybe_unused
+phy_led_hw_control_set(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_set(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static __maybe_unused int phy_led_hw_is_supported(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_is_supported(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
static void phy_leds_unregister(struct phy_device *phydev)
{
struct phy_led *phyled;
@@ -3001,6 +3056,19 @@ static int of_phy_led(struct phy_device
cdev->brightness_set_blocking = phy_led_set_brightness;
if (phydev->drv->led_blink_set)
cdev->blink_set = phy_led_blink_set;
+
+#ifdef CONFIG_LEDS_TRIGGERS
+ if (phydev->drv->led_hw_is_supported &&
+ phydev->drv->led_hw_control_set &&
+ phydev->drv->led_hw_control_get) {
+ cdev->hw_control_is_supported = phy_led_hw_is_supported;
+ cdev->hw_control_set = phy_led_hw_control_set;
+ cdev->hw_control_get = phy_led_hw_control_get;
+ cdev->hw_control_trigger = "netdev";
+ }
+
+ cdev->hw_control_get_device = phy_led_hw_control_get_device;
+#endif
cdev->max_brightness = 1;
init_data.devicename = dev_name(&phydev->mdio.dev);
init_data.fwnode = of_fwnode_handle(led);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1013,6 +1013,39 @@ struct phy_driver {
int (*led_blink_set)(struct phy_device *dev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off);
+ /**
+ * @led_hw_is_supported: Can the HW support the given rules.
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules The core is interested in these rules
+ *
+ * Return 0 if yes, -EOPNOTSUPP if not, or an error code.
+ */
+ int (*led_hw_is_supported)(struct phy_device *dev, u8 index,
+ unsigned long rules);
+ /**
+ * @led_hw_control_set: Set the HW to control the LED
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules The rules used to control the LED
+ *
+ * Returns 0, or a an error code.
+ */
+ int (*led_hw_control_set)(struct phy_device *dev, u8 index,
+ unsigned long rules);
+ /**
+ * @led_hw_control_get: Get how the HW is controlling the LED
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules Pointer to the rules used to control the LED
+ *
+ * Set *@rules to how the HW is currently blinking. Returns 0
+ * on success, or a error code if the current blinking cannot
+ * be represented in rules, or some other error happens.
+ */
+ int (*led_hw_control_get)(struct phy_device *dev, u8 index,
+ unsigned long *rules);
+
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
From 460b0b648fab24f576c481424e0de5479ffb9786 Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:35 +0200
Subject: [PATCH 3/4] net: phy: marvell: Add support for offloading LED
blinking
Add the code needed to indicate if a given blinking pattern can be
offloaded, to offload a pattern and to try to return the current
pattern.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-4-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/marvell.c | 281 ++++++++++++++++++++++++++++++++++++++
1 file changed, 281 insertions(+)
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2893,6 +2893,272 @@ static int m88e1318_led_blink_set(struct
MII_88E1318S_PHY_LED_FUNC, reg);
}
+struct marvell_led_rules {
+ int mode;
+ unsigned long rules;
+};
+
+static const struct marvell_led_rules marvell_led0[] = {
+ {
+ .mode = 0,
+ .rules = BIT(TRIGGER_NETDEV_LINK),
+ },
+ {
+ .mode = 1,
+ .rules = (BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 3,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 4,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 5,
+ .rules = BIT(TRIGGER_NETDEV_TX),
+ },
+ {
+ .mode = 6,
+ .rules = BIT(TRIGGER_NETDEV_LINK),
+ },
+ {
+ .mode = 7,
+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
+ },
+ {
+ .mode = 8,
+ .rules = 0,
+ },
+};
+
+static const struct marvell_led_rules marvell_led1[] = {
+ {
+ .mode = 1,
+ .rules = (BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 2,
+ .rules = (BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_RX)),
+ },
+ {
+ .mode = 3,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 4,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 6,
+ .rules = (BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000)),
+ },
+ {
+ .mode = 7,
+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
+ },
+ {
+ .mode = 8,
+ .rules = 0,
+ },
+};
+
+static const struct marvell_led_rules marvell_led2[] = {
+ {
+ .mode = 0,
+ .rules = BIT(TRIGGER_NETDEV_LINK),
+ },
+ {
+ .mode = 1,
+ .rules = (BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 3,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 4,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 5,
+ .rules = BIT(TRIGGER_NETDEV_TX),
+ },
+ {
+ .mode = 6,
+ .rules = (BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_1000)),
+ },
+ {
+ .mode = 7,
+ .rules = BIT(TRIGGER_NETDEV_LINK_10),
+ },
+ {
+ .mode = 8,
+ .rules = 0,
+ },
+};
+
+static int marvell_find_led_mode(unsigned long rules,
+ const struct marvell_led_rules *marvell_rules,
+ int count,
+ int *mode)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (marvell_rules[i].rules == rules) {
+ *mode = marvell_rules[i].mode;
+ return 0;
+ }
+ }
+ return -EOPNOTSUPP;
+}
+
+static int marvell_get_led_mode(u8 index, unsigned long rules, int *mode)
+{
+ int ret;
+
+ switch (index) {
+ case 0:
+ ret = marvell_find_led_mode(rules, marvell_led0,
+ ARRAY_SIZE(marvell_led0), mode);
+ break;
+ case 1:
+ ret = marvell_find_led_mode(rules, marvell_led1,
+ ARRAY_SIZE(marvell_led1), mode);
+ break;
+ case 2:
+ ret = marvell_find_led_mode(rules, marvell_led2,
+ ARRAY_SIZE(marvell_led2), mode);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int marvell_find_led_rules(unsigned long *rules,
+ const struct marvell_led_rules *marvell_rules,
+ int count,
+ int mode)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (marvell_rules[i].mode == mode) {
+ *rules = marvell_rules[i].rules;
+ return 0;
+ }
+ }
+ return -EOPNOTSUPP;
+}
+
+static int marvell_get_led_rules(u8 index, unsigned long *rules, int mode)
+{
+ int ret;
+
+ switch (index) {
+ case 0:
+ ret = marvell_find_led_rules(rules, marvell_led0,
+ ARRAY_SIZE(marvell_led0), mode);
+ break;
+ case 1:
+ ret = marvell_find_led_rules(rules, marvell_led1,
+ ARRAY_SIZE(marvell_led1), mode);
+ break;
+ case 2:
+ ret = marvell_find_led_rules(rules, marvell_led2,
+ ARRAY_SIZE(marvell_led2), mode);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+static int m88e1318_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ int mode, ret;
+
+ switch (index) {
+ case 0:
+ case 1:
+ case 2:
+ ret = marvell_get_led_mode(index, rules, &mode);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int m88e1318_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ int mode, ret, reg;
+
+ switch (index) {
+ case 0:
+ case 1:
+ case 2:
+ ret = marvell_get_led_mode(index, rules, &mode);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1318S_PHY_LED_FUNC);
+ if (reg < 0)
+ return reg;
+
+ reg &= ~(0xf << (4 * index));
+ reg |= mode << (4 * index);
+ return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1318S_PHY_LED_FUNC, reg);
+}
+
+static int m88e1318_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+{
+ int mode, reg;
+
+ if (index > 2)
+ return -EINVAL;
+
+ reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1318S_PHY_LED_FUNC);
+ if (reg < 0)
+ return reg;
+
+ mode = (reg >> (4 * index)) & 0xf;
+
+ return marvell_get_led_rules(index, rules, mode);
+}
+
static int marvell_probe(struct phy_device *phydev)
{
struct marvell_priv *priv;
@@ -3144,6 +3410,9 @@ static struct phy_driver marvell_drivers
.get_stats = marvell_get_stats,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E1145,
@@ -3252,6 +3521,9 @@ static struct phy_driver marvell_drivers
.cable_test_get_status = marvell_vct7_cable_test_get_status,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
@@ -3280,6 +3552,9 @@ static struct phy_driver marvell_drivers
.cable_test_get_status = marvell_vct7_cable_test_get_status,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E1545,
@@ -3308,6 +3583,9 @@ static struct phy_driver marvell_drivers
.cable_test_get_status = marvell_vct7_cable_test_get_status,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E3016,
@@ -3451,6 +3729,9 @@ static struct phy_driver marvell_drivers
.set_tunable = m88e1540_set_tunable,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
};
From e8fbcc47a8e935f36f044d85f21a99acecbd7bfb Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 8 Aug 2023 23:04:36 +0200
Subject: [PATCH 4/4] leds: trig-netdev: Disable offload on deactivation of
trigger
Ensure that the offloading of blinking is stopped when the trigger is
deactivated. Calling led_set_brightness() is documented as stopping
offload and setting the LED to a constant brightness.
Suggested-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Tested-by: Daniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20230808210436.838995-5-andrew@lunn.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/leds/trigger/ledtrig-netdev.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -595,6 +595,8 @@ static void netdev_trig_deactivate(struc
cancel_delayed_work_sync(&trigger_data->work);
+ led_set_brightness(led_cdev, LED_OFF);
+
dev_put(trigger_data->net_dev);
kfree(trigger_data);
......@@ -4831,6 +4831,7 @@ CONFIG_PCI_SYSCALL=y
# CONFIG_PHANTOM is not set
# CONFIG_PHONET is not set
# CONFIG_PHYLIB is not set
# CONFIG_PHYLIB_LEDS is not set
# CONFIG_PHYS_ADDR_T_64BIT is not set
# CONFIG_PHY_CADENCE_DP is not set
# CONFIG_PHY_CADENCE_DPHY is not set
......
......@@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -62,6 +62,80 @@ config SFP
@@ -69,6 +69,80 @@ config SFP
depends on HWMON || HWMON=n
select MDIO_I2C
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册