[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:
parent
aac2b24d84
commit
d57c6dcdab
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user