linux-leds.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/4] Add support for led triggers on phy link state change
@ 2016-10-17 15:49 Zach Brown
  2016-10-17 15:49 ` [PATCH v5 1/4] skge: Rename LED_OFF and LED_ON in marvel skge driver to avoid conflicts with leds namespace Zach Brown
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Zach Brown @ 2016-10-17 15:49 UTC (permalink / raw)
  To: f.fainelli
  Cc: devel, florian.c.schilhabel, andrew, netdev, linux-kernel,
	rpurdie, gregkh, Larry.Finger, j.anaszewski, linux-leds, mlindner

Fix skge driver that declared enum contants that conflicted with enum
constants in linux/leds.h

Create function that encapsulates actions taken during the adjust phy link step
of phy state changes.

Create function that provides list of speeds currently supported by the phy.

Add support for led triggers on phy link state changes by adding
a config option. When set the config option will create a set of led triggers
for each phy device. Users can use the led triggers to represent link state
changes on the phy.

v2:
 * New patch that creates phy_adjust_link function to encapsulate actions taken
   when adjusting phy link during phy state changes
 * led trigger speed strings changed to match existing phy speed strings
 * New function that maps speeds to led triggers
 * Replace magic constants with definitions when declaring trigger name
   buffer and number of triggers.
v3:
 * Changed LED_ON to LED_REG_ON in skge driver to avoid possible future
   conflict and improve consistency.
 * Dropped rtl8712 patch that was accepted separately.
v4:
 * tweaked commit message
v5
 * Changed commit message to explain relationship between the new triggers and
   leds driven by phys.
 * Added new patch that creates phy_supported_speeds function.
 * Moved phy_leds_triggers_register and phy_leds_triggers_unregister to
   phy_attach and phy_detach respectively. This change is so the
   phydev->supported field will be filled by the time the triggers are
   registered.
 * Changed hardcoded list of triggers to dynamic list determined by speeds
   return by phy_supported_speeds.

Zach Brown (4):
  skge: Rename LED_OFF and LED_ON in marvel skge driver to avoid
    conflicts with     leds namespace
  net: phy: Encapsulate actions performed during link state changes into
        function phy_adjust_link
  net: phy: Create phy_supported_speeds function which lists speeds
    currently supported by a     phydevice
  net: phy: leds: add support for led triggers on phy link state change

 drivers/net/ethernet/marvell/skge.c |   6 +-
 drivers/net/ethernet/marvell/skge.h |   4 +-
 drivers/net/phy/Kconfig             |  13 ++++
 drivers/net/phy/Makefile            |   1 +
 drivers/net/phy/phy.c               |  57 ++++++++++++---
 drivers/net/phy/phy_device.c        |   5 ++
 drivers/net/phy/phy_led_triggers.c  | 136 ++++++++++++++++++++++++++++++++++++
 include/linux/phy.h                 |  22 ++++++
 include/linux/phy_led_triggers.h    |  51 ++++++++++++++
 9 files changed, 282 insertions(+), 13 deletions(-)
 create mode 100644 drivers/net/phy/phy_led_triggers.c
 create mode 100644 include/linux/phy_led_triggers.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v5 1/4] skge: Rename LED_OFF and LED_ON in marvel skge driver to avoid conflicts with leds namespace
  2016-10-17 15:49 [PATCH v5 0/4] Add support for led triggers on phy link state change Zach Brown
@ 2016-10-17 15:49 ` Zach Brown
  2016-10-17 15:49 ` [PATCH v5 2/4] net: phy: Encapsulate actions performed during link state changes into function phy_adjust_link Zach Brown
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Zach Brown @ 2016-10-17 15:49 UTC (permalink / raw)
  To: f.fainelli
  Cc: devel, florian.c.schilhabel, andrew, netdev, linux-kernel,
	rpurdie, gregkh, Larry.Finger, j.anaszewski, linux-leds, mlindner

Adding led support for phy causes namespace conflicts for some
phy drivers.

The marvel skge driver declared an enum for representing the states of
Link LED Register. The enum contained constant LED_OFF which conflicted
with declartation found in linux/leds.h.
LED_OFF changed to LED_REG_OFF
Also changed LED_ON to LED_REG_ON to avoid possible future conflict and
for consistency.

Signed-off-by: Zach Brown <zach.brown@ni.com>
---
 drivers/net/ethernet/marvell/skge.c | 6 +++---
 drivers/net/ethernet/marvell/skge.h | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index 7173836..783df01 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -1048,7 +1048,7 @@ static const char *skge_pause(enum pause_status status)
 static void skge_link_up(struct skge_port *skge)
 {
 	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG),
-		    LED_BLK_OFF|LED_SYNC_OFF|LED_ON);
+		    LED_BLK_OFF|LED_SYNC_OFF|LED_REG_ON);
 
 	netif_carrier_on(skge->netdev);
 	netif_wake_queue(skge->netdev);
@@ -1062,7 +1062,7 @@ static void skge_link_up(struct skge_port *skge)
 
 static void skge_link_down(struct skge_port *skge)
 {
-	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
+	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_REG_OFF);
 	netif_carrier_off(skge->netdev);
 	netif_stop_queue(skge->netdev);
 
@@ -2668,7 +2668,7 @@ static int skge_down(struct net_device *dev)
 	if (hw->ports == 1)
 		free_irq(hw->pdev->irq, hw);
 
-	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
+	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_REG_OFF);
 	if (is_genesis(hw))
 		genesis_stop(skge);
 	else
diff --git a/drivers/net/ethernet/marvell/skge.h b/drivers/net/ethernet/marvell/skge.h
index a2eb341..3ea151f 100644
--- a/drivers/net/ethernet/marvell/skge.h
+++ b/drivers/net/ethernet/marvell/skge.h
@@ -662,8 +662,8 @@ enum {
 	LED_BLK_OFF	= 1<<4,	/* Link LED Blinking Off */
 	LED_SYNC_ON	= 1<<3,	/* Use Sync Wire to switch LED */
 	LED_SYNC_OFF	= 1<<2,	/* Disable Sync Wire Input */
-	LED_ON	= 1<<1,	/* switch LED on */
-	LED_OFF	= 1<<0,	/* switch LED off */
+	LED_REG_ON	= 1<<1,	/* switch LED on */
+	LED_REG_OFF	= 1<<0,	/* switch LED off */
 };
 
 /* Receive GMAC FIFO (YUKON) */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v5 2/4] net: phy: Encapsulate actions performed during link state changes into function phy_adjust_link
  2016-10-17 15:49 [PATCH v5 0/4] Add support for led triggers on phy link state change Zach Brown
  2016-10-17 15:49 ` [PATCH v5 1/4] skge: Rename LED_OFF and LED_ON in marvel skge driver to avoid conflicts with leds namespace Zach Brown
@ 2016-10-17 15:49 ` Zach Brown
  2016-10-17 15:49 ` [PATCH v5 3/4] net: phy: Create phy_supported_speeds function which lists speeds currently supported by a phydevice Zach Brown
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Zach Brown @ 2016-10-17 15:49 UTC (permalink / raw)
  To: f.fainelli
  Cc: devel, florian.c.schilhabel, andrew, netdev, linux-kernel,
	rpurdie, gregkh, Larry.Finger, j.anaszewski, linux-leds, mlindner

During phy state machine state transitions some set of actions should
occur whenever the link state changes. These actions should be
encapsulated into a single function

This patch adds the phy_adjust_link function, which is called whenever
phydev->adjust_link would have been called before. Actions that should
occur whenever the phy link is adjusted can now be added to the
phy_adjust_link function.

Signed-off-by: Zach Brown <zach.brown@ni.com>
---
 drivers/net/phy/phy.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c6f6683..f5721db 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -893,6 +893,11 @@ void phy_start(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_start);
 
+static void phy_adjust_link(struct phy_device *phydev)
+{
+	phydev->adjust_link(phydev->attached_dev);
+}
+
 /**
  * phy_state_machine - Handle the state machine
  * @work: work_struct that describes the work to be done
@@ -935,7 +940,7 @@ void phy_state_machine(struct work_struct *work)
 		if (!phydev->link) {
 			phydev->state = PHY_NOLINK;
 			netif_carrier_off(phydev->attached_dev);
-			phydev->adjust_link(phydev->attached_dev);
+			phy_adjust_link(phydev);
 			break;
 		}
 
@@ -948,7 +953,7 @@ void phy_state_machine(struct work_struct *work)
 		if (err > 0) {
 			phydev->state = PHY_RUNNING;
 			netif_carrier_on(phydev->attached_dev);
-			phydev->adjust_link(phydev->attached_dev);
+			phy_adjust_link(phydev);
 
 		} else if (0 == phydev->link_timeout--)
 			needs_aneg = true;
@@ -975,7 +980,7 @@ void phy_state_machine(struct work_struct *work)
 			}
 			phydev->state = PHY_RUNNING;
 			netif_carrier_on(phydev->attached_dev);
-			phydev->adjust_link(phydev->attached_dev);
+			phy_adjust_link(phydev);
 		}
 		break;
 	case PHY_FORCING:
@@ -991,7 +996,7 @@ void phy_state_machine(struct work_struct *work)
 				needs_aneg = true;
 		}
 
-		phydev->adjust_link(phydev->attached_dev);
+		phy_adjust_link(phydev);
 		break;
 	case PHY_RUNNING:
 		/* Only register a CHANGE if we are polling and link changed
@@ -1020,7 +1025,7 @@ void phy_state_machine(struct work_struct *work)
 			netif_carrier_off(phydev->attached_dev);
 		}
 
-		phydev->adjust_link(phydev->attached_dev);
+		phy_adjust_link(phydev);
 
 		if (phy_interrupt_is_valid(phydev))
 			err = phy_config_interrupt(phydev,
@@ -1030,7 +1035,7 @@ void phy_state_machine(struct work_struct *work)
 		if (phydev->link) {
 			phydev->link = 0;
 			netif_carrier_off(phydev->attached_dev);
-			phydev->adjust_link(phydev->attached_dev);
+			phy_adjust_link(phydev);
 			do_suspend = true;
 		}
 		break;
@@ -1054,7 +1059,7 @@ void phy_state_machine(struct work_struct *work)
 				} else	{
 					phydev->state = PHY_NOLINK;
 				}
-				phydev->adjust_link(phydev->attached_dev);
+				phy_adjust_link(phydev);
 			} else {
 				phydev->state = PHY_AN;
 				phydev->link_timeout = PHY_AN_TIMEOUT;
@@ -1070,7 +1075,7 @@ void phy_state_machine(struct work_struct *work)
 			} else	{
 				phydev->state = PHY_NOLINK;
 			}
-			phydev->adjust_link(phydev->attached_dev);
+			phy_adjust_link(phydev);
 		}
 		break;
 	}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v5 3/4] net: phy: Create phy_supported_speeds function which lists speeds currently supported by a phydevice
  2016-10-17 15:49 [PATCH v5 0/4] Add support for led triggers on phy link state change Zach Brown
  2016-10-17 15:49 ` [PATCH v5 1/4] skge: Rename LED_OFF and LED_ON in marvel skge driver to avoid conflicts with leds namespace Zach Brown
  2016-10-17 15:49 ` [PATCH v5 2/4] net: phy: Encapsulate actions performed during link state changes into function phy_adjust_link Zach Brown
@ 2016-10-17 15:49 ` Zach Brown
  2016-10-17 15:49 ` [PATCH v5 4/4] net: phy: leds: add support for led triggers on phy link state change Zach Brown
  2016-10-18 15:57 ` [PATCH v5 0/4] Add " David Miller
  4 siblings, 0 replies; 8+ messages in thread
From: Zach Brown @ 2016-10-17 15:49 UTC (permalink / raw)
  To: f.fainelli
  Cc: devel, florian.c.schilhabel, andrew, netdev, linux-kernel,
	rpurdie, gregkh, Larry.Finger, j.anaszewski, linux-leds, mlindner

phy_supported_speeds provides a means to get a list of all the speeds a
phy device currently supports.

Signed-off-by: Zach Brown <zach.brown@ni.com>
---
 drivers/net/phy/phy.c | 35 +++++++++++++++++++++++++++++++++++
 include/linux/phy.h   | 15 +++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index f5721db..82ee233 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -261,6 +261,41 @@ static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
 }
 
 /**
+ * phy_supported_speeds - return all speeds currently supported by a phy device
+ * @phy: The phy device to return supported speeds of.
+ * @speeds: buffer to store supported speeds in.
+ * @size:   size of speeds buffer.
+ *
+ * Description: Returns the number of supported speeds, and fills the speeds
+ * buffer with the supported speeds. If speeds buffer is too small to contain
+ * all currently supported speeds, will return as many speeds as can fit.
+ */
+unsigned int phy_supported_speeds(struct phy_device *phy,
+				  unsigned int *speeds,
+				  unsigned int size)
+{
+	unsigned int count = 0;
+	unsigned int idx = 0;
+
+	while (idx < MAX_NUM_SETTINGS && count < size) {
+		idx = phy_find_valid(idx, phy->supported);
+
+		if (!(settings[idx].setting & phy->supported))
+			break;
+
+		/* Assumes settings are grouped by speed */
+		if ((count == 0) ||
+		    (speeds[count - 1] != settings[idx].speed)) {
+			speeds[count] = settings[idx].speed;
+			count++;
+		}
+		idx++;
+	}
+
+	return count;
+}
+
+/**
  * phy_check_valid - check if there is a valid PHY setting which matches
  *		     speed, duplex, and feature mask
  * @speed: speed to match
diff --git a/include/linux/phy.h b/include/linux/phy.h
index e25f183..8761f30 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -85,6 +85,21 @@ typedef enum {
 } phy_interface_t;
 
 /**
+ * phy_supported_speeds - return all speeds currently supported by a phy device
+ * @phy: The phy device to return supported speeds of.
+ * @speeds: buffer to store supported speeds in.
+ * @size: size of speeds buffer.
+ *
+ * Description: Returns the number of supported speeds, and
+ * fills the speeds * buffer with the supported speeds. If speeds buffer is
+ * too small to contain * all currently supported speeds, will return as
+ * many speeds as can fit.
+ */
+unsigned int phy_supported_speeds(struct phy_device *phy,
+				      unsigned int *speeds,
+				      unsigned int size);
+
+/**
  * It maps 'enum phy_interface_t' found in include/linux/phy.h
  * into the device tree binding of 'phy-mode', so that Ethernet
  * device driver can get phy interface from device tree.
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v5 4/4] net: phy: leds: add support for led triggers on phy link state change
  2016-10-17 15:49 [PATCH v5 0/4] Add support for led triggers on phy link state change Zach Brown
                   ` (2 preceding siblings ...)
  2016-10-17 15:49 ` [PATCH v5 3/4] net: phy: Create phy_supported_speeds function which lists speeds currently supported by a phydevice Zach Brown
@ 2016-10-17 15:49 ` Zach Brown
  2016-10-18  7:13   ` Andrew Lunn
  2016-10-18 15:57 ` [PATCH v5 0/4] Add " David Miller
  4 siblings, 1 reply; 8+ messages in thread
From: Zach Brown @ 2016-10-17 15:49 UTC (permalink / raw)
  To: f.fainelli
  Cc: devel, florian.c.schilhabel, andrew, netdev, linux-kernel,
	rpurdie, gregkh, Larry.Finger, j.anaszewski, linux-leds, mlindner

Create an option CONFIG_LED_TRIGGER_PHY (default n), which will create a
set of led triggers for each instantiated PHY device. There is one LED
trigger per link-speed, per-phy.
The triggers are registered during phy_attach and unregistered during
phy_detach.

This allows for a user to configure their system to allow a set of LEDs
not controlled by the phy to represent link state changes on the phy.
LEDS controlled by the phy are unaffected.

For example, we have a board where some of the leds in the
RJ45 socket are controlled by the phy, but others are not. Using the
triggers provided by this patch the leds not controlled by the phy can
be configured to show the current speed of the ethernet connection. The
leds controlled by the phy are unaffected.

Signed-off-by: Josh Cartwright <josh.cartwright@ni.com>
Signed-off-by: Nathan Sullivan <nathan.sullivan@ni.com>
Signed-off-by: Zach Brown <zach.brown@ni.com>
---
 drivers/net/phy/Kconfig            |  13 ++++
 drivers/net/phy/Makefile           |   1 +
 drivers/net/phy/phy.c              |   1 +
 drivers/net/phy/phy_device.c       |   5 ++
 drivers/net/phy/phy_led_triggers.c | 136 +++++++++++++++++++++++++++++++++++++
 include/linux/phy.h                |   7 ++
 include/linux/phy_led_triggers.h   |  51 ++++++++++++++
 7 files changed, 214 insertions(+)
 create mode 100644 drivers/net/phy/phy_led_triggers.c
 create mode 100644 include/linux/phy_led_triggers.h

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 5078a0d..54c8eb8 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -15,6 +15,19 @@ if PHYLIB
 config SWPHY
 	bool
 
+config LED_TRIGGER_PHY
+	bool "Support LED triggers for tracking link state"
+	depends on LEDS_TRIGGERS
+	---help---
+	  Adds support for a set of LED trigger events per-PHY.  Link
+	  state change will trigger the events, for consumption by an
+	  LED class driver.  There are triggers for each link speed currently
+	  supported by the phy, and are of the form:
+	       <mii bus id>:<phy>:<speed>
+
+	  Where speed is in the form:
+		<Speed in megabits>Mbps or <Speed in gigabits>Gbps
+
 comment "MDIO bus device drivers"
 
 config MDIO_BCM_IPROC
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index e58667d..86d12cd 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -2,6 +2,7 @@
 
 libphy-y			:= phy.o phy_device.o mdio_bus.o mdio_device.o
 libphy-$(CONFIG_SWPHY)		+= swphy.o
+libphy-$(CONFIG_LED_TRIGGER_PHY)	+= phy_led_triggers.o
 
 obj-$(CONFIG_PHYLIB)		+= libphy.o
 
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 82ee233..ef0e3d0 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -931,6 +931,7 @@ EXPORT_SYMBOL(phy_start);
 static void phy_adjust_link(struct phy_device *phydev)
 {
 	phydev->adjust_link(phydev->attached_dev);
+	phy_led_trigger_change_speed(phydev);
 }
 
 /**
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index e977ba9..b41ebd5 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -30,6 +30,7 @@
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/phy.h>
+#include <linux/phy_led_triggers.h>
 #include <linux/mdio.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
@@ -916,6 +917,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
 	else
 		phy_resume(phydev);
 
+	phy_led_triggers_register(phydev);
+
 	return err;
 
 error:
@@ -989,6 +992,8 @@ void phy_detach(struct phy_device *phydev)
 		}
 	}
 
+	phy_led_triggers_unregister(phydev);
+
 	/*
 	 * The phydev might go away on the put_device() below, so avoid
 	 * a use-after-free bug by reading the underlying bus first.
diff --git a/drivers/net/phy/phy_led_triggers.c b/drivers/net/phy/phy_led_triggers.c
new file mode 100644
index 0000000..cda600a
--- /dev/null
+++ b/drivers/net/phy/phy_led_triggers.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 2016 National Instruments Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/leds.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+
+static struct phy_led_trigger *phy_speed_to_led_trigger(struct phy_device *phy,
+							unsigned int speed)
+{
+	unsigned int i;
+
+	for (i = 0; i < phy->phy_num_led_triggers; i++) {
+		if (phy->phy_led_triggers[i].speed == speed)
+			return &phy->phy_led_triggers[i];
+	}
+	return NULL;
+}
+
+void phy_led_trigger_change_speed(struct phy_device *phy)
+{
+	struct phy_led_trigger *plt;
+
+	if (!phy->link)
+		goto out_change_speed;
+
+	if (phy->speed == 0)
+		return;
+
+	plt = phy_speed_to_led_trigger(phy, phy->speed);
+	if (!plt) {
+		netdev_alert(phy->attached_dev,
+			     "No phy led trigger registered for speed(%d)\n",
+			     phy->speed);
+		goto out_change_speed;
+	}
+
+	if (plt != phy->last_triggered) {
+		led_trigger_event(&phy->last_triggered->trigger, LED_OFF);
+		led_trigger_event(&plt->trigger, LED_FULL);
+		phy->last_triggered = plt;
+	}
+	return;
+
+out_change_speed:
+	if (phy->last_triggered) {
+		led_trigger_event(&phy->last_triggered->trigger,
+				  LED_OFF);
+		phy->last_triggered = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed);
+
+static int phy_led_trigger_register(struct phy_device *phy,
+				    struct phy_led_trigger *plt,
+				    unsigned int speed)
+{
+	char name_suffix[PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE];
+
+	plt->speed = speed;
+
+	if (speed < SPEED_1000)
+		snprintf(name_suffix, sizeof(name_suffix), "%dMbps", speed);
+	else if (speed == SPEED_2500)
+		snprintf(name_suffix, sizeof(name_suffix), "2.5Gbps");
+	else
+		snprintf(name_suffix, sizeof(name_suffix), "%dGbps",
+			 DIV_ROUND_CLOSEST(speed, 1000));
+
+	snprintf(plt->name, sizeof(plt->name), PHY_ID_FMT ":%s",
+		 phy->mdio.bus->id, phy->mdio.addr, name_suffix);
+	plt->trigger.name = plt->name;
+
+	return led_trigger_register(&plt->trigger);
+}
+
+static void phy_led_trigger_unregister(struct phy_led_trigger *plt)
+{
+	led_trigger_unregister(&plt->trigger);
+}
+
+int phy_led_triggers_register(struct phy_device *phy)
+{
+	int i, err;
+	unsigned int speeds[50];
+
+	phy->phy_num_led_triggers = phy_supported_speeds(phy, speeds,
+							 ARRAY_SIZE(speeds));
+	if (!phy->phy_num_led_triggers)
+		return 0;
+
+	phy->phy_led_triggers = devm_kzalloc(&phy->mdio.dev,
+					    sizeof(struct phy_led_trigger) *
+						   phy->phy_num_led_triggers,
+					    GFP_KERNEL);
+	if (!phy->phy_led_triggers)
+		return -ENOMEM;
+
+	for (i = 0; i < phy->phy_num_led_triggers; i++) {
+		err = phy_led_trigger_register(phy, &phy->phy_led_triggers[i],
+					       speeds[i]);
+		if (err)
+			goto out_unreg;
+	}
+
+	phy->last_triggered = NULL;
+	phy_led_trigger_change_speed(phy);
+
+	return 0;
+out_unreg:
+	while (i--)
+		phy_led_trigger_unregister(&phy->phy_led_triggers[i]);
+	devm_kfree(&phy->mdio.dev, phy->phy_led_triggers);
+	return err;
+}
+EXPORT_SYMBOL_GPL(phy_led_triggers_register);
+
+void phy_led_triggers_unregister(struct phy_device *phy)
+{
+	int i;
+
+	for (i = 0; i < phy->phy_num_led_triggers; i++)
+		phy_led_trigger_unregister(&phy->phy_led_triggers[i]);
+
+	devm_kfree(&phy->mdio.dev, phy->phy_led_triggers);
+}
+EXPORT_SYMBOL_GPL(phy_led_triggers_unregister);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 8761f30..8ecfd75 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -25,6 +25,7 @@
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/mod_devicetable.h>
+#include <linux/phy_led_triggers.h>
 
 #include <linux/atomic.h>
 
@@ -420,6 +421,12 @@ struct phy_device {
 
 	int link_timeout;
 
+#ifdef CONFIG_LED_TRIGGER_PHY
+	struct phy_led_trigger *phy_led_triggers;
+	unsigned int phy_num_led_triggers;
+	struct phy_led_trigger *last_triggered;
+#endif
+
 	/*
 	 * Interrupt number for this PHY
 	 * -1 means no interrupt
diff --git a/include/linux/phy_led_triggers.h b/include/linux/phy_led_triggers.h
new file mode 100644
index 0000000..a2daea0
--- /dev/null
+++ b/include/linux/phy_led_triggers.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2016 National Instruments Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __PHY_LED_TRIGGERS
+#define __PHY_LED_TRIGGERS
+
+struct phy_device;
+
+#ifdef CONFIG_LED_TRIGGER_PHY
+
+#include <linux/leds.h>
+
+#define PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE	10
+#define PHY_MII_BUS_ID_SIZE	(20 - 3)
+
+#define PHY_LINK_LED_TRIGGER_NAME_SIZE (PHY_MII_BUS_ID_SIZE + \
+				       FIELD_SIZEOF(struct mdio_device, addr)+\
+				       PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE)
+
+struct phy_led_trigger {
+	struct led_trigger trigger;
+	char name[PHY_LINK_LED_TRIGGER_NAME_SIZE];
+	unsigned int speed;
+};
+
+
+extern int phy_led_triggers_register(struct phy_device *phy);
+extern void phy_led_triggers_unregister(struct phy_device *phy);
+extern void phy_led_trigger_change_speed(struct phy_device *phy);
+
+#else
+
+static inline int phy_led_triggers_register(struct phy_device *phy)
+{
+	return 0;
+}
+static inline void phy_led_triggers_unregister(struct phy_device *phy) { }
+static inline void phy_led_trigger_change_speed(struct phy_device *phy) { }
+
+#endif
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v5 4/4] net: phy: leds: add support for led triggers on phy link state change
  2016-10-17 15:49 ` [PATCH v5 4/4] net: phy: leds: add support for led triggers on phy link state change Zach Brown
@ 2016-10-18  7:13   ` Andrew Lunn
  2016-10-18 14:50     ` Zach Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Lunn @ 2016-10-18  7:13 UTC (permalink / raw)
  To: Zach Brown
  Cc: devel, florian.c.schilhabel, f.fainelli, netdev, linux-kernel,
	rpurdie, gregkh, Larry.Finger, j.anaszewski, linux-leds, mlindner

On Mon, Oct 17, 2016 at 10:49:55AM -0500, Zach Brown wrote:
> Create an option CONFIG_LED_TRIGGER_PHY (default n), which will create a
> set of led triggers for each instantiated PHY device. There is one LED
> trigger per link-speed, per-phy.
> The triggers are registered during phy_attach and unregistered during
> phy_detach.
> 
> This allows for a user to configure their system to allow a set of LEDs
> not controlled by the phy to represent link state changes on the phy.
> LEDS controlled by the phy are unaffected.
> 
> For example, we have a board where some of the leds in the
> RJ45 socket are controlled by the phy, but others are not. Using the
> triggers provided by this patch the leds not controlled by the phy can
> be configured to show the current speed of the ethernet connection. The
> leds controlled by the phy are unaffected.

Is there a clear path how we generalise this, so it could also be used
to control PHY LEDs?

The idea i had a while ago was that the PHY LEDS would also have a
list of triggers which mapped to what the PHY controller could do. So
to enable the PHY LED to show RxTx activity, you would enable the RxTx
trigger on the PHY LED.

This needs an extension to the PHY code, in that these triggers are
specific to the LED, not general across all LEDs. But this is not too
big an issue.

We could end up that if a PHY LED can be used as a generic LED, your
'manual' trigger could be used on it. But it could also support the
PHY driven 'automatic' link status indication trigger. Do we want two
triggers for the same or similar information?

	 Andrew

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v5 4/4] net: phy: leds: add support for led triggers on phy link state change
  2016-10-18  7:13   ` Andrew Lunn
@ 2016-10-18 14:50     ` Zach Brown
  0 siblings, 0 replies; 8+ messages in thread
From: Zach Brown @ 2016-10-18 14:50 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: f.fainelli, mlindner, stephen, netdev, linux-kernel, devel,
	florian.c.schilhabel, Larry.Finger, gregkh, rpurdie, j.anaszewski,
	linux-leds

On Tue, Oct 18, 2016 at 09:13:50AM +0200, Andrew Lunn wrote:
> On Mon, Oct 17, 2016 at 10:49:55AM -0500, Zach Brown wrote:
> > Create an option CONFIG_LED_TRIGGER_PHY (default n), which will create a
> > set of led triggers for each instantiated PHY device. There is one LED
> > trigger per link-speed, per-phy.
> > The triggers are registered during phy_attach and unregistered during
> > phy_detach.
> >
> > This allows for a user to configure their system to allow a set of LEDs
> > not controlled by the phy to represent link state changes on the phy.
> > LEDS controlled by the phy are unaffected.
> >
> > For example, we have a board where some of the leds in the
> > RJ45 socket are controlled by the phy, but others are not. Using the
> > triggers provided by this patch the leds not controlled by the phy can
> > be configured to show the current speed of the ethernet connection. The
> > leds controlled by the phy are unaffected.
>
> Is there a clear path how we generalise this, so it could also be used
> to control PHY LEDs?
>

No, this patch set is only concerned with generic LEDs not PHY LEDs.

> The idea i had a while ago was that the PHY LEDS would also have a
> list of triggers which mapped to what the PHY controller could do. So
> to enable the PHY LED to show RxTx activity, you would enable the RxTx
> trigger on the PHY LED.
>
> This needs an extension to the PHY code, in that these triggers are
> specific to the LED, not general across all LEDs. But this is not too
> big an issue.
>
> We could end up that if a PHY LED can be used as a generic LED, your
> 'manual' trigger could be used on it. But it could also support the
> PHY driven 'automatic' link status indication trigger. Do we want two
> triggers for the same or similar information?
>

If generic LEDs can only use the 'manual' triggers then having two triggers
for the same or similar information would be okay. The focus of this patch set
was to allow generic LEDs to represent the current speed of the phy, which is
very useful when the PHY LEDs don't for whatever reason i.e they don't exist or
are busy representing another aspect.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v5 0/4] Add support for led triggers on phy link state change
  2016-10-17 15:49 [PATCH v5 0/4] Add support for led triggers on phy link state change Zach Brown
                   ` (3 preceding siblings ...)
  2016-10-17 15:49 ` [PATCH v5 4/4] net: phy: leds: add support for led triggers on phy link state change Zach Brown
@ 2016-10-18 15:57 ` David Miller
  4 siblings, 0 replies; 8+ messages in thread
From: David Miller @ 2016-10-18 15:57 UTC (permalink / raw)
  To: zach.brown
  Cc: devel, florian.c.schilhabel, f.fainelli, andrew, netdev,
	linux-kernel, rpurdie, gregkh, Larry.Finger, j.anaszewski,
	linux-leds, mlindner

From: Zach Brown <zach.brown@ni.com>
Date: Mon, 17 Oct 2016 10:49:51 -0500

> Fix skge driver that declared enum contants that conflicted with enum
> constants in linux/leds.h
> 
> Create function that encapsulates actions taken during the adjust phy link step
> of phy state changes.
> 
> Create function that provides list of speeds currently supported by the phy.
> 
> Add support for led triggers on phy link state changes by adding
> a config option. When set the config option will create a set of led triggers
> for each phy device. Users can use the led triggers to represent link state
> changes on the phy.

Ok this looks good enough for now, we can expand and improve upon it
later if necessary.

Series applied, thanks Zach.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-10-18 15:57 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-10-17 15:49 [PATCH v5 0/4] Add support for led triggers on phy link state change Zach Brown
2016-10-17 15:49 ` [PATCH v5 1/4] skge: Rename LED_OFF and LED_ON in marvel skge driver to avoid conflicts with leds namespace Zach Brown
2016-10-17 15:49 ` [PATCH v5 2/4] net: phy: Encapsulate actions performed during link state changes into function phy_adjust_link Zach Brown
2016-10-17 15:49 ` [PATCH v5 3/4] net: phy: Create phy_supported_speeds function which lists speeds currently supported by a phydevice Zach Brown
2016-10-17 15:49 ` [PATCH v5 4/4] net: phy: leds: add support for led triggers on phy link state change Zach Brown
2016-10-18  7:13   ` Andrew Lunn
2016-10-18 14:50     ` Zach Brown
2016-10-18 15:57 ` [PATCH v5 0/4] Add " David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).