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