svn commit: r303751 - in head/sys/dev/etherswitch: . arswitch

Adrian Chadd adrian at FreeBSD.org
Thu Aug 4 17:45:37 UTC 2016


Author: adrian
Date: Thu Aug  4 17:45:35 2016
New Revision: 303751
URL: https://svnweb.freebsd.org/changeset/base/303751

Log:
  [etherswitch] add in an initial API for controlling per-port LED behaviour.
  
  This is just implemented for the AR8327 for now.
  
  Submitted by:	Dan Nelson <dnelson_1901 at yahoo.com>

Modified:
  head/sys/dev/etherswitch/arswitch/arswitch.c
  head/sys/dev/etherswitch/arswitch/arswitch_8327.c
  head/sys/dev/etherswitch/arswitch/arswitch_8327.h
  head/sys/dev/etherswitch/arswitch/arswitchvar.h
  head/sys/dev/etherswitch/etherswitch.h

Modified: head/sys/dev/etherswitch/arswitch/arswitch.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch.c	Thu Aug  4 17:29:42 2016	(r303750)
+++ head/sys/dev/etherswitch/arswitch/arswitch.c	Thu Aug  4 17:45:35 2016	(r303751)
@@ -77,6 +77,14 @@
 static SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch");
 #endif
 
+/* Map ETHERSWITCH_PORT_LED_* to Atheros pattern codes */
+static int led_pattern_table[] = {
+	[ETHERSWITCH_PORT_LED_DEFAULT] = 0x3,
+	[ETHERSWITCH_PORT_LED_ON] = 0x2,
+	[ETHERSWITCH_PORT_LED_OFF] = 0x0,
+	[ETHERSWITCH_PORT_LED_BLINK] = 0x1
+};
+
 static inline int arswitch_portforphy(int phy);
 static void arswitch_tick(void *arg);
 static int arswitch_ifmedia_upd(struct ifnet *);
@@ -85,6 +93,8 @@ static int ar8xxx_port_vlan_setup(struct
     etherswitch_port_t *p);
 static int ar8xxx_port_vlan_get(struct arswitch_softc *sc,
     etherswitch_port_t *p);
+static int arswitch_setled(struct arswitch_softc *sc, int phy, int led,
+    int style);
 
 static int
 arswitch_probe(device_t dev)
@@ -188,9 +198,23 @@ arswitch_attach_phys(struct arswitch_sof
 			device_printf(sc->sc_dev,
 			    "attaching PHY %d failed\n",
 			    phy);
+			return (err);
+		}
+
+		if (AR8X16_IS_SWITCH(sc, AR8327)) {
+			int led;
+			char ledname[IFNAMSIZ+4];
+
+			for (led = 0; led < 3; led++) {
+				sprintf(ledname, "%s%dled%d", name,
+				    arswitch_portforphy(phy), led+1);
+				sc->dev_led[phy][led].sc = sc;
+				sc->dev_led[phy][led].phy = phy;
+				sc->dev_led[phy][led].lednum = led;
+			}
 		}
 	}
-	return (err);
+	return (0);
 }
 
 static int
@@ -683,6 +707,38 @@ arswitch_getport(device_t dev, etherswit
 	} else {
 		return (ENXIO);
 	}
+	
+	if (!arswitch_is_cpuport(sc, p->es_port) &&
+	    AR8X16_IS_SWITCH(sc, AR8327)) {
+		int led;
+		p->es_nleds = 3;
+
+		for (led = 0; led < p->es_nleds; led++)
+		{
+			int style;
+			uint32_t val;
+			
+			/* Find the right style enum for our pattern */
+			val = arswitch_readreg(dev,
+			    ar8327_led_mapping[p->es_port-1][led].reg);
+			val = (val>>ar8327_led_mapping[p->es_port-1][led].shift)&0x03;
+
+			for (style = 0; style < ETHERSWITCH_PORT_LED_MAX; style++)
+			{
+				if (led_pattern_table[style] == val) break;
+			}
+			
+			/* can't happen */
+			if (style == ETHERSWITCH_PORT_LED_MAX)
+				style = ETHERSWITCH_PORT_LED_DEFAULT;
+			
+			p->es_led[led] = style;
+		}
+	} else
+	{
+		p->es_nleds = 0;
+	}
+	
 	return (0);
 }
 
@@ -727,7 +783,7 @@ ar8xxx_port_vlan_setup(struct arswitch_s
 static int
 arswitch_setport(device_t dev, etherswitch_port_t *p)
 {
-	int err;
+	int err, i;
 	struct arswitch_softc *sc;
 	struct ifmedia *ifm;
 	struct mii_data *mii;
@@ -744,9 +800,20 @@ arswitch_setport(device_t dev, etherswit
 			return (err);
 	}
 
-	/* Do not allow media changes on CPU port. */
+	/* Do not allow media or led changes on CPU port. */
 	if (arswitch_is_cpuport(sc, p->es_port))
 		return (0);
+	
+	if (AR8X16_IS_SWITCH(sc, AR8327))
+	{
+		for (i = 0; i < 3; i++)
+		{	
+			int err;
+			err = arswitch_setled(sc, p->es_port-1, i, p->es_led[i]);
+			if (err)
+				return (err);
+		}
+	}
 
 	mii = arswitch_miiforport(sc, p->es_port);
 	if (mii == NULL)
@@ -758,6 +825,23 @@ arswitch_setport(device_t dev, etherswit
 	return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA));
 }
 
+static int
+arswitch_setled(struct arswitch_softc *sc, int phy, int led, int style)
+{
+	int shift;
+
+	if (phy < 0 || phy > sc->numphys)
+		return EINVAL;
+
+	if (style < 0 || style > ETHERSWITCH_PORT_LED_MAX)
+		return (EINVAL);
+
+	shift = ar8327_led_mapping[phy][led].shift;
+	return (arswitch_modifyreg(sc->sc_dev,
+	    ar8327_led_mapping[phy][led].reg,
+	    0x03 << shift, led_pattern_table[style] << shift));
+}
+
 static void
 arswitch_statchg(device_t dev)
 {

Modified: head/sys/dev/etherswitch/arswitch/arswitch_8327.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_8327.c	Thu Aug  4 17:29:42 2016	(r303750)
+++ head/sys/dev/etherswitch/arswitch/arswitch_8327.c	Thu Aug  4 17:45:35 2016	(r303751)
@@ -75,6 +75,36 @@
  * lead to traffic storms/loops.
  */
 
+/* Map port+led to register+shift */
+struct ar8327_led_mapping ar8327_led_mapping[AR8327_NUM_PHYS][ETHERSWITCH_PORT_MAX_LEDS] =
+{
+	{	/* PHY0 */
+		{AR8327_REG_LED_CTRL0, 14 },
+		{AR8327_REG_LED_CTRL1, 14 },
+		{AR8327_REG_LED_CTRL2, 14 }
+	},
+	{	/* PHY1 */
+		{AR8327_REG_LED_CTRL3, 8  },
+		{AR8327_REG_LED_CTRL3, 10 },
+		{AR8327_REG_LED_CTRL3, 12 }
+	},
+	{	/* PHY2 */
+		{AR8327_REG_LED_CTRL3, 14 },
+		{AR8327_REG_LED_CTRL3, 16 },
+		{AR8327_REG_LED_CTRL3, 18 }
+	},
+	{	/* PHY3 */
+		{AR8327_REG_LED_CTRL3, 20 },
+		{AR8327_REG_LED_CTRL3, 22 },
+		{AR8327_REG_LED_CTRL3, 24 }
+	},
+	{	/* PHY4 */
+		{AR8327_REG_LED_CTRL0, 30 },
+		{AR8327_REG_LED_CTRL1, 30 },
+		{AR8327_REG_LED_CTRL2, 30 }
+	}
+};
+
 static int
 ar8327_vlan_op(struct arswitch_softc *sc, uint32_t op, uint32_t vid,
     uint32_t data)

Modified: head/sys/dev/etherswitch/arswitch/arswitch_8327.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_8327.h	Thu Aug  4 17:29:42 2016	(r303750)
+++ head/sys/dev/etherswitch/arswitch/arswitch_8327.h	Thu Aug  4 17:45:35 2016	(r303751)
@@ -85,6 +85,11 @@ struct ar8327_port_cfg {
 	uint32_t rxpause;
 };
 
+extern struct ar8327_led_mapping {
+	int reg;
+	int shift;
+} ar8327_led_mapping[AR8327_NUM_PHYS][ETHERSWITCH_PORT_MAX_LEDS];
+
 extern	void ar8327_attach(struct arswitch_softc *sc);
 
 #endif	/* __ARSWITCH_8327_H__ */

Modified: head/sys/dev/etherswitch/arswitch/arswitchvar.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitchvar.h	Thu Aug  4 17:29:42 2016	(r303750)
+++ head/sys/dev/etherswitch/arswitch/arswitchvar.h	Thu Aug  4 17:45:35 2016	(r303751)
@@ -48,6 +48,15 @@ typedef enum {
 #define ARSWITCH_NUM_PORTS	MAX(AR8327_NUM_PORTS, AR8X16_NUM_PORTS)
 #define ARSWITCH_NUM_PHYS	MAX(AR8327_NUM_PHYS, AR8X16_NUM_PHYS)
 
+#define ARSWITCH_NUM_LEDS	3
+
+struct arswitch_dev_led {
+	struct arswitch_softc	*sc;
+	struct cdev	*led;
+	int		phy;
+	int		lednum;
+};
+
 struct arswitch_softc {
 	struct mtx	sc_mtx;		/* serialize access to softc */
 	device_t	sc_dev;
@@ -66,6 +75,7 @@ struct arswitch_softc {
 	char		*ifname[ARSWITCH_NUM_PHYS];
 	device_t	miibus[ARSWITCH_NUM_PHYS];
 	struct ifnet	*ifp[ARSWITCH_NUM_PHYS];
+	struct arswitch_dev_led	dev_led[ARSWITCH_NUM_PHYS][ARSWITCH_NUM_LEDS];
 	struct callout	callout_tick;
 	etherswitch_info_t info;
 

Modified: head/sys/dev/etherswitch/etherswitch.h
==============================================================================
--- head/sys/dev/etherswitch/etherswitch.h	Thu Aug  4 17:29:42 2016	(r303750)
+++ head/sys/dev/etherswitch/etherswitch.h	Thu Aug  4 17:45:35 2016	(r303751)
@@ -14,7 +14,7 @@ extern driver_t         etherswitch_driv
 
 struct etherswitch_reg {
 	uint16_t	reg;
-	uint16_t	val;
+	uint32_t	val;
 };
 typedef struct etherswitch_reg etherswitch_reg_t;
 
@@ -64,10 +64,23 @@ typedef struct etherswitch_conf etherswi
 #define	ETHERSWITCH_PORT_FLAGS_BITS	\
 "\020\1CPUPORT\2STRIPTAG\3ADDTAG\4FIRSTLOCK\5DROPUNTAGGED\6QinQ\7INGRESS"
 
+#define ETHERSWITCH_PORT_MAX_LEDS 3
+
+enum etherswitch_port_led {
+	ETHERSWITCH_PORT_LED_DEFAULT,
+	ETHERSWITCH_PORT_LED_ON,
+	ETHERSWITCH_PORT_LED_OFF,
+	ETHERSWITCH_PORT_LED_BLINK,
+	ETHERSWITCH_PORT_LED_MAX
+};
+typedef enum etherswitch_port_led etherswitch_port_led_t;
+
 struct etherswitch_port {
 	int		es_port;
 	int		es_pvid;
+	int		es_nleds;
 	uint32_t	es_flags;
+	etherswitch_port_led_t es_led[ETHERSWITCH_PORT_MAX_LEDS];
 	union {
 		struct ifreq		es_uifr;
 		struct ifmediareq	es_uifmr;


More information about the svn-src-head mailing list