/*
 * Access PHYs integrated into the switch chip through the switch's MDIO
 * control register.
 */
int
arswitch_readphy_internal(device_t dev, int phy, int reg)
{
	struct arswitch_softc *sc;
	uint32_t data = 0, ctrl;
	int err, timeout;
	uint32_t a;

	sc = device_get_softc(dev);
	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);

	if (phy < 0 || phy >= 32)
		return (ENXIO);
	if (reg < 0 || reg >= 32)
		return (ENXIO);

	if (AR8X16_IS_SWITCH(sc, AR8327))
		a = AR8327_REG_MDIO_CTRL;
	else
		a = AR8X16_REG_MDIO_CTRL;

	ARSWITCH_LOCK(sc);
	err = arswitch_writereg_msb(dev, a,
	    AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN |
	    AR8X16_MDIO_CTRL_CMD_READ |
	    (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) |
	    (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT));
	DEVERR(dev, err, "arswitch_readphy()=%d: phy=%d.%02x\n", phy, reg);
	if (err != 0)
		goto fail;
	for (timeout = 100; timeout--; ) {
		ctrl = arswitch_readreg_msb(dev, a);
		if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0)
			break;
	}
	if (timeout < 0) {
		DPRINTF(sc, ARSWITCH_DBG_ANY,
		    "arswitch_readphy(): phy=%d.%02x; timeout=%d\n",
		    phy, reg, timeout);
		goto fail;
	}
	data = arswitch_readreg_lsb(dev, a) &
	    AR8X16_MDIO_CTRL_DATA_MASK;
	ARSWITCH_UNLOCK(sc);

	DPRINTF(sc, ARSWITCH_DBG_PHYIO,
	    "%s: phy=0x%08x, reg=0x%08x, ret=0x%08x\n",
	    __func__, phy, reg, data);

	return (data);

fail:
	ARSWITCH_UNLOCK(sc);

	DPRINTF(sc, ARSWITCH_DBG_PHYIO,
	    "%s: phy=0x%08x, reg=0x%08x, fail; err=%d\n",
	    __func__, phy, reg, err);

	return (-1);
}
Beispiel #2
0
int
arswitch_writephy(device_t dev, int phy, int reg, int data)
{
	struct arswitch_softc *sc;
	uint32_t ctrl;
	int err, timeout;

	sc = device_get_softc(dev);
	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);

	if (reg < 0 || reg >= 32)
		return (ENXIO);

	ARSWITCH_LOCK(sc);
	err = arswitch_writereg(dev, AR8X16_REG_MDIO_CTRL,
	    AR8X16_MDIO_CTRL_BUSY |
	    AR8X16_MDIO_CTRL_MASTER_EN |
	    AR8X16_MDIO_CTRL_CMD_WRITE |
	    (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) |
	    (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT) |
	    (data & AR8X16_MDIO_CTRL_DATA_MASK));
	if (err != 0)
		goto out;
	for (timeout = 100; timeout--; ) {
		ctrl = arswitch_readreg(dev, AR8X16_REG_MDIO_CTRL);
		if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0)
			break;
	}
	if (timeout < 0)
		err = EIO;
out:
	DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg);
	ARSWITCH_UNLOCK(sc);
	return (err);
}
int
arswitch_writephy_external(device_t dev, int phy, int reg, int data)
{
	struct arswitch_softc *sc;

	sc = device_get_softc(dev);

	ARSWITCH_LOCK(sc);
	(void) MDIO_WRITEREG(device_get_parent(dev), phy,
	    reg, data);
	DPRINTF(sc, ARSWITCH_DBG_PHYIO,
	    "%s: phy=0x%08x, reg=0x%08x, data=0x%08x\n",
	    __func__, phy, reg, data);
	ARSWITCH_UNLOCK(sc);

	return (0);
}
/*
 * Access PHYs integrated into the switch by going direct
 * to the PHY space itself, rather than through the switch
 * MDIO register.
 */
int
arswitch_readphy_external(device_t dev, int phy, int reg)
{
	int ret;
	struct arswitch_softc *sc;

	sc = device_get_softc(dev);

	ARSWITCH_LOCK(sc);
	ret = (MDIO_READREG(device_get_parent(dev), phy, reg));
	DPRINTF(sc, ARSWITCH_DBG_PHYIO,
	    "%s: phy=0x%08x, reg=0x%08x, ret=0x%08x\n",
	    __func__, phy, reg, ret);
	ARSWITCH_UNLOCK(sc);

	return (ret);
}
int
arswitch_writephy_internal(device_t dev, int phy, int reg, int data)
{
	struct arswitch_softc *sc;
	uint32_t ctrl;
	int err, timeout;
	uint32_t a;

	sc = device_get_softc(dev);
	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);

	if (reg < 0 || reg >= 32)
		return (ENXIO);

	if (AR8X16_IS_SWITCH(sc, AR8327))
		a = AR8327_REG_MDIO_CTRL;
	else
		a = AR8X16_REG_MDIO_CTRL;

	ARSWITCH_LOCK(sc);
	err = arswitch_writereg(dev, a,
	    AR8X16_MDIO_CTRL_BUSY |
	    AR8X16_MDIO_CTRL_MASTER_EN |
	    AR8X16_MDIO_CTRL_CMD_WRITE |
	    (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) |
	    (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT) |
	    (data & AR8X16_MDIO_CTRL_DATA_MASK));
	if (err != 0)
		goto out;
	for (timeout = 100; timeout--; ) {
		ctrl = arswitch_readreg(dev, a);
		if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0)
			break;
	}
	if (timeout < 0)
		err = EIO;

	DPRINTF(sc, ARSWITCH_DBG_PHYIO,
	    "%s: phy=0x%08x, reg=0x%08x, data=0x%08x, err=%d\n",
	    __func__, phy, reg, data, err);

out:
	DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg);
	ARSWITCH_UNLOCK(sc);
	return (err);
}
Beispiel #6
0
/*
 * Get the port VLAN configuration.
 */
static int
ar8327_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p)
{

	ARSWITCH_LOCK(sc);

	/* Retrieve the PVID */
	sc->hal.arswitch_vlan_get_pvid(sc, p->es_port, &p->es_pvid);

	/* Retrieve the current port configuration from the VTU */
	/*
	 * DOUBLE_TAG
	 * VLAN_MODE_ADD
	 * VLAN_MODE_STRIP
	 */

	ARSWITCH_UNLOCK(sc);
	return (0);
}
Beispiel #7
0
static int
ar8327_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p)
{

	/* Check: ADDTAG/STRIPTAG - exclusive */

	ARSWITCH_LOCK(sc);

	/* Set the PVID. */
	if (p->es_pvid != 0)
		sc->hal.arswitch_vlan_set_pvid(sc, p->es_port, p->es_pvid);

	/*
	 * DOUBLE_TAG
	 * VLAN_MODE_ADD
	 * VLAN_MODE_STRIP
	 */
	ARSWITCH_UNLOCK(sc);
	return (0);
}
Beispiel #8
0
/*
 * access PHYs integrated into the switch chip through the switch's MDIO
 * control register.
 */
int
arswitch_readphy(device_t dev, int phy, int reg)
{
	struct arswitch_softc *sc;
	uint32_t data = 0, ctrl;
	int err, timeout;

	sc = device_get_softc(dev);
	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);

	if (phy < 0 || phy >= 32)
		return (ENXIO);
	if (reg < 0 || reg >= 32)
		return (ENXIO);

	ARSWITCH_LOCK(sc);
	err = arswitch_writereg_msb(dev, AR8X16_REG_MDIO_CTRL,
	    AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN |
	    AR8X16_MDIO_CTRL_CMD_READ |
	    (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) |
	    (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT));
	DEVERR(dev, err, "arswitch_readphy()=%d: phy=%d.%02x\n", phy, reg);
	if (err != 0)
		goto fail;
	for (timeout = 100; timeout--; ) {
		ctrl = arswitch_readreg_msb(dev, AR8X16_REG_MDIO_CTRL);
		if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0)
			break;
	}
	if (timeout < 0)
		goto fail;
	data = arswitch_readreg_lsb(dev, AR8X16_REG_MDIO_CTRL) &
	    AR8X16_MDIO_CTRL_DATA_MASK;
	ARSWITCH_UNLOCK(sc);
	return (data);

fail:
	ARSWITCH_UNLOCK(sc);
	return (-1);
}
Beispiel #9
0
static void
ar8327_reset_vlans(struct arswitch_softc *sc)
{
	int i;
	uint32_t t;
	int ports;

	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
	ARSWITCH_LOCK(sc);

	/* Clear the existing VLAN configuration */
	memset(sc->vid, 0, sizeof(sc->vid));

	/*
	 * Disable mirroring.
	 */
	arswitch_modifyreg(sc->sc_dev, AR8327_REG_FWD_CTRL0,
	    AR8327_FWD_CTRL0_MIRROR_PORT,
	    (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S));

	/*
	 * XXX TODO: disable any Q-in-Q port configuration,
	 * tagging, egress filters, etc.
	 */

	/*
	 * For now, let's default to one portgroup, just so traffic
	 * flows.  All ports can see other ports. There are two CPU GMACs
	 * (GMAC0, GMAC6), GMAC1..GMAC5 are external PHYs.
	 *
	 * (ETHERSWITCH_VLAN_PORT)
	 */
	ports = 0x7f;

	/*
	 * XXX TODO: set things up correctly for vlans!
	 */
	for (i = 0; i < AR8327_NUM_PORTS; i++) {
		int egress, ingress;

		if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
			sc->vid[i] = i | ETHERSWITCH_VID_VALID;
			/* set egress == out_keep */
			ingress = AR8X16_PORT_VLAN_MODE_PORT_ONLY;
			/* in_port_only, forward */
			egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH;
		} else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
			ingress = AR8X16_PORT_VLAN_MODE_SECURE;
			egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD;
		} else {
			/* set egress == out_keep */
			ingress = AR8X16_PORT_VLAN_MODE_PORT_ONLY;
			/* in_port_only, forward */
			egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH;
		}

		/* set pvid = 1; there's only one vlangroup to start with */
		t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
		t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
		arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(i), t);

		t = AR8327_PORT_VLAN1_PORT_VLAN_PROP;
		t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S;
		arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(i), t);

		/* Ports can see other ports */
		/* XXX not entirely true for dot1q? */
		t = (ports & ~(1 << i));	/* all ports besides us */
		t |= AR8327_PORT_LOOKUP_LEARN;

		t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S;
		t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
		arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(i), t);
	}

	/*
	 * Disable port mirroring entirely.
	 */
	for (i = 0; i < AR8327_NUM_PORTS; i++) {
		ar8327_port_disable_mirror(sc, i);
	}

	/*
	 * If dot1q - set pvid; dot1q, etc.
	 */
	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
		sc->vid[0] = 1;
		for (i = 0; i < AR8327_NUM_PORTS; i++) {
			/* Each port - pvid 1 */
			sc->hal.arswitch_vlan_set_pvid(sc, i, sc->vid[0]);
		}
		/* Initialise vlan1 - all ports, untagged */
		sc->hal.arswitch_set_dot1q_vlan(sc, ports, ports, sc->vid[0]);
		sc->vid[0] |= ETHERSWITCH_VID_VALID;
	}

	ARSWITCH_UNLOCK(sc);
}