svn commit: r279767 - head/sys/dev/etherswitch/arswitch

Adrian Chadd adrian at FreeBSD.org
Sun Mar 8 03:53:39 UTC 2015


Author: adrian
Date: Sun Mar  8 03:53:36 2015
New Revision: 279767
URL: https://svnweb.freebsd.org/changeset/base/279767

Log:
  Fix up support for the AR8327.
  
  * Even though I got the registers around "right", it seems
    I'm not tickling the MDIO access correctly for the internal PHY
    bus.  Some of the switches are fine poking at the external PHY
    registers; others aren't.  So, enable direct PHY bus access
    for the AR8327, and leave the existing code in place for the
    others.
  
  * Go and shuffle the register access around.  Whilst here,
    restore the 2ms delay if changing page.
  
  * Comment out some of the stub printf()s; there's some upcoming
    work to add port VLAN support.
  
  Tested:
  
  * AP135 development board
  * Carambola2 - AR9331 SoC

Modified:
  head/sys/dev/etherswitch/arswitch/arswitch.c
  head/sys/dev/etherswitch/arswitch/arswitch_8327.c
  head/sys/dev/etherswitch/arswitch/arswitch_phy.c
  head/sys/dev/etherswitch/arswitch/arswitch_phy.h
  head/sys/dev/etherswitch/arswitch/arswitch_reg.c
  head/sys/dev/etherswitch/arswitch/arswitchvar.h

Modified: head/sys/dev/etherswitch/arswitch/arswitch.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch.c	Sun Mar  8 03:34:06 2015	(r279766)
+++ head/sys/dev/etherswitch/arswitch/arswitch.c	Sun Mar  8 03:53:36 2015	(r279767)
@@ -149,8 +149,10 @@ done:
 	DPRINTF(dev, "chipname=%s, id=%08x\n", chipname, id);
 	if (chipname != NULL) {
 		snprintf(desc, sizeof(desc),
-		    "Atheros %s Ethernet Switch",
-		    chipname);
+		    "Atheros %s Ethernet Switch (ver %d rev %d)",
+		    chipname,
+		    sc->chip_ver,
+		    sc->chip_rev);
 		device_set_desc_copy(dev, desc);
 		return (BUS_PROBE_DEFAULT);
 	}
@@ -177,9 +179,11 @@ arswitch_attach_phys(struct arswitch_sof
 		err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy],
 		    arswitch_ifmedia_upd, arswitch_ifmedia_sts, \
 		    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
+#if 0
 		DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
 		    device_get_nameunit(sc->miibus[phy]),
 		    sc->ifp[phy]->if_xname);
+#endif
 		if (err != 0) {
 			device_printf(sc->sc_dev,
 			    "attaching PHY %d failed\n",
@@ -304,6 +308,8 @@ arswitch_attach(device_t dev)
 	sc->hal.arswitch_vlan_get_pvid = ar8xxx_get_pvid;
 	sc->hal.arswitch_vlan_set_pvid = ar8xxx_set_pvid;
 	sc->hal.arswitch_atu_flush = ar8xxx_atu_flush;
+	sc->hal.arswitch_phy_read = arswitch_readphy_internal;
+	sc->hal.arswitch_phy_write = arswitch_writephy_internal;
 
 	/*
 	 * Attach switch related functions
@@ -320,8 +326,10 @@ arswitch_attach(device_t dev)
 		ar8316_attach(sc);
 	else if (AR8X16_IS_SWITCH(sc, AR8327))
 		ar8327_attach(sc);
-	else
+	else {
+		DPRINTF(dev, "%s: unknown switch (%d)?\n", __func__, sc->sc_switchtype);
 		return (ENXIO);
+	}
 
 	/* Common defaults. */
 	sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */
@@ -348,14 +356,18 @@ arswitch_attach(device_t dev)
 		sc->numphys = AR8X16_NUM_PHYS;
 
 	/* Reset the switch. */
-	if (arswitch_reset(dev))
+	if (arswitch_reset(dev)) {
+		DPRINTF(dev, "%s: arswitch_reset: failed\n", __func__);
 		return (ENXIO);
+	}
 
 	err = sc->hal.arswitch_hw_setup(sc);
+	DPRINTF(dev, "%s: hw_setup: err=%d\n", __func__, err);
 	if (err != 0)
 		return (err);
 
 	err = sc->hal.arswitch_hw_global_setup(sc);
+	DPRINTF(dev, "%s: hw_global_setup: err=%d\n", __func__, err);
 	if (err != 0)
 		return (err);
 
@@ -368,17 +380,20 @@ arswitch_attach(device_t dev)
 	 * Attach the PHYs and complete the bus enumeration.
 	 */
 	err = arswitch_attach_phys(sc);
+	DPRINTF(dev, "%s: attach_phys: err=%d\n", __func__, err);
 	if (err != 0)
 		return (err);
 
 	/* Default to ingress filters off. */
 	err = arswitch_set_vlan_mode(sc, 0);
+	DPRINTF(dev, "%s: set_vlan_mode: err=%d\n", __func__, err);
 	if (err != 0)
 		return (err);
 
 	bus_generic_probe(dev);
 	bus_enumerate_hinted_children(dev);
 	err = bus_generic_attach(dev);
+	DPRINTF(dev, "%s: bus_generic_attach: err=%d\n", __func__, err);
 	if (err != 0)
 		return (err);
 	
@@ -803,6 +818,22 @@ arswitch_setvgroup(device_t dev, ethersw
 	return (sc->hal.arswitch_vlan_setvgroup(sc, e));
 }
 
+static int
+arswitch_readphy(device_t dev, int phy, int reg)
+{
+	struct arswitch_softc *sc = device_get_softc(dev);
+
+	return (sc->hal.arswitch_phy_read(dev, phy, reg));
+}
+
+static int
+arswitch_writephy(device_t dev, int phy, int reg, int val)
+{
+	struct arswitch_softc *sc = device_get_softc(dev);
+
+	return (sc->hal.arswitch_phy_write(dev, phy, reg, val));
+}
+
 static device_method_t arswitch_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		arswitch_probe),

Modified: head/sys/dev/etherswitch/arswitch/arswitch_8327.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_8327.c	Sun Mar  8 03:34:06 2015	(r279766)
+++ head/sys/dev/etherswitch/arswitch/arswitch_8327.c	Sun Mar  8 03:53:36 2015	(r279767)
@@ -57,6 +57,9 @@
 #include <dev/etherswitch/arswitch/arswitchreg.h>
 #include <dev/etherswitch/arswitch/arswitchvar.h>
 #include <dev/etherswitch/arswitch/arswitch_reg.h>
+#include <dev/etherswitch/arswitch/arswitch_phy.h>
+#include <dev/etherswitch/arswitch/arswitch_vlans.h>
+
 #include <dev/etherswitch/arswitch/arswitch_8327.h>
 
 #include "mdio_if.h"
@@ -290,7 +293,7 @@ ar8327_fetch_pdata_port(struct arswitch_
 	    sbuf, &val) == 0)
 		pcfg->rxpause = val;
 
-#if 0
+#if 1
 	device_printf(sc->sc_dev,
 	    "%s: port %d: speed=%d, duplex=%d, txpause=%d, rxpause=%d\n",
 	    __func__,
@@ -562,6 +565,7 @@ ar8327_init_pdata(struct arswitch_softc 
 	/* SGMII config */
 	bzero(&scfg, sizeof(scfg));
 	if (ar8327_fetch_pdata_sgmii(sc, &scfg)) {
+		device_printf(sc->sc_dev, "%s: SGMII cfg?\n", __func__);
 		t = scfg.sgmii_ctrl;
 		if (sc->chip_rev == 1)
 			t |= AR8327_SGMII_CTRL_EN_PLL |
@@ -657,12 +661,16 @@ ar8327_hw_global_setup(struct arswitch_s
 }
 
 /*
- * Port setup.
+ * Port setup.  Called at attach time.
  */
 static void
 ar8327_port_init(struct arswitch_softc *sc, int port)
 {
 	uint32_t t;
+	int ports;
+
+	/* For now, port can see all other ports */
+	ports = 0x7f;
 
 	if (port == AR8X16_PORT_CPU)
 		t = sc->ar8327.port0_status;
@@ -696,7 +704,7 @@ ar8327_port_init(struct arswitch_softc *
 	t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
 
 	/* So this allows traffic to any port except ourselves */
-	t |= (0x7f & ~(1 << port));
+	t |= (ports & ~(1 << port));
 	arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port), t);
 }
 
@@ -705,16 +713,18 @@ ar8327_port_vlan_setup(struct arswitch_s
 {
 
 	/* XXX stub for now */
-	device_printf(sc->sc_dev, "%s: called\n", __func__);
+//	device_printf(sc->sc_dev, "%s: called\n", __func__);
 	return (0);
 }
 
+/*
+ * Get the port VLAN configuration.
+ */
 static int
 ar8327_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p)
 {
-
 	/* XXX stub for now */
-	device_printf(sc->sc_dev, "%s: called\n", __func__);
+//	device_printf(sc->sc_dev, "%s: called\n", __func__);
 	return (0);
 }
 
@@ -723,6 +733,13 @@ ar8327_reset_vlans(struct arswitch_softc
 {
 	int i;
 	uint32_t mode, 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.
@@ -732,10 +749,21 @@ ar8327_reset_vlans(struct arswitch_softc
 	    (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.
+	 * flows.  All ports can see other ports. There are two CPU GMACs
+	 * (GMAC0, GMAC6), GMAC1..GMAC5 are external PHYs.
+	 *
+	 * (ETHERSWITCH_VLAN_PORT)
 	 */
+	ports = 0x7f;
+
 	for (i = 0; i < AR8327_NUM_PORTS; i++) {
+
 		/* set pvid = 1; there's only one vlangroup */
 		t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
 		t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
@@ -749,7 +777,7 @@ ar8327_reset_vlans(struct arswitch_softc
 		arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(i), t);
 
 		/* Ports can see other ports */
-		t = (0x7f & ~(1 << i));	/* all ports besides us */
+		t = (ports & ~(1 << i));	/* all ports besides us */
 		t |= AR8327_PORT_LOOKUP_LEARN;
 
 		/* in_port_only, forward */
@@ -769,12 +797,20 @@ ar8327_reset_vlans(struct arswitch_softc
 		    AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN,
 		    0);
 	}
+
+	ARSWITCH_UNLOCK(sc);
 }
 
 static int
 ar8327_vlan_getvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg)
 {
-	device_printf(sc->sc_dev, "%s: called\n", __func__);
+
+#if 0
+	/* XXX for now, no dot1q vlans */
+	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
+		return (EINVAL);
+	return (ar8xxx_getvgroup(sc, vg));
+#endif
 	return (0);
 }
 
@@ -782,7 +818,12 @@ static int
 ar8327_vlan_setvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg)
 {
 
-	device_printf(sc->sc_dev, "%s: called\n", __func__);
+#if 0
+	/* XXX for now, no dot1q vlans */
+	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
+		return (EINVAL);
+	return (ar8xxx_setvgroup(sc, vg));
+#endif
 	return (0);
 }
 
@@ -832,17 +873,29 @@ ar8327_attach(struct arswitch_softc *sc)
 	sc->hal.arswitch_hw_global_setup = ar8327_hw_global_setup;
 
 	sc->hal.arswitch_port_init = ar8327_port_init;
+
+	sc->hal.arswitch_vlan_getvgroup = ar8327_vlan_getvgroup;
+	sc->hal.arswitch_vlan_setvgroup = ar8327_vlan_setvgroup;
 	sc->hal.arswitch_port_vlan_setup = ar8327_port_vlan_setup;
 	sc->hal.arswitch_port_vlan_get = ar8327_port_vlan_get;
 
 	sc->hal.arswitch_vlan_init_hw = ar8327_reset_vlans;
-	sc->hal.arswitch_vlan_getvgroup = ar8327_vlan_getvgroup;
-	sc->hal.arswitch_vlan_setvgroup = ar8327_vlan_setvgroup;
 	sc->hal.arswitch_vlan_get_pvid = ar8327_get_pvid;
 	sc->hal.arswitch_vlan_set_pvid = ar8327_set_pvid;
 
 	sc->hal.arswitch_atu_flush = ar8327_atu_flush;
 
+	/*
+	 * Reading the PHY via the MDIO interface currently doesn't
+	 * work correctly.
+	 *
+	 * So for now, just go direct to the PHY registers themselves.
+	 * This has always worked  on external devices, but not internal
+	 * devices (AR934x, AR724x, AR933x.)
+	 */
+	sc->hal.arswitch_phy_read = arswitch_readphy_external;
+	sc->hal.arswitch_phy_write = arswitch_writephy_external;
+
 	/* Set the switch vlan capabilities. */
 	sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q |
 	    ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOUBLE_TAG;

Modified: head/sys/dev/etherswitch/arswitch/arswitch_phy.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_phy.c	Sun Mar  8 03:34:06 2015	(r279766)
+++ head/sys/dev/etherswitch/arswitch/arswitch_phy.c	Sun Mar  8 03:53:36 2015	(r279767)
@@ -67,11 +67,46 @@ static SYSCTL_NODE(_debug, OID_AUTO, ars
 #endif
 
 /*
- * access PHYs integrated into the switch chip through the switch's MDIO
+ * 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));
+	ARSWITCH_UNLOCK(sc);
+
+	return (ret);
+}
+
+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);
+	ARSWITCH_UNLOCK(sc);
+
+	return (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)
+arswitch_readphy_internal(device_t dev, int phy, int reg)
 {
 	struct arswitch_softc *sc;
 	uint32_t data = 0, ctrl;
@@ -105,8 +140,10 @@ arswitch_readphy(device_t dev, int phy, 
 		if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0)
 			break;
 	}
-	if (timeout < 0)
+	if (timeout < 0) {
+		DPRINTF(dev, "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);
@@ -118,7 +155,7 @@ fail:
 }
 
 int
-arswitch_writephy(device_t dev, int phy, int reg, int data)
+arswitch_writephy_internal(device_t dev, int phy, int reg, int data)
 {
 	struct arswitch_softc *sc;
 	uint32_t ctrl;

Modified: head/sys/dev/etherswitch/arswitch/arswitch_phy.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_phy.h	Sun Mar  8 03:34:06 2015	(r279766)
+++ head/sys/dev/etherswitch/arswitch/arswitch_phy.h	Sun Mar  8 03:53:36 2015	(r279767)
@@ -28,7 +28,10 @@
 #ifndef	__ARSWITCH_PHY_H__
 #define	__ARSWITCH_PHY_H__
 
-extern	int arswitch_readphy(device_t dev, int phy, int reg);
-extern	int arswitch_writephy(device_t dev, int phy, int reg, int data);
+extern	int arswitch_readphy_external(device_t dev, int phy, int reg);
+extern	int arswitch_writephy_external(device_t dev, int phy, int reg, int data);
+
+extern	int arswitch_readphy_internal(device_t dev, int phy, int reg);
+extern	int arswitch_writephy_internal(device_t dev, int phy, int reg, int data);
 
 #endif	/* __ARSWITCH_PHY_H__ */

Modified: head/sys/dev/etherswitch/arswitch/arswitch_reg.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_reg.c	Sun Mar  8 03:34:06 2015	(r279766)
+++ head/sys/dev/etherswitch/arswitch/arswitch_reg.c	Sun Mar  8 03:53:36 2015	(r279767)
@@ -68,12 +68,13 @@ arswitch_split_setpage(device_t dev, uin
 	struct arswitch_softc *sc = device_get_softc(dev);
 	uint16_t page;
 
-	page = ((addr) >> 9) & 0xffff;
-	*phy = (((addr) >> 6) & 0x07) | 0x10;
-	*reg = ((addr) >> 1) & 0x1f;
+	page = (addr >> 9) & 0x1ff;
+	*phy = (addr >> 6) & 0x7;
+	*reg = (addr >> 1) & 0x1f;
 
 	if (sc->page != page) {
 		MDIO_WRITEREG(device_get_parent(dev), 0x18, 0, page);
+		DELAY(2000);
 		sc->page = page;
 	}
 }
@@ -87,9 +88,21 @@ static inline int
 arswitch_readreg16(device_t dev, int addr)
 {
 	uint16_t phy, reg;
-	
+
 	arswitch_split_setpage(dev, addr, &phy, &reg);
-	return (MDIO_READREG(device_get_parent(dev), phy, reg));
+	return (MDIO_READREG(device_get_parent(dev), 0x10 | phy, reg));
+}
+
+/*
+ * Write half a register.  See above!
+ */
+static inline int
+arswitch_writereg16(device_t dev, int addr, int data)
+{
+	uint16_t phy, reg;
+
+	arswitch_split_setpage(dev, addr, &phy, &reg);
+	return (MDIO_WRITEREG(device_get_parent(dev), 0x10 | phy, reg, data));
 }
 
 /*
@@ -121,93 +134,123 @@ arswitch_writemmd(device_t dev, int phy,
 	    MII_ATH_MMD_DATA, dbg_data);
 }
 
-/*
- * Write half a register
- */
-static inline int
-arswitch_writereg16(device_t dev, int addr, int data)
+static uint32_t
+arswitch_reg_read32(device_t dev, int phy, int reg)
 {
-	uint16_t phy, reg;
-	
-	arswitch_split_setpage(dev, addr, &phy, &reg);
-	return (MDIO_WRITEREG(device_get_parent(dev), phy, reg, data));
+	uint16_t lo, hi;
+	lo = MDIO_READREG(device_get_parent(dev), phy, reg);
+	hi = MDIO_READREG(device_get_parent(dev), phy, reg + 1);
+
+	return (hi << 16) | lo;
 }
 
-int
-arswitch_readreg_lsb(device_t dev, int addr)
+static int
+arswitch_reg_write32(device_t dev, int phy, int reg, uint32_t value)
 {
+	struct arswitch_softc *sc;
+	int r;
+	uint16_t lo, hi;
 
-	return (arswitch_readreg16(dev, addr));
+	sc = device_get_softc(dev);
+	lo = value & 0xffff;
+	hi = (uint16_t) (value >> 16);
+
+	if (sc->mii_lo_first) {
+		r = MDIO_WRITEREG(device_get_parent(dev),
+		    phy, reg, lo);
+		r |= MDIO_WRITEREG(device_get_parent(dev),
+		    phy, reg + 1, hi);
+	} else {
+		r = MDIO_WRITEREG(device_get_parent(dev),
+		    phy, reg + 1, hi);
+		r |= MDIO_WRITEREG(device_get_parent(dev),
+		    phy, reg, lo);
+	}
+
+	return r;
 }
 
 int
-arswitch_readreg_msb(device_t dev, int addr)
+arswitch_readreg(device_t dev, int addr)
 {
+	uint16_t phy, reg;
 
-	return (arswitch_readreg16(dev, addr + 2) << 16);
+	arswitch_split_setpage(dev, addr, &phy, &reg);
+	return arswitch_reg_read32(dev, 0x10 | phy, reg);
 }
 
 int
-arswitch_writereg_lsb(device_t dev, int addr, int data)
+arswitch_writereg(device_t dev, int addr, int value)
 {
+	struct arswitch_softc *sc;
+	uint16_t phy, reg;
 
-	return (arswitch_writereg16(dev, addr, data & 0xffff));
+	sc = device_get_softc(dev);
+
+	arswitch_split_setpage(dev, addr, &phy, &reg);
+	return (arswitch_reg_write32(dev, 0x10 | phy, reg, value));
 }
 
+/*
+ * Read/write 16 bit values in the switch register space.
+ *
+ * Some of the registers are control registers (eg the MDIO
+ * data versus control space) and so need to be treated
+ * differently.
+ */
 int
-arswitch_writereg_msb(device_t dev, int addr, int data)
+arswitch_readreg_lsb(device_t dev, int addr)
 {
 
-	return (arswitch_writereg16(dev, addr + 2, (data >> 16) & 0xffff));
+	return (arswitch_readreg16(dev, addr));
 }
 
 int
-arswitch_readreg(device_t dev, int addr)
+arswitch_readreg_msb(device_t dev, int addr)
 {
 
-	return (arswitch_readreg_lsb(dev, addr) |
-	    arswitch_readreg_msb(dev, addr));
+	return (arswitch_readreg16(dev, addr + 2) << 16);
 }
 
 int
-arswitch_writereg(device_t dev, int addr, int value)
+arswitch_writereg_lsb(device_t dev, int addr, int data)
 {
-	struct arswitch_softc *sc;
-	int r;
 
-	sc = device_get_softc(dev);
+	return (arswitch_writereg16(dev, addr, data & 0xffff));
+}
 
-	/* XXX Check the first write too? */
-	if (sc->mii_lo_first) {
-		r = arswitch_writereg_lsb(dev, addr, value);
-		r |= arswitch_writereg_msb(dev, addr, value);
-	} else {
-		r = arswitch_writereg_msb(dev, addr, value);
-		r |= arswitch_writereg_lsb(dev, addr, value);
-	}
+int
+arswitch_writereg_msb(device_t dev, int addr, int data)
+{
 
-	return r;
+	return (arswitch_writereg16(dev, addr + 2, (data >> 16) & 0xffff));
 }
 
 int
 arswitch_modifyreg(device_t dev, int addr, int mask, int set)
 {
 	int value;
-	
-	value = arswitch_readreg(dev, addr);
+	uint16_t phy, reg;
+
+	arswitch_split_setpage(dev, addr, &phy, &reg);
+
+	value = arswitch_reg_read32(dev, 0x10 | phy, reg);
 	value &= ~mask;
 	value |= set;
-	return (arswitch_writereg(dev, addr, value));
+	return (arswitch_reg_write32(dev, 0x10 | phy, reg, value));
 }
 
 int
 arswitch_waitreg(device_t dev, int addr, int mask, int val, int timeout)
 {
 	int err, v;
+	uint16_t phy, reg;
+
+	arswitch_split_setpage(dev, addr, &phy, &reg);
 
 	err = -1;
 	while (1) {
-		v = arswitch_readreg(dev, addr);
+		v = arswitch_reg_read32(dev, 0x10 | phy, reg);
 		v &= mask;
 		if (v == val) {
 			err = 0;

Modified: head/sys/dev/etherswitch/arswitch/arswitchvar.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitchvar.h	Sun Mar  8 03:34:06 2015	(r279766)
+++ head/sys/dev/etherswitch/arswitch/arswitchvar.h	Sun Mar  8 03:53:36 2015	(r279767)
@@ -60,7 +60,7 @@ struct arswitch_softc {
 	int		is_internal_switch;
 	int		chip_ver;
 	int		chip_rev;
-	int		mii_lo_first;
+	int		mii_lo_first;		/* Send low data DWORD before high */
 	ar8x16_switch_type	sc_switchtype;
 	/* should be the max of both pre-AR8327 and AR8327 ports */
 	char		*ifname[ARSWITCH_NUM_PHYS];
@@ -98,6 +98,10 @@ struct arswitch_softc {
 		    int *);
 		int (* arswitch_vlan_set_pvid) (struct arswitch_softc *, int,
 		    int);
+
+		/* PHY functions */
+		int (* arswitch_phy_read) (device_t, int, int);
+		int (* arswitch_phy_write) (device_t, int, int, int);
 	} hal;
 
 	struct {


More information about the svn-src-head mailing list