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_1...@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;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to