mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-21 03:55:06 +00:00
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: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
parent
c46ac89ec6
commit
6b63fcf8df
@ -0,0 +1,65 @@
|
||||
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 */
|
@ -0,0 +1,43 @@
|
||||
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)
|
@ -0,0 +1,67 @@
|
||||
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);
|
@ -0,0 +1,44 @@
|
||||
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);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
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;
|
||||
|
@ -0,0 +1,57 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,149 @@
|
||||
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)
|
@ -0,0 +1,344 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
@ -0,0 +1,31 @@
|
||||
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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user