diff --git a/sys/arm64/conf/std.marvell b/sys/arm64/conf/std.marvell --- a/sys/arm64/conf/std.marvell +++ b/sys/arm64/conf/std.marvell @@ -42,7 +42,6 @@ # Etherswitch devices device etherswitch # Enable etherswitch support device miiproxy # Required for etherswitch -device e6000sw # Marvell mv88e6085 based switches # USB support device ehci_mv # Marvell EHCI USB interface diff --git a/sys/dev/etherswitch/e6000sw/e6000sw.c b/sys/dev/etherswitch/e6000sw/e6000sw.c --- a/sys/dev/etherswitch/e6000sw/e6000sw.c +++ b/sys/dev/etherswitch/e6000sw/e6000sw.c @@ -122,8 +122,6 @@ static int e6000sw_set_vlan_mode(e6000sw_softc_t *, uint32_t); static int e6000sw_readreg_wrapper(device_t, int); static int e6000sw_writereg_wrapper(device_t, int, int); -static int e6000sw_readphy_wrapper(device_t, int, int); -static int e6000sw_writephy_wrapper(device_t, int, int, int); static int e6000sw_getvgroup_wrapper(device_t, etherswitch_vlangroup_t *); static int e6000sw_setvgroup_wrapper(device_t, etherswitch_vlangroup_t *); static int e6000sw_setvgroup(device_t, etherswitch_vlangroup_t *); @@ -174,8 +172,8 @@ DEVMETHOD(etherswitch_setport, e6000sw_setport), DEVMETHOD(etherswitch_readreg, e6000sw_readreg_wrapper), DEVMETHOD(etherswitch_writereg, e6000sw_writereg_wrapper), - DEVMETHOD(etherswitch_readphyreg, e6000sw_readphy_wrapper), - DEVMETHOD(etherswitch_writephyreg, e6000sw_writephy_wrapper), + DEVMETHOD(etherswitch_readphyreg, e6000sw_readphy), + DEVMETHOD(etherswitch_writephyreg, e6000sw_writephy), DEVMETHOD(etherswitch_setvgroup, e6000sw_setvgroup_wrapper), DEVMETHOD(etherswitch_getvgroup, e6000sw_getvgroup_wrapper), @@ -463,6 +461,7 @@ if (ports == 0) { device_printf(dev, "failed to parse DTS: no ports found for " "switch\n"); + E6000SW_UNLOCK(sc); return (ENXIO); } @@ -531,11 +530,20 @@ if (!e6000sw_is_phyport(sc, port)) continue; + /* + * It's necessary to unlock mutex, because e6000sw_attach_miibus + * calls functions, which try to lock mutex.That leads + * to recursive lock on non recursive mutex. + */ + E6000SW_UNLOCK(sc); + err = e6000sw_attach_miibus(sc, port); if (err != 0) { device_printf(sc->dev, "failed to attach miibus\n"); goto out_fail; } + + E6000SW_LOCK(sc); } etherswitch_info.es_nports = sc->num_ports; @@ -556,7 +564,6 @@ return (0); out_fail: - E6000SW_UNLOCK(sc); e6000sw_detach(dev); return (err); @@ -661,14 +668,18 @@ uint32_t val; sc = device_get_softc(dev); + E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); + if (!e6000sw_is_phyport(sc, phy) || reg >= E6000SW_NUM_PHY_REGS) { device_printf(dev, "Wrong register address.\n"); return (EINVAL); } - E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); + E6000SW_LOCK(sc); + if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) { device_printf(dev, "Timeout while waiting for switch\n"); + E6000SW_UNLOCK(sc); return (ETIMEDOUT); } @@ -677,11 +688,14 @@ ((phy << SMI_CMD_DEV_ADDR) & SMI_CMD_DEV_ADDR_MASK)); if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) { device_printf(dev, "Timeout while waiting for switch\n"); + E6000SW_UNLOCK(sc); return (ETIMEDOUT); } val = e6000sw_readreg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG); + E6000SW_UNLOCK(sc); + return (val & PHY_DATA_MASK); } @@ -691,14 +705,18 @@ e6000sw_softc_t *sc; sc = device_get_softc(dev); + E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); + if (!e6000sw_is_phyport(sc, phy) || reg >= E6000SW_NUM_PHY_REGS) { device_printf(dev, "Wrong register address.\n"); return (EINVAL); } - E6000SW_LOCK_ASSERT(sc, SA_XLOCKED); + E6000SW_LOCK(sc); + if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) { device_printf(dev, "Timeout while waiting for switch\n"); + E6000SW_UNLOCK(sc); return (ETIMEDOUT); } @@ -708,6 +726,8 @@ SMI_CMD_OP_C22_WRITE | (reg & SMI_CMD_REG_ADDR_MASK) | ((phy << SMI_CMD_DEV_ADDR) & SMI_CMD_DEV_ADDR_MASK)); + E6000SW_UNLOCK(sc); + return (0); } @@ -725,11 +745,10 @@ if (sc->sc_tq != NULL) taskqueue_free(sc->sc_tq); - bus_generic_detach(dev); + device_delete_children(dev); + sx_destroy(&sc->sx); for (phy = 0; phy < sc->num_ports; phy++) { - if (sc->miibus[phy] != NULL) - device_delete_child(dev, sc->miibus[phy]); if (sc->ifp[phy] != NULL) if_free(sc->ifp[phy]); if (sc->ifname[phy] != NULL) @@ -1051,42 +1070,6 @@ return (0); } -/* - * These wrappers are necessary because PHY accesses from etherswitchcfg - * need to be synchronized with locks, while miibus PHY accesses do not. - */ -static int -e6000sw_readphy_wrapper(device_t dev, int phy, int reg) -{ - e6000sw_softc_t *sc; - int ret; - - sc = device_get_softc(dev); - E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); - - E6000SW_LOCK(sc); - ret = e6000sw_readphy(dev, phy, reg); - E6000SW_UNLOCK(sc); - - return (ret); -} - -static int -e6000sw_writephy_wrapper(device_t dev, int phy, int reg, int data) -{ - e6000sw_softc_t *sc; - int ret; - - sc = device_get_softc(dev); - E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); - - E6000SW_LOCK(sc); - ret = e6000sw_writephy(dev, phy, reg, data); - E6000SW_UNLOCK(sc); - - return (ret); -} - /* * setvgroup/getvgroup called from etherswitchfcg need to be locked, * while internal calls do not. diff --git a/sys/modules/Makefile b/sys/modules/Makefile --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -108,6 +108,7 @@ ${_dpms} \ dummynet \ ${_dwwdt} \ + ${_e6000sw} \ ${_efirt} \ ${_em} \ ${_ena} \ @@ -624,6 +625,7 @@ .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" _sdhci_fdt= sdhci_fdt +_e6000sw= e6000sw .endif .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" diff --git a/sys/modules/e6000sw/Makefile b/sys/modules/e6000sw/Makefile new file mode 100644 --- /dev/null +++ b/sys/modules/e6000sw/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/etherswitch/e6000sw + +KMOD= e6000sw +SRCS= e6000sw.c + +SRCS+= bus_if.h etherswitch_if.h mdio_if.h miibus_if.h ofw_bus_if.h + +.include