[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@yahoo.com>
This commit is contained in:
Adrian Chadd 2016-08-04 17:45:35 +00:00
parent 9217931fb4
commit c94dc8089f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=303751
5 changed files with 146 additions and 4 deletions

View File

@ -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 arswitch_softc *sc,
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_softc *sc)
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, etherswitch_port_t *p)
} 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_softc *sc, etherswitch_port_t *p)
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, etherswitch_port_t *p)
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, etherswitch_port_t *p)
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)
{

View File

@ -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)

View File

@ -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__ */

View File

@ -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;

View File

@ -14,7 +14,7 @@ extern driver_t etherswitch_driver;
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 etherswitch_conf_t;
#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;