summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2020-11-09 15:45:22 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2020-11-09 15:45:22 +0000
commitfca63952c27a4663ea512544e1aed3a5851cd880 (patch)
tree626ad0f1e719145de80d483b25fa6e46c3afb9aa /sys/dev
parent3b29a603cfb9c736d6b2ed58a7f8b50ef889766d (diff)
Rework MAC initialization code. Properly turn comphy off and on again
on re-initialization. Make sure interrupts are masked while we are doing those bits dirty. This fixes issues with network stopping after the first down/up cycle.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/fdt/if_mvpp.c251
1 files changed, 164 insertions, 87 deletions
diff --git a/sys/dev/fdt/if_mvpp.c b/sys/dev/fdt/if_mvpp.c
index df284ef85f3..cee8a6d26ca 100644
--- a/sys/dev/fdt/if_mvpp.c
+++ b/sys/dev/fdt/if_mvpp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_mvpp.c,v 1.36 2020/11/09 15:41:44 patrick Exp $ */
+/* $OpenBSD: if_mvpp.c,v 1.37 2020/11/09 15:45:21 patrick Exp $ */
/*
* Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
* Copyright (c) 2017, 2020 Patrick Wildt <patrick@blueri.se>
@@ -310,11 +310,16 @@ void mvpp2_rxq_hw_deinit(struct mvpp2_port *, struct mvpp2_rx_queue *);
void mvpp2_rxq_long_pool_set(struct mvpp2_port *, int, int);
void mvpp2_rxq_short_pool_set(struct mvpp2_port *, int, int);
+void mvpp2_mac_reset_assert(struct mvpp2_port *);
+void mvpp2_pcs_reset_assert(struct mvpp2_port *);
+void mvpp2_pcs_reset_deassert(struct mvpp2_port *);
void mvpp2_mac_config(struct mvpp2_port *);
void mvpp2_xlg_config(struct mvpp2_port *);
void mvpp2_gmac_config(struct mvpp2_port *);
-void mvpp2_comphy_config(struct mvpp2_port *);
+void mvpp2_comphy_config(struct mvpp2_port *, int);
void mvpp2_gop_config(struct mvpp2_port *);
+void mvpp2_gop_intr_mask(struct mvpp2_port *);
+void mvpp2_gop_intr_unmask(struct mvpp2_port *);
struct mvpp2_dmamem *
mvpp2_dmamem_alloc(struct mvpp2_softc *, bus_size_t, bus_size_t);
@@ -1453,24 +1458,8 @@ mvpp2_port_attach(struct device *parent, struct device *self, void *aux)
mvpp2_rxq_short_pool_set(sc, i, i);
}
- /* Reset Mac */
- mvpp2_gmac_write(sc, MVPP2_PORT_CTRL2_REG,
- mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) |
- MVPP2_PORT_CTRL2_PORTMACRESET);
- if (sc->sc_gop_id == 0) {
- mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG,
- mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG) &
- ~MV_XLG_MAC_CTRL0_MACRESETN);
- reg = mvpp2_mpcs_read(sc, MVPP22_MPCS_CLOCK_RESET);
- reg |= MVPP22_MPCS_CLK_DIV_PHASE_SET;
- reg &= ~MVPP22_MPCS_TX_SD_CLK_RESET;
- reg &= ~MVPP22_MPCS_RX_SD_CLK_RESET;
- reg &= ~MVPP22_MPCS_MAC_CLK_RESET;
- mvpp2_mpcs_write(sc, MVPP22_MPCS_CLOCK_RESET, reg);
- reg = mvpp2_xpcs_read(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG);
- reg &= ~MVPP22_XPCS_PCSRESET;
- mvpp2_xpcs_write(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG, reg);
- }
+ mvpp2_mac_reset_assert(sc);
+ mvpp2_pcs_reset_assert(sc);
timeout_set(&sc->sc_tick, mvpp2_tick, sc);
@@ -1551,26 +1540,16 @@ mvpp2_port_attach(struct device *parent, struct device *self, void *aux)
reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_MASK_REG);
reg |= MVPP2_GMAC_INT_CAUSE_LINK_CHANGE;
mvpp2_gmac_write(sc, MVPP2_GMAC_INT_MASK_REG, reg);
- reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_SUM_MASK_REG);
- reg |= MVPP2_GMAC_INT_SUM_CAUSE_LINK_CHANGE;
- mvpp2_gmac_write(sc, MVPP2_GMAC_INT_SUM_MASK_REG, reg);
}
if (sc->sc_gop_id == 0) {
reg = mvpp2_xlg_read(sc, MV_XLG_INTERRUPT_MASK_REG);
reg |= MV_XLG_INTERRUPT_LINK_CHANGE;
mvpp2_xlg_write(sc, MV_XLG_INTERRUPT_MASK_REG, reg);
- reg = mvpp2_xlg_read(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG);
- reg &= ~MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_XLG;
- reg &= ~MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_GIG;
- if (sc->sc_phy_mode == PHY_MODE_10GBASER ||
- sc->sc_phy_mode == PHY_MODE_XAUI)
- reg |= MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_XLG;
- else
- reg |= MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_GIG;
- mvpp2_xlg_write(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG, reg);
}
+ mvpp2_gop_intr_unmask(sc);
+
idx = OF_getindex(sc->sc_node, "link", "interrupt-names");
if (idx >= 0)
fdt_intr_establish_idx(sc->sc_node, idx, IPL_NET,
@@ -1954,10 +1933,7 @@ mvpp2_port_change(struct mvpp2_port *sc)
{
uint32_t reg;
- if (!!(sc->sc_mii.mii_media_status & IFM_ACTIVE) == sc->sc_link)
- return;
-
- sc->sc_link = !sc->sc_link;
+ sc->sc_link = !!(sc->sc_mii.mii_media_status & IFM_ACTIVE);
if (sc->sc_inband_status)
return;
@@ -2412,47 +2388,97 @@ mvpp2_rxq_hw_init(struct mvpp2_port *sc, struct mvpp2_rx_queue *rxq)
}
void
-mvpp2_mac_config(struct mvpp2_port *sc)
+mvpp2_mac_reset_assert(struct mvpp2_port *sc)
{
- uint32_t reg;
-
- mvpp2_port_disable(sc);
-
mvpp2_gmac_write(sc, MVPP2_PORT_CTRL2_REG,
mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) |
MVPP2_PORT_CTRL2_PORTMACRESET);
- if (sc->sc_gop_id == 0) {
+ if (sc->sc_gop_id == 0)
mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG,
mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG) &
~MV_XLG_MAC_CTRL0_MACRESETN);
+}
+
+void
+mvpp2_pcs_reset_assert(struct mvpp2_port *sc)
+{
+ uint32_t reg;
+
+ if (sc->sc_gop_id != 0)
+ return;
+
+ reg = mvpp2_mpcs_read(sc, MVPP22_MPCS_CLOCK_RESET);
+ reg |= MVPP22_MPCS_CLK_DIV_PHASE_SET;
+ reg &= ~MVPP22_MPCS_TX_SD_CLK_RESET;
+ reg &= ~MVPP22_MPCS_RX_SD_CLK_RESET;
+ reg &= ~MVPP22_MPCS_MAC_CLK_RESET;
+ mvpp2_mpcs_write(sc, MVPP22_MPCS_CLOCK_RESET, reg);
+ reg = mvpp2_xpcs_read(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG);
+ reg &= ~MVPP22_XPCS_PCSRESET;
+ mvpp2_xpcs_write(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG, reg);
+}
+
+void
+mvpp2_pcs_reset_deassert(struct mvpp2_port *sc)
+{
+ uint32_t reg;
+
+ if (sc->sc_gop_id != 0)
+ return;
+
+ if (sc->sc_phy_mode == PHY_MODE_10GBASER) {
reg = mvpp2_mpcs_read(sc, MVPP22_MPCS_CLOCK_RESET);
- reg |= MVPP22_MPCS_CLK_DIV_PHASE_SET;
- reg &= ~MVPP22_MPCS_TX_SD_CLK_RESET;
- reg &= ~MVPP22_MPCS_RX_SD_CLK_RESET;
- reg &= ~MVPP22_MPCS_MAC_CLK_RESET;
+ reg &= ~MVPP22_MPCS_CLK_DIV_PHASE_SET;
+ reg |= MVPP22_MPCS_TX_SD_CLK_RESET;
+ reg |= MVPP22_MPCS_RX_SD_CLK_RESET;
+ reg |= MVPP22_MPCS_MAC_CLK_RESET;
mvpp2_mpcs_write(sc, MVPP22_MPCS_CLOCK_RESET, reg);
+ } else if (sc->sc_phy_mode == PHY_MODE_XAUI) {
reg = mvpp2_xpcs_read(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG);
- reg &= ~MVPP22_XPCS_PCSRESET;
+ reg |= MVPP22_XPCS_PCSRESET;
mvpp2_xpcs_write(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG, reg);
}
+}
- mvpp2_comphy_config(sc);
- mvpp2_gop_config(sc);
+void
+mvpp2_mac_config(struct mvpp2_port *sc)
+{
+ uint32_t reg;
+ reg = mvpp2_gmac_read(sc, MVPP2_GMAC_AUTONEG_CONFIG);
+ reg &= ~MVPP2_GMAC_FORCE_LINK_PASS;
+ reg |= MVPP2_GMAC_FORCE_LINK_DOWN;
+ mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, reg);
if (sc->sc_gop_id == 0) {
- if (sc->sc_phy_mode == PHY_MODE_10GBASER) {
- reg = mvpp2_mpcs_read(sc, MVPP22_MPCS_CLOCK_RESET);
- reg &= ~MVPP22_MPCS_CLK_DIV_PHASE_SET;
- reg |= MVPP22_MPCS_TX_SD_CLK_RESET;
- reg |= MVPP22_MPCS_RX_SD_CLK_RESET;
- reg |= MVPP22_MPCS_MAC_CLK_RESET;
- mvpp2_mpcs_write(sc, MVPP22_MPCS_CLOCK_RESET, reg);
- } else if (sc->sc_phy_mode == PHY_MODE_XAUI) {
- reg = mvpp2_xpcs_read(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG);
- reg |= MVPP22_XPCS_PCSRESET;
- mvpp2_xpcs_write(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG, reg);
- }
+ reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG);
+ reg &= ~MV_XLG_MAC_CTRL0_FORCELINKPASS;
+ reg |= MV_XLG_MAC_CTRL0_FORCELINKDOWN;
+ mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG, reg);
+ }
+
+ mvpp2_port_disable(sc);
+
+ mvpp2_gmac_write(sc, MVPP2_PORT_CTRL2_REG,
+ mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) |
+ MVPP2_PORT_CTRL2_PORTMACRESET);
+ mvpp2_gop_intr_mask(sc);
+ mvpp2_comphy_config(sc, 0);
+
+ if (sc->sc_gop_id == 0 && (sc->sc_phy_mode == PHY_MODE_10GBASER ||
+ sc->sc_phy_mode == PHY_MODE_XAUI))
+ mvpp2_xlg_config(sc);
+ else
+ mvpp2_gmac_config(sc);
+ mvpp2_mac_reset_assert(sc);
+ mvpp2_pcs_reset_assert(sc);
+
+ mvpp2_comphy_config(sc, 1);
+ mvpp2_gop_config(sc);
+
+ mvpp2_pcs_reset_deassert(sc);
+
+ if (sc->sc_gop_id == 0) {
reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL3_REG);
reg &= ~MV_XLG_MAC_CTRL3_MACMODESELECT_MASK;
if (sc->sc_phy_mode == PHY_MODE_10GBASER ||
@@ -2478,13 +2504,33 @@ mvpp2_mac_config(struct mvpp2_port *sc)
mvpp2_gmac_write(sc, MVPP2_GMAC_CTRL_0_REG, reg);
}
- if (sc->sc_gop_id == 0 && (sc->sc_phy_mode == PHY_MODE_10GBASER ||
- sc->sc_phy_mode == PHY_MODE_XAUI))
- mvpp2_xlg_config(sc);
- else
- mvpp2_gmac_config(sc);
+ mvpp2_gop_intr_unmask(sc);
+
+ if (!(sc->sc_phy_mode == PHY_MODE_10GBASER ||
+ sc->sc_phy_mode == PHY_MODE_XAUI)) {
+ mvpp2_gmac_write(sc, MVPP2_PORT_CTRL2_REG,
+ mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) &
+ ~MVPP2_PORT_CTRL2_PORTMACRESET);
+ while (mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) &
+ MVPP2_PORT_CTRL2_PORTMACRESET)
+ ;
+ }
mvpp2_port_enable(sc);
+
+ if (sc->sc_inband_status) {
+ reg = mvpp2_gmac_read(sc, MVPP2_GMAC_AUTONEG_CONFIG);
+ reg &= ~MVPP2_GMAC_FORCE_LINK_PASS;
+ reg &= ~MVPP2_GMAC_FORCE_LINK_DOWN;
+ mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, reg);
+ if (sc->sc_gop_id == 0) {
+ reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG);
+ reg &= ~MV_XLG_MAC_CTRL0_FORCELINKPASS;
+ reg &= ~MV_XLG_MAC_CTRL0_FORCELINKDOWN;
+ mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG, reg);
+ }
+ } else
+ mvpp2_port_change(sc);
}
void
@@ -2520,11 +2566,6 @@ mvpp2_gmac_config(struct mvpp2_port *sc)
ctl4 = mvpp2_gmac_read(sc, MVPP2_PORT_CTRL4_REG);
panc = mvpp2_gmac_read(sc, MVPP2_GMAC_AUTONEG_CONFIG);
- /* Force link down to change in-band settings. */
- panc &= ~MVPP2_GMAC_FORCE_LINK_PASS;
- panc |= MVPP2_GMAC_FORCE_LINK_DOWN;
- mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, panc);
-
ctl0 &= ~MVPP2_GMAC_PORT_TYPE_MASK;
ctl2 &= ~(MVPP2_GMAC_PORT_RESET_MASK | MVPP2_GMAC_PCS_ENABLE_MASK |
MVPP2_GMAC_INBAND_AN_MASK);
@@ -2566,22 +2607,20 @@ mvpp2_gmac_config(struct mvpp2_port *sc)
/* Use Auto-Negotiation for Inband Status only */
if (sc->sc_inband_status) {
- panc &= ~MVPP2_GMAC_FORCE_LINK_DOWN;
- panc &= ~MVPP2_GMAC_FORCE_LINK_PASS;
panc &= ~MVPP2_GMAC_CONFIG_MII_SPEED;
panc &= ~MVPP2_GMAC_CONFIG_GMII_SPEED;
panc &= ~MVPP2_GMAC_CONFIG_FULL_DUPLEX;
panc |= MVPP2_GMAC_IN_BAND_AUTONEG;
/* TODO: read mode from SFP */
- if (1) {
+ if (sc->sc_phy_mode == PHY_MODE_SGMII) {
+ /* SGMII */
+ panc |= MVPP2_GMAC_AN_SPEED_EN;
+ panc |= MVPP2_GMAC_AN_DUPLEX_EN;
+ } else {
/* 802.3z */
ctl0 |= MVPP2_GMAC_PORT_TYPE_MASK;
panc |= MVPP2_GMAC_CONFIG_GMII_SPEED;
panc |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
- } else {
- /* SGMII */
- panc |= MVPP2_GMAC_AN_SPEED_EN;
- panc |= MVPP2_GMAC_AN_DUPLEX_EN;
}
}
@@ -2589,11 +2628,6 @@ mvpp2_gmac_config(struct mvpp2_port *sc)
mvpp2_gmac_write(sc, MVPP2_PORT_CTRL2_REG, ctl2);
mvpp2_gmac_write(sc, MVPP2_PORT_CTRL4_REG, ctl4);
mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, panc);
-
- /* Port reset */
- while (mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) &
- MVPP2_PORT_CTRL2_PORTMACRESET)
- ;
}
#define COMPHY_BASE 0x120000
@@ -2622,7 +2656,7 @@ mvpp2_gmac_config(struct mvpp2_port *sc)
#define COMPHY_MODE_AP 11
void
-mvpp2_comphy_config(struct mvpp2_port *sc)
+mvpp2_comphy_config(struct mvpp2_port *sc, int on)
{
int node, phys[2], lane, unit;
uint32_t mode;
@@ -2662,8 +2696,12 @@ mvpp2_comphy_config(struct mvpp2_port *sc)
return;
}
- smc_call(COMPHY_SIP_POWER_ON, sc->sc->sc_ioh_paddr + COMPHY_BASE,
- lane, mode);
+ if (on)
+ smc_call(COMPHY_SIP_POWER_ON, sc->sc->sc_ioh_paddr + COMPHY_BASE,
+ lane, mode);
+ else
+ smc_call(COMPHY_SIP_POWER_OFF, sc->sc->sc_ioh_paddr + COMPHY_BASE,
+ lane, 0);
}
void
@@ -2738,6 +2776,43 @@ mvpp2_gop_config(struct mvpp2_port *sc)
}
void
+mvpp2_gop_intr_mask(struct mvpp2_port *sc)
+{
+ uint32_t reg;
+
+ if (sc->sc_gop_id == 0) {
+ reg = mvpp2_xlg_read(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG);
+ reg &= ~MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_XLG;
+ reg &= ~MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_GIG;
+ mvpp2_xlg_write(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG, reg);
+ }
+
+ reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_SUM_MASK_REG);
+ reg &= ~MVPP2_GMAC_INT_SUM_CAUSE_LINK_CHANGE;
+ mvpp2_gmac_write(sc, MVPP2_GMAC_INT_SUM_MASK_REG, reg);
+}
+
+void
+mvpp2_gop_intr_unmask(struct mvpp2_port *sc)
+{
+ uint32_t reg;
+
+ reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_SUM_MASK_REG);
+ reg |= MVPP2_GMAC_INT_SUM_CAUSE_LINK_CHANGE;
+ mvpp2_gmac_write(sc, MVPP2_GMAC_INT_SUM_MASK_REG, reg);
+
+ if (sc->sc_gop_id == 0) {
+ reg = mvpp2_xlg_read(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG);
+ if (sc->sc_phy_mode == PHY_MODE_10GBASER ||
+ sc->sc_phy_mode == PHY_MODE_XAUI)
+ reg |= MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_XLG;
+ else
+ reg |= MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_GIG;
+ mvpp2_xlg_write(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG, reg);
+ }
+}
+
+void
mvpp2_down(struct mvpp2_port *sc)
{
struct ifnet *ifp = &sc->sc_ac.ac_if;
@@ -2752,7 +2827,9 @@ mvpp2_down(struct mvpp2_port *sc)
mvpp2_egress_disable(sc);
mvpp2_ingress_disable(sc);
- mvpp2_port_disable(sc);
+
+ mvpp2_mac_reset_assert(sc);
+ mvpp2_pcs_reset_assert(sc);
/* XXX: single vector */
mvpp2_interrupts_disable(sc, (1 << 0));