lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1458755500-15571-2-git-send-email-vishalthanki@gmail.com>
Date:	Wed, 23 Mar 2016 18:51:38 +0100
From:	Vishal Thanki <vishalthanki@...il.com>
To:	andrew@...n.ch, f.fainelli@...il.com, ujhelyi.m@...il.com,
	netdev@...r.kernel.org
Cc:	Vishal Thanki <vishalthanki@...il.com>
Subject: [PATCH 1/3] net: phy: Add ethernet PHY LED triggers

Add the LED triggers for ethernet PHY link and activity
status. The triggers are set mainly based on the
PHY state machine.

Signed-off-by: Vishal Thanki <vishalthanki@...il.com>
---
 drivers/net/phy/Kconfig      |  7 +++++
 drivers/net/phy/Makefile     |  1 +
 drivers/net/phy/phy.c        | 20 +++++++++++--
 drivers/net/phy/phy_device.c |  4 +++
 drivers/net/phy/phy_led.c    | 70 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/phy/phy_led.h    | 37 +++++++++++++++++++++++
 include/linux/leds.h         |  1 +
 include/linux/phy.h          |  6 ++++
 8 files changed, 144 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/phy/phy_led.c
 create mode 100644 drivers/net/phy/phy_led.h

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 6dad9a9..15712da 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -271,6 +271,13 @@ config MDIO_BCM_IPROC
 	  This module provides a driver for the MDIO busses found in the
 	  Broadcom iProc SoC's.
 
+config ETH_PHY_LED
+	bool "Ethernet PHY LED trigger support (Experimental)"
+	depends on LEDS_TRIGGERS
+	help
+	  This feature enables the Ethernet PHY LED triggers for PHY link
+	  and data transfer activities.
+
 endif # PHYLIB
 
 config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index fcdbb92..76ebd83 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_MDIO_MOXART)	+= mdio-moxart.o
 obj-$(CONFIG_MDIO_BCM_UNIMAC)	+= mdio-bcm-unimac.o
 obj-$(CONFIG_MICROCHIP_PHY)	+= microchip.o
 obj-$(CONFIG_MDIO_BCM_IPROC)	+= mdio-bcm-iproc.o
+obj-$(CONFIG_ETH_PHY_LED)	+= phy_led.o
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 5590b9c..e422ff6 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -35,6 +35,7 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/atomic.h>
+#include "phy_led.h"
 
 #include <asm/irq.h>
 
@@ -831,15 +832,15 @@ void phy_state_machine(struct work_struct *work)
 
 	switch (phydev->state) {
 	case PHY_DOWN:
+		phy_trig_led_link(phydev, 0);
 	case PHY_STARTING:
 	case PHY_READY:
 	case PHY_PENDING:
 		break;
 	case PHY_UP:
 		needs_aneg = true;
-
 		phydev->link_timeout = PHY_AN_TIMEOUT;
-
+		phy_trig_led_link(phydev, 1);
 		break;
 	case PHY_AN:
 		err = phy_read_status(phydev);
@@ -849,6 +850,7 @@ void phy_state_machine(struct work_struct *work)
 		/* If the link is down, give up on negotiation for now */
 		if (!phydev->link) {
 			phydev->state = PHY_NOLINK;
+			phy_trig_led_link(phydev, 0);
 			netif_carrier_off(phydev->attached_dev);
 			phydev->adjust_link(phydev->attached_dev);
 			break;
@@ -862,6 +864,7 @@ void phy_state_machine(struct work_struct *work)
 		/* If AN is done, we're running */
 		if (err > 0) {
 			phydev->state = PHY_RUNNING;
+			phy_trig_led_act(phydev);
 			netif_carrier_on(phydev->attached_dev);
 			phydev->adjust_link(phydev->attached_dev);
 
@@ -889,6 +892,7 @@ void phy_state_machine(struct work_struct *work)
 				}
 			}
 			phydev->state = PHY_RUNNING;
+			phy_trig_led_act(phydev);
 			netif_carrier_on(phydev->attached_dev);
 			phydev->adjust_link(phydev->attached_dev);
 		}
@@ -900,6 +904,8 @@ void phy_state_machine(struct work_struct *work)
 
 		if (phydev->link) {
 			phydev->state = PHY_RUNNING;
+			phy_trig_led_act(phydev);
+			phy_trig_led_link(phydev, 1);
 			netif_carrier_on(phydev->attached_dev);
 		} else {
 			if (0 == phydev->link_timeout--)
@@ -929,9 +935,12 @@ void phy_state_machine(struct work_struct *work)
 
 		if (phydev->link) {
 			phydev->state = PHY_RUNNING;
+			phy_trig_led_act(phydev);
+			phy_trig_led_link(phydev, 1);
 			netif_carrier_on(phydev->attached_dev);
 		} else {
 			phydev->state = PHY_NOLINK;
+			phy_trig_led_link(phydev, 0);
 			netif_carrier_off(phydev->attached_dev);
 		}
 
@@ -948,6 +957,7 @@ void phy_state_machine(struct work_struct *work)
 			phydev->adjust_link(phydev->attached_dev);
 			do_suspend = true;
 		}
+		led_trigger_event(phydev->phy_act, LED_OFF);
 		break;
 	case PHY_RESUMING:
 		if (AUTONEG_ENABLE == phydev->autoneg) {
@@ -965,9 +975,12 @@ void phy_state_machine(struct work_struct *work)
 
 				if (phydev->link) {
 					phydev->state = PHY_RUNNING;
+					phy_trig_led_link(phydev, 1);
+					phy_trig_led_act(phydev);
 					netif_carrier_on(phydev->attached_dev);
 				} else	{
 					phydev->state = PHY_NOLINK;
+					phy_trig_led_link(phydev, 0);
 				}
 				phydev->adjust_link(phydev->attached_dev);
 			} else {
@@ -981,9 +994,12 @@ void phy_state_machine(struct work_struct *work)
 
 			if (phydev->link) {
 				phydev->state = PHY_RUNNING;
+				phy_trig_led_link(phydev, 1);
+				phy_trig_led_act(phydev);
 				netif_carrier_on(phydev->attached_dev);
 			} else	{
 				phydev->state = PHY_NOLINK;
+				phy_trig_led_link(phydev, 0);
 			}
 			phydev->adjust_link(phydev->attached_dev);
 		}
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index e551f3a..fafcc3c 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -34,6 +34,7 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/of.h>
+#include "phy_led.h"
 
 #include <asm/irq.h>
 
@@ -1592,6 +1593,8 @@ static int phy_probe(struct device *dev)
 	of_set_phy_supported(phydev);
 	phydev->advertising = phydev->supported;
 
+	phy_led_init(phydev);
+
 	/* Set the state to READY by default */
 	phydev->state = PHY_READY;
 
@@ -1608,6 +1611,7 @@ static int phy_remove(struct device *dev)
 	struct phy_device *phydev = to_phy_device(dev);
 
 	mutex_lock(&phydev->lock);
+	phy_led_cleanup(phydev);
 	phydev->state = PHY_DOWN;
 	mutex_unlock(&phydev->lock);
 
diff --git a/drivers/net/phy/phy_led.c b/drivers/net/phy/phy_led.c
new file mode 100644
index 0000000..240355a
--- /dev/null
+++ b/drivers/net/phy/phy_led.c
@@ -0,0 +1,70 @@
+#include <linux/phy.h>
+#include <linux/leds.h>
+
+static void phy_link_trig_activate(struct led_classdev *led)
+{
+	struct phy_device *phydev = led->trigger->data;
+	enum led_brightness value = LED_OFF;
+
+	if (phydev && phydev->state != PHY_DOWN)
+		value = LED_FULL;
+	led_set_brightness(led, value);
+}
+
+static void phy_act_trig_activate(struct led_classdev *led)
+{
+	struct phy_device *phydev = led->trigger->data;
+	unsigned long on = 0, off = 0;
+
+	if (phydev && (phydev->state == PHY_RUNNING ||
+		       phydev->state == PHY_CHANGELINK))
+		led_blink_set(led, &on, &off);
+}
+
+void phy_led_init(struct phy_device *phydev)
+{
+	phydev->phy_link = kzalloc(sizeof(*phydev->phy_link), GFP_KERNEL);
+	if (!phydev->phy_link)
+		return;
+
+	snprintf(phydev->phy_link_name, sizeof(phydev->phy_link_name),
+		 "%x-eth-phy-link", phydev->drv->phy_id);
+	phydev->phy_link->name = phydev->phy_link_name;
+	if (led_trigger_register(phydev->phy_link)) {
+		kfree(phydev->phy_link);
+		phydev->phy_link = NULL;
+	}
+	phydev->phy_link->data = phydev;
+	phydev->phy_link->activate = phy_link_trig_activate;
+
+	phydev->phy_act = kzalloc(sizeof(*phydev->phy_act), GFP_KERNEL);
+	if (!phydev->phy_act) {
+		led_trigger_unregister(phydev->phy_link);
+		kfree(phydev->phy_link);
+		return;
+	}
+	phydev->phy_act->data = phydev;
+	phydev->phy_act->activate = phy_act_trig_activate;
+
+	snprintf(phydev->phy_act_name, sizeof(phydev->phy_act_name),
+		 "%x-eth-phy-activity", phydev->drv->phy_id);
+	phydev->phy_act->name = phydev->phy_act_name;
+	if (led_trigger_register(phydev->phy_act)) {
+		kfree(phydev->phy_act);
+		phydev->phy_act = NULL;
+		return;
+	}
+}
+
+void phy_led_cleanup(struct phy_device *phydev)
+{
+	if (phydev->phy_link) {
+		led_trigger_unregister(phydev->phy_link);
+		kfree(phydev->phy_link);
+	}
+	if (phydev->phy_act) {
+		led_trigger_unregister(phydev->phy_act);
+		kfree(phydev->phy_act);
+	}
+}
+
diff --git a/drivers/net/phy/phy_led.h b/drivers/net/phy/phy_led.h
new file mode 100644
index 0000000..ff5bd98
--- /dev/null
+++ b/drivers/net/phy/phy_led.h
@@ -0,0 +1,37 @@
+#include <linux/leds.h>
+
+#ifdef CONFIG_ETH_PHY_LED
+static inline void phy_trig_led_act(struct phy_device *phydev)
+{
+	unsigned long on = 0, off = 0;
+
+	led_trigger_blink(phydev->phy_act, &on, &off);
+}
+
+static inline void phy_trig_led_link(struct phy_device *phydev, int on)
+{
+	enum led_brightness value = (on) ? LED_FULL : LED_OFF;
+
+	led_trigger_event(phydev->phy_link, value);
+}
+
+void phy_led_init(struct phy_device *phydev);
+void phy_led_cleanup(struct phy_device *phydev);
+#else
+static inline void phy_trig_led_act(struct phy_device *phydev)
+{
+}
+
+static inline void phy_trig_led_link(struct phy_device *phydev, int on)
+{
+}
+
+static inline void phy_led_init(struct phy_device *phydev)
+{
+}
+
+static inline void phy_led_cleanup(struct phy_device *phydev)
+{
+}
+#endif
+
diff --git a/include/linux/leds.h b/include/linux/leds.h
index f203a8f..11ec574 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -233,6 +233,7 @@ struct led_trigger {
 	const char	 *name;
 	void		(*activate)(struct led_classdev *led_cdev);
 	void		(*deactivate)(struct led_classdev *led_cdev);
+	void *data;
 
 	/* LEDs under control by this trigger (for simple triggers) */
 	rwlock_t	  leddev_list_lock;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 2abd791..94fee77 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/leds.h>
 
 #include <linux/atomic.h>
 
@@ -60,6 +61,7 @@
 #define PHY_HAS_INTERRUPT	0x00000001
 #define PHY_HAS_MAGICANEG	0x00000002
 #define PHY_IS_INTERNAL		0x00000004
+#define PHY_HAS_LED_CTRL	0x00000008
 #define MDIO_DEVICE_IS_PHY	0x80000000
 
 /* Interface Mode definitions */
@@ -424,6 +426,10 @@ struct phy_device {
 	u8 mdix;
 
 	void (*adjust_link)(struct net_device *dev);
+
+	struct led_trigger *phy_link, *phy_act;
+	char phy_link_name[32], phy_act_name[32];
+
 };
 #define to_phy_device(d) container_of(to_mdio_device(d), \
 				      struct phy_device, mdio)
-- 
2.4.3

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ