Index: sys/dev/axgbe/if_axgbe.c =================================================================== --- sys/dev/axgbe/if_axgbe.c +++ sys/dev/axgbe/if_axgbe.c @@ -51,10 +51,6 @@ #include #include -#include -#include -#include - #include #include "miibus_if.h" @@ -114,6 +110,14 @@ { -1, 0 } }; +static struct xgbe_version_data xgbe_v1 = { + .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v1, + .xpcs_access = XGBE_XPCS_ACCESS_V1, + .tx_max_fifo_size = 81920, + .rx_max_fifo_size = 81920, + .tx_tstamp_workaround = 1, +}; + MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data"); static void @@ -276,22 +280,6 @@ return (BUS_PROBE_DEFAULT); } -static int -axgbe_get_optional_prop(device_t dev, phandle_t node, const char *name, - int *data, size_t len) -{ - - if (!OF_hasprop(node, name)) - return (-1); - - if (OF_getencprop(node, name, data, len) <= 0) { - device_printf(dev,"%s property is invalid\n", name); - return (ENXIO); - } - - return (0); -} - static int axgbe_attach(device_t dev) { @@ -303,10 +291,11 @@ struct resource *mac_res[11]; struct resource *phy_res[4]; ssize_t len; - int error, i, j; + int i, j; sc = device_get_softc(dev); + sc->prv.vdata = &xgbe_v1; node = ofw_bus_get_node(dev); if (OF_getencprop(node, "phy-handle", &phy_handle, sizeof(phy_handle)) <= 0) { @@ -387,83 +376,12 @@ } sc->prv.dev = dev; + sc->prv.phy_node = phy_node; sc->prv.dmat = bus_get_dma_tag(dev); sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full | ADVERTISED_1000baseKX_Full; - /* - * Read the needed properties from the phy node. - */ - - /* This is documented as optional, but Linux requires it */ - if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set, - sizeof(sc->prv.speed_set)) <= 0) { - device_printf(dev, "%s property is missing\n", - XGBE_SPEEDSET_PROPERTY); - return (EINVAL); - } - - error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY, - sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc)); - if (error > 0) { - return (error); - } else if (error < 0) { - sc->prv.serdes_blwc[0] = XGBE_SPEED_1000_BLWC; - sc->prv.serdes_blwc[1] = XGBE_SPEED_2500_BLWC; - sc->prv.serdes_blwc[2] = XGBE_SPEED_10000_BLWC; - } - - error = axgbe_get_optional_prop(dev, phy_node, XGBE_CDR_RATE_PROPERTY, - sc->prv.serdes_cdr_rate, sizeof(sc->prv.serdes_cdr_rate)); - if (error > 0) { - return (error); - } else if (error < 0) { - sc->prv.serdes_cdr_rate[0] = XGBE_SPEED_1000_CDR; - sc->prv.serdes_cdr_rate[1] = XGBE_SPEED_2500_CDR; - sc->prv.serdes_cdr_rate[2] = XGBE_SPEED_10000_CDR; - } - - error = axgbe_get_optional_prop(dev, phy_node, XGBE_PQ_SKEW_PROPERTY, - sc->prv.serdes_pq_skew, sizeof(sc->prv.serdes_pq_skew)); - if (error > 0) { - return (error); - } else if (error < 0) { - sc->prv.serdes_pq_skew[0] = XGBE_SPEED_1000_PQ; - sc->prv.serdes_pq_skew[1] = XGBE_SPEED_2500_PQ; - sc->prv.serdes_pq_skew[2] = XGBE_SPEED_10000_PQ; - } - - error = axgbe_get_optional_prop(dev, phy_node, XGBE_TX_AMP_PROPERTY, - sc->prv.serdes_tx_amp, sizeof(sc->prv.serdes_tx_amp)); - if (error > 0) { - return (error); - } else if (error < 0) { - sc->prv.serdes_tx_amp[0] = XGBE_SPEED_1000_TXAMP; - sc->prv.serdes_tx_amp[1] = XGBE_SPEED_2500_TXAMP; - sc->prv.serdes_tx_amp[2] = XGBE_SPEED_10000_TXAMP; - } - - error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_CFG_PROPERTY, - sc->prv.serdes_dfe_tap_cfg, sizeof(sc->prv.serdes_dfe_tap_cfg)); - if (error > 0) { - return (error); - } else if (error < 0) { - sc->prv.serdes_dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG; - sc->prv.serdes_dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG; - sc->prv.serdes_dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG; - } - - error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_ENA_PROPERTY, - sc->prv.serdes_dfe_tap_ena, sizeof(sc->prv.serdes_dfe_tap_ena)); - if (error > 0) { - return (error); - } else if (error < 0) { - sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE; - sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE; - sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE; - } - /* Check if the NIC is DMA coherent */ sc->prv.coherent = OF_hasprop(node, "dma-coherent"); if (sc->prv.coherent) { @@ -487,6 +405,7 @@ xgbe_init_function_ptrs_phy(&sc->prv.phy_if); xgbe_init_function_ptrs_dev(&sc->prv.hw_if); xgbe_init_function_ptrs_desc(&sc->prv.desc_if); + sc->prv.vdata->init_function_ptrs_phy_impl(&sc->prv.phy_if); /* Reset the hardware */ sc->prv.hw_if.exit(&sc->prv); Index: sys/dev/axgbe/xgbe-common.h =================================================================== --- sys/dev/axgbe/xgbe-common.h +++ sys/dev/axgbe/xgbe-common.h @@ -1057,6 +1057,11 @@ #endif /* MDIO mask values */ +#define XGBE_AN_CL73_INT_CMPLT BIT(0) +#define XGBE_AN_CL73_INC_LINK BIT(1) +#define XGBE_AN_CL73_PG_RCV BIT(2) +#define XGBE_AN_CL73_INT_MASK 0x07 + #define XGBE_XNP_MCF_NULL_MESSAGE 0x001 #define XGBE_XNP_ACK_PROCESSED BIT(12) #define XGBE_XNP_MP_FORMATTED BIT(13) Index: sys/dev/axgbe/xgbe-dev.c =================================================================== --- sys/dev/axgbe/xgbe-dev.c +++ sys/dev/axgbe/xgbe-dev.c @@ -552,32 +552,26 @@ XGMAC_IOWRITE_BITS(pdata, MMC_TIER, ALL_INTERRUPTS, 0xffffffff); } -static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata) +static int xgbe_set_speed(struct xgbe_prv_data *pdata, int speed) { - if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x3) - return 0; - - XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x3); - - return 0; -} - -static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata) -{ - if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x2) - return 0; - - XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x2); + unsigned int ss; - return 0; -} - -static int xgbe_set_xgmii_speed(struct xgbe_prv_data *pdata) -{ - if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0) - return 0; + switch (speed) { + case SPEED_1000: + ss = 0x03; + break; + case SPEED_2500: + ss = 0x02; + break; + case SPEED_10000: + ss = 0x00; + break; + default: + return -EINVAL; + } - XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0); + if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) != ss) + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, ss); return 0; } @@ -851,7 +845,9 @@ rdesc->desc2 = 0; rdesc->desc3 = 0; +#if defined(__arm__) dsb(sy); +#endif } static void xgbe_tx_desc_init(struct xgbe_channel *channel) @@ -906,11 +902,15 @@ XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, inte); +#if defined(__arm__) dsb(sy); +#endif XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN, 1); +#if defined(__arm__) dsb(sy); +#endif } static void xgbe_rx_desc_init(struct xgbe_channel *channel) @@ -1111,13 +1111,17 @@ bus_dmamap_sync(ring->rdesc_dmat, ring->rdesc_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); +#if defined(__arm__) dsb(sy); +#endif /* Check for data availability */ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN)) return 1; +#if defined(__arm__) dsb(sy); +#endif /* Normal Descriptor, be sure Context Descriptor bit is off */ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, CONTEXT, 0); @@ -1524,23 +1528,7 @@ static void xgbe_config_mac_speed(struct xgbe_prv_data *pdata) { - switch (pdata->phy_speed) { - case SPEED_10000: - xgbe_set_xgmii_speed(pdata); - break; - - case SPEED_2500: - xgbe_set_gmii_2500_speed(pdata); - break; - - case SPEED_1000: - xgbe_set_gmii_speed(pdata); - break; - case SPEED_UNKNOWN: - break; - default: - panic("TODO %s:%d\n", __FILE__, __LINE__); - } + xgbe_set_speed(pdata, pdata->phy_speed); } static void xgbe_config_checksum_offload(struct xgbe_prv_data *pdata) @@ -2237,9 +2225,7 @@ hw_if->read_mmd_regs = xgbe_read_mmd_regs; hw_if->write_mmd_regs = xgbe_write_mmd_regs; - hw_if->set_gmii_speed = xgbe_set_gmii_speed; - hw_if->set_gmii_2500_speed = xgbe_set_gmii_2500_speed; - hw_if->set_xgmii_speed = xgbe_set_xgmii_speed; + hw_if->set_speed = xgbe_set_speed; hw_if->enable_tx = xgbe_enable_tx; hw_if->disable_tx = xgbe_disable_tx; Index: sys/dev/axgbe/xgbe-drv.c =================================================================== --- sys/dev/axgbe/xgbe-drv.c +++ sys/dev/axgbe/xgbe-drv.c @@ -886,7 +886,9 @@ } /* Make sure everything is written before the register write */ +#if defined(__arm__) dsb(sy); +#endif /* Update the Rx Tail Pointer Register with address of * the last cleaned entry */ @@ -915,7 +917,9 @@ cur = ring->cur; /* Be sure we get ring->cur before accessing descriptor data */ +#if defined(__arm__) dsb(sy); +#endif while ((processed < XGBE_TX_DESC_MAX_PROC) && (ring->dirty != cur)) { @@ -927,7 +931,9 @@ /* Make sure descriptor fields are read after reading the OWN * bit */ +#if defined(__arm__) dsb(sy); +#endif /* Free the SKB and reset the descriptor for re-use */ desc_if->unmap_rdata(pdata, rdata); Index: sys/dev/axgbe/xgbe-mdio.c =================================================================== --- sys/dev/axgbe/xgbe-mdio.c +++ sys/dev/axgbe/xgbe-mdio.c @@ -145,274 +145,125 @@ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); } -static void xgbe_pcs_power_cycle(struct xgbe_prv_data *pdata) +static void xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata) { - unsigned int reg; - - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); - - reg |= MDIO_CTRL1_LPOWER; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); - - DELAY(75); - - reg &= ~MDIO_CTRL1_LPOWER; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); } -static void xgbe_serdes_start_ratechange(struct xgbe_prv_data *pdata) +static void xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata) { - /* Assert Rx and Tx ratechange */ - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 1); + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); } -static void xgbe_serdes_complete_ratechange(struct xgbe_prv_data *pdata) +static void xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata) { - unsigned int wait; - u16 status; - - /* Release Rx and Tx ratechange */ - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 0); - - /* Wait for Rx and Tx ready */ - wait = XGBE_RATECHANGE_COUNT; - while (wait--) { - DELAY(50); + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK); +} - status = XSIR0_IOREAD(pdata, SIR0_STATUS); - if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) && - XSIR_GET_BITS(status, SIR0_STATUS, TX_READY)) - goto rx_reset; +static void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata) +{ + switch (pdata->an_mode) { + case XGBE_AN_MODE_CL73: + xgbe_an73_enable_interrupts(pdata); + break; + default: + break; } - -rx_reset: - /* Perform Rx reset for the DFE changes */ - XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 0); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 1); } -static void xgbe_xgmii_mode(struct xgbe_prv_data *pdata) +static void xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata) { - unsigned int reg; + xgbe_an73_clear_interrupts(pdata); +} +static void xgbe_kr_mode(struct xgbe_prv_data *pdata) +{ /* Enable KR training */ xgbe_an_enable_kr_training(pdata); /* Set MAC to 10G speed */ - pdata->hw_if.set_xgmii_speed(pdata); - - /* Set PCS to KR/10G speed */ - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); - reg &= ~MDIO_PCS_CTRL2_TYPE; - reg |= MDIO_PCS_CTRL2_10GBR; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); - - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); - reg &= ~MDIO_CTRL1_SPEEDSEL; - reg |= MDIO_CTRL1_SPEED10G; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); - - xgbe_pcs_power_cycle(pdata); - - /* Set SerDes to 10G speed */ - xgbe_serdes_start_ratechange(pdata); - - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_10000_RATE); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_10000_WORD); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_10000_PLL); - - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, - pdata->serdes_cdr_rate[XGBE_SPEED_10000]); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, - pdata->serdes_tx_amp[XGBE_SPEED_10000]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, - pdata->serdes_blwc[XGBE_SPEED_10000]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, - pdata->serdes_pq_skew[XGBE_SPEED_10000]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, - pdata->serdes_dfe_tap_cfg[XGBE_SPEED_10000]); - XRXTX_IOWRITE(pdata, RXTX_REG22, - pdata->serdes_dfe_tap_ena[XGBE_SPEED_10000]); - - xgbe_serdes_complete_ratechange(pdata); + pdata->hw_if.set_speed(pdata, SPEED_10000); + + /* Call PHY implementation support to complete rate change */ + pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR); } -static void xgbe_gmii_2500_mode(struct xgbe_prv_data *pdata) +static void xgbe_kx_2500_mode(struct xgbe_prv_data *pdata) { - unsigned int reg; - /* Disable KR training */ xgbe_an_disable_kr_training(pdata); /* Set MAC to 2.5G speed */ - pdata->hw_if.set_gmii_2500_speed(pdata); - - /* Set PCS to KX/1G speed */ - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); - reg &= ~MDIO_PCS_CTRL2_TYPE; - reg |= MDIO_PCS_CTRL2_10GBX; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); - - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); - reg &= ~MDIO_CTRL1_SPEEDSEL; - reg |= MDIO_CTRL1_SPEED1G; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); - - xgbe_pcs_power_cycle(pdata); - - /* Set SerDes to 2.5G speed */ - xgbe_serdes_start_ratechange(pdata); - - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_2500_RATE); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_2500_WORD); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_2500_PLL); - - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, - pdata->serdes_cdr_rate[XGBE_SPEED_2500]); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, - pdata->serdes_tx_amp[XGBE_SPEED_2500]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, - pdata->serdes_blwc[XGBE_SPEED_2500]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, - pdata->serdes_pq_skew[XGBE_SPEED_2500]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, - pdata->serdes_dfe_tap_cfg[XGBE_SPEED_2500]); - XRXTX_IOWRITE(pdata, RXTX_REG22, - pdata->serdes_dfe_tap_ena[XGBE_SPEED_2500]); - - xgbe_serdes_complete_ratechange(pdata); + pdata->hw_if.set_speed(pdata, SPEED_2500); + + /* Call PHY implementation support to complete rate change */ + pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500); } -static void xgbe_gmii_mode(struct xgbe_prv_data *pdata) +static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata) { - unsigned int reg; - /* Disable KR training */ xgbe_an_disable_kr_training(pdata); /* Set MAC to 1G speed */ - pdata->hw_if.set_gmii_speed(pdata); - - /* Set PCS to KX/1G speed */ - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); - reg &= ~MDIO_PCS_CTRL2_TYPE; - reg |= MDIO_PCS_CTRL2_10GBX; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); - - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); - reg &= ~MDIO_CTRL1_SPEEDSEL; - reg |= MDIO_CTRL1_SPEED1G; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); - - xgbe_pcs_power_cycle(pdata); - - /* Set SerDes to 1G speed */ - xgbe_serdes_start_ratechange(pdata); - - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_1000_RATE); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_1000_WORD); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_1000_PLL); - - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, - pdata->serdes_cdr_rate[XGBE_SPEED_1000]); - XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, - pdata->serdes_tx_amp[XGBE_SPEED_1000]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, - pdata->serdes_blwc[XGBE_SPEED_1000]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, - pdata->serdes_pq_skew[XGBE_SPEED_1000]); - XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, - pdata->serdes_dfe_tap_cfg[XGBE_SPEED_1000]); - XRXTX_IOWRITE(pdata, RXTX_REG22, - pdata->serdes_dfe_tap_ena[XGBE_SPEED_1000]); - - xgbe_serdes_complete_ratechange(pdata); + pdata->hw_if.set_speed(pdata, SPEED_1000); + + /* Call PHY implementation support to complete rate change */ + pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000); } -static void xgbe_cur_mode(struct xgbe_prv_data *pdata, - enum xgbe_mode *mode) +static enum xgbe_mode xgbe_cur_mode(struct xgbe_prv_data *pdata) { - unsigned int reg; - - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); - if ((reg & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR) - *mode = XGBE_MODE_KR; - else - *mode = XGBE_MODE_KX; + return pdata->phy_if.phy_impl.cur_mode(pdata); } static bool xgbe_in_kr_mode(struct xgbe_prv_data *pdata) { - enum xgbe_mode mode; - - xgbe_cur_mode(pdata, &mode); - - return (mode == XGBE_MODE_KR); + return (xgbe_cur_mode(pdata) == XGBE_MODE_KR); } -static void xgbe_switch_mode(struct xgbe_prv_data *pdata) +static void xgbe_change_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) { - /* If we are in KR switch to KX, and vice-versa */ - if (xgbe_in_kr_mode(pdata)) { - if (pdata->speed_set == XGBE_SPEEDSET_1000_10000) - xgbe_gmii_mode(pdata); - else - xgbe_gmii_2500_mode(pdata); - } else { - xgbe_xgmii_mode(pdata); + switch (mode) { + case XGBE_MODE_KX_1000: + xgbe_kx_1000_mode(pdata); + break; + case XGBE_MODE_KX_2500: + xgbe_kx_2500_mode(pdata); + break; + case XGBE_MODE_KR: + xgbe_kr_mode(pdata); + break; + case XGBE_MODE_UNKNOWN: + break; + default: + device_printf(pdata->dev, "invalid operation mode requested (%u)\n", mode); } } -static void xgbe_set_mode(struct xgbe_prv_data *pdata, - enum xgbe_mode mode) +static void xgbe_switch_mode(struct xgbe_prv_data *pdata) { - enum xgbe_mode cur_mode; - - xgbe_cur_mode(pdata, &cur_mode); - if (mode != cur_mode) - xgbe_switch_mode(pdata); + xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata)); } -static bool xgbe_use_xgmii_mode(struct xgbe_prv_data *pdata) +static bool xgbe_set_mode(struct xgbe_prv_data *pdata, + enum xgbe_mode mode) { - if (pdata->phy.autoneg == AUTONEG_ENABLE) { - if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) - return true; - } else { - if (pdata->phy.speed == SPEED_10000) - return true; - } - - return false; -} + if (mode == xgbe_cur_mode(pdata)) + return false; -static bool xgbe_use_gmii_2500_mode(struct xgbe_prv_data *pdata) -{ - if (pdata->phy.autoneg == AUTONEG_ENABLE) { - if (pdata->phy.advertising & ADVERTISED_2500baseX_Full) - return true; - } else { - if (pdata->phy.speed == SPEED_2500) - return true; - } + xgbe_change_mode(pdata, mode); - return false; + return true; } -static bool xgbe_use_gmii_mode(struct xgbe_prv_data *pdata) +static bool xgbe_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) { - if (pdata->phy.autoneg == AUTONEG_ENABLE) { - if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full) - return true; - } else { - if (pdata->phy.speed == SPEED_1000) - return true; - } - - return false; + return pdata->phy_if.phy_impl.use_mode(pdata, mode); } -static void xgbe_set_an(struct xgbe_prv_data *pdata, bool enable, bool restart) +static void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable, + bool restart) { unsigned int reg; @@ -428,18 +279,49 @@ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); } -static void xgbe_restart_an(struct xgbe_prv_data *pdata) +static void xgbe_an73_restart(struct xgbe_prv_data *pdata) { - xgbe_set_an(pdata, true, true); + xgbe_an73_enable_interrupts(pdata); + xgbe_an73_set(pdata, true, true); } -static void xgbe_disable_an(struct xgbe_prv_data *pdata) +static void xgbe_an73_disable(struct xgbe_prv_data *pdata) { - xgbe_set_an(pdata, false, false); + xgbe_an73_set(pdata, false, false); + xgbe_an73_disable_interrupts(pdata); + + pdata->an_start = 0; } -static enum xgbe_an xgbe_an_tx_training(struct xgbe_prv_data *pdata, - enum xgbe_rx *state) +static void xgbe_an_restart(struct xgbe_prv_data *pdata) +{ + switch (pdata->an_mode) { + case XGBE_AN_MODE_CL73: + xgbe_an73_restart(pdata); + break; + default: + break; + } +} + +static void xgbe_an_disable(struct xgbe_prv_data *pdata) +{ + switch (pdata->an_mode) { + case XGBE_AN_MODE_CL73: + xgbe_an73_disable(pdata); + break; + default: + break; + } +} + +static void xgbe_an_disable_all(struct xgbe_prv_data *pdata) +{ + xgbe_an73_disable(pdata); +} + +static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata, + enum xgbe_rx *state) { unsigned int ad_reg, lp_reg, reg; @@ -463,20 +345,22 @@ /* Start KR training */ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); if (reg & XGBE_KR_TRAINING_ENABLE) { - XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 1); + if (pdata->phy_if.phy_impl.kr_training_pre) + pdata->phy_if.phy_impl.kr_training_pre(pdata); reg |= XGBE_KR_TRAINING_START; XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, - reg); + reg); - XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 0); + if (pdata->phy_if.phy_impl.kr_training_post) + pdata->phy_if.phy_impl.kr_training_post(pdata); } return XGBE_AN_PAGE_RECEIVED; } -static enum xgbe_an xgbe_an_tx_xnp(struct xgbe_prv_data *pdata, - enum xgbe_rx *state) +static enum xgbe_an xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata, + enum xgbe_rx *state) { u16 msg; @@ -492,8 +376,8 @@ return XGBE_AN_PAGE_RECEIVED; } -static enum xgbe_an xgbe_an_rx_bpa(struct xgbe_prv_data *pdata, - enum xgbe_rx *state) +static enum xgbe_an xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata, + enum xgbe_rx *state) { unsigned int link_support; unsigned int reg, ad_reg, lp_reg; @@ -512,12 +396,12 @@ return ((ad_reg & XGBE_XNP_NP_EXCHANGE) || (lp_reg & XGBE_XNP_NP_EXCHANGE)) - ? xgbe_an_tx_xnp(pdata, state) - : xgbe_an_tx_training(pdata, state); + ? xgbe_an73_tx_xnp(pdata, state) + : xgbe_an73_tx_training(pdata, state); } -static enum xgbe_an xgbe_an_rx_xnp(struct xgbe_prv_data *pdata, - enum xgbe_rx *state) +static enum xgbe_an xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata, + enum xgbe_rx *state) { unsigned int ad_reg, lp_reg; @@ -527,11 +411,11 @@ return ((ad_reg & XGBE_XNP_NP_EXCHANGE) || (lp_reg & XGBE_XNP_NP_EXCHANGE)) - ? xgbe_an_tx_xnp(pdata, state) - : xgbe_an_tx_training(pdata, state); + ? xgbe_an73_tx_xnp(pdata, state) + : xgbe_an73_tx_training(pdata, state); } -static enum xgbe_an xgbe_an_page_received(struct xgbe_prv_data *pdata) +static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata) { enum xgbe_rx *state; unsigned long an_timeout; @@ -551,16 +435,15 @@ } } - state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state - : &pdata->kx_state; + state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state : &pdata->kx_state; switch (*state) { case XGBE_RX_BPA: - ret = xgbe_an_rx_bpa(pdata, state); + ret = xgbe_an73_rx_bpa(pdata, state); break; case XGBE_RX_XNP: - ret = xgbe_an_rx_xnp(pdata, state); + ret = xgbe_an73_rx_xnp(pdata, state); break; default: @@ -570,14 +453,14 @@ return ret; } -static enum xgbe_an xgbe_an_incompat_link(struct xgbe_prv_data *pdata) +static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) { /* Be sure we aren't looping trying to negotiate */ if (xgbe_in_kr_mode(pdata)) { pdata->kr_state = XGBE_RX_ERROR; - if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) && - !(pdata->phy.advertising & ADVERTISED_2500baseX_Full)) + if (!(XGBE_ADV(&pdata->phy, 1000baseKX_Full)) && + !(XGBE_ADV(&pdata->phy, 2500baseX_Full))) return XGBE_AN_NO_LINK; if (pdata->kx_state != XGBE_RX_BPA) @@ -585,28 +468,26 @@ } else { pdata->kx_state = XGBE_RX_ERROR; - if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full)) + if (!(XGBE_ADV(&pdata->phy, 10000baseKR_Full))) return XGBE_AN_NO_LINK; if (pdata->kr_state != XGBE_RX_BPA) return XGBE_AN_NO_LINK; } - xgbe_disable_an(pdata); + xgbe_an_disable(pdata); xgbe_switch_mode(pdata); - xgbe_restart_an(pdata); + xgbe_an_restart(pdata); return XGBE_AN_INCOMPAT_LINK; } -static void xgbe_an_isr(void *data) +static void xgbe_an73_isr(struct xgbe_prv_data *pdata) { - struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; - /* Disable AN interrupts */ - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); + xgbe_an73_disable_interrupts(pdata); /* Save the interrupt(s) that fired */ pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); @@ -618,30 +499,40 @@ xgbe_an_state_machine(pdata); } else { /* Enable AN interrupts */ - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, - XGBE_AN_INT_MASK); + xgbe_an73_enable_interrupts(pdata); } } -static void xgbe_an_state_machine(struct xgbe_prv_data *pdata) +static void xgbe_an_isr(void *data) { - enum xgbe_an cur_state = pdata->an_state; + struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; - sx_xlock(&pdata->an_mutex); + switch (pdata->an_mode) { + case XGBE_AN_MODE_CL73: + xgbe_an73_isr(pdata); + break; + default: + break; + } +} + +static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata) +{ + enum xgbe_an cur_state = pdata->an_state; if (!pdata->an_int) goto out; next_int: - if (pdata->an_int & XGBE_AN_PG_RCV) { + if (pdata->an_int & XGBE_AN_CL73_PG_RCV) { pdata->an_state = XGBE_AN_PAGE_RECEIVED; - pdata->an_int &= ~XGBE_AN_PG_RCV; - } else if (pdata->an_int & XGBE_AN_INC_LINK) { + pdata->an_int &= ~XGBE_AN_CL73_PG_RCV; + } else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) { pdata->an_state = XGBE_AN_INCOMPAT_LINK; - pdata->an_int &= ~XGBE_AN_INC_LINK; - } else if (pdata->an_int & XGBE_AN_INT_CMPLT) { + pdata->an_int &= ~XGBE_AN_CL73_INC_LINK; + } else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) { pdata->an_state = XGBE_AN_COMPLETE; - pdata->an_int &= ~XGBE_AN_INT_CMPLT; + pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT; } else { pdata->an_state = XGBE_AN_ERROR; } @@ -657,14 +548,14 @@ break; case XGBE_AN_PAGE_RECEIVED: - pdata->an_state = xgbe_an_page_received(pdata); + pdata->an_state = xgbe_an73_page_received(pdata); pdata->an_supported++; break; case XGBE_AN_INCOMPAT_LINK: pdata->an_supported = 0; pdata->parallel_detect = 0; - pdata->an_state = xgbe_an_incompat_link(pdata); + pdata->an_state = xgbe_an73_incompat_link(pdata); break; case XGBE_AN_COMPLETE: @@ -680,10 +571,10 @@ if (pdata->an_state == XGBE_AN_NO_LINK) { pdata->an_int = 0; - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); + xgbe_an73_clear_interrupts(pdata); } else if (pdata->an_state == XGBE_AN_ERROR) { pdata->an_int = 0; - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); + xgbe_an73_clear_interrupts(pdata); } if (pdata->an_state >= XGBE_AN_COMPLETE) { @@ -702,30 +593,49 @@ out: /* Enable AN interrupts on the way out */ - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_INT_MASK); + xgbe_an73_enable_interrupts(pdata); +} + +static void xgbe_an_state_machine(struct xgbe_prv_data *pdata) +{ + sx_xlock(&pdata->an_mutex); + + switch (pdata->an_mode) { + case XGBE_AN_MODE_CL73: + xgbe_an73_state_machine(pdata); + break; + default: + break; + } sx_xunlock(&pdata->an_mutex); } -static void xgbe_an_init(struct xgbe_prv_data *pdata) +static void xgbe_an73_init(struct xgbe_prv_data *pdata) { + struct xgbe_phy local_phy; unsigned int reg; + pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy); + /* Set up Advertisement register 3 first */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); - reg &= ~0xc000; + if (XGBE_ADV(&local_phy, 10000baseR_FEC)) + reg |= 0xc000; + else + reg &= ~0xc000; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg); /* Set up Advertisement register 2 next */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); - if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) + if (XGBE_ADV(&local_phy, 10000baseKR_Full)) reg |= 0x80; else reg &= ~0x80; - if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) || - (pdata->phy.advertising & ADVERTISED_2500baseX_Full)) + if (XGBE_ADV(&local_phy, 1000baseKX_Full) || + XGBE_ADV(&local_phy, 2500baseX_Full)) reg |= 0x20; else reg &= ~0x20; @@ -734,12 +644,12 @@ /* Set up Advertisement register 1 last */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); - if (pdata->phy.advertising & ADVERTISED_Pause) + if (XGBE_ADV(&local_phy, Pause)) reg |= 0x400; else reg &= ~0x400; - if (pdata->phy.advertising & ADVERTISED_Asym_Pause) + if (XGBE_ADV(&local_phy, Asym_Pause)) reg |= 0x800; else reg &= ~0x800; @@ -750,72 +660,145 @@ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); } +static void xgbe_an_init(struct xgbe_prv_data *pdata) +{ + /* Set up advertisement registers based on current settings */ + pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata); + + switch (pdata->an_mode) { + case XGBE_AN_MODE_CL73: + xgbe_an73_init(pdata); + break; + default: + break; + } +} + +static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata) +{ + if (pdata->tx_pause && pdata->rx_pause) + return "rx/tx"; + else if (pdata->rx_pause) + return "rx"; + else if (pdata->tx_pause) + return "tx"; + else + return "off"; +} + +static const char *xgbe_phy_speed_string(int speed) +{ + switch (speed) { + case SPEED_1000: + return "1Gbps"; + case SPEED_2500: + return "2.5Gbps"; + case SPEED_10000: + return "10Gbps"; + case SPEED_UNKNOWN: + return "Unknown"; + default: + return "Unsupported"; + } +} + +static void xgbe_phy_print_status(struct xgbe_prv_data *pdata) +{ + if (pdata->phy.link) + device_printf(pdata->dev, + "Link is CONNECTED - %s/%s - flow control %s\n", + xgbe_phy_speed_string(pdata->phy.speed), + pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half", + xgbe_phy_fc_string(pdata)); + else + device_printf(pdata->dev, "Link is NOT CONNECTED\n"); +} + static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata) { + int new_state = 0; if (pdata->phy.link) { /* Flow control support */ pdata->pause_autoneg = pdata->phy.pause_autoneg; if (pdata->tx_pause != pdata->phy.tx_pause) { + new_state = 1; pdata->hw_if.config_tx_flow_control(pdata); pdata->tx_pause = pdata->phy.tx_pause; } if (pdata->rx_pause != pdata->phy.rx_pause) { + new_state = 1; pdata->hw_if.config_rx_flow_control(pdata); pdata->rx_pause = pdata->phy.rx_pause; } /* Speed support */ if (pdata->phy_speed != pdata->phy.speed) { + new_state = 1; pdata->phy_speed = pdata->phy.speed; } if (pdata->phy_link != pdata->phy.link) { + new_state = 1; pdata->phy_link = pdata->phy.link; } } else if (pdata->phy_link) { + new_state = 1; pdata->phy_link = 0; pdata->phy_speed = SPEED_UNKNOWN; } + + if (new_state) + xgbe_phy_print_status(pdata); } static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) { + enum xgbe_mode mode; /* Disable auto-negotiation */ - xgbe_disable_an(pdata); - - /* Validate/Set specified speed */ - switch (pdata->phy.speed) { - case SPEED_10000: - xgbe_set_mode(pdata, XGBE_MODE_KR); - break; - - case SPEED_2500: - case SPEED_1000: - xgbe_set_mode(pdata, XGBE_MODE_KX); + xgbe_an_disable(pdata); + + /* Set specified speed */ + mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed); + switch (mode) { + case XGBE_MODE_KX_1000: + case XGBE_MODE_KX_2500: + case XGBE_MODE_KR: + xgbe_set_mode(pdata, mode); break; - + case XGBE_MODE_UNKNOWN: default: - return -EINVAL; + return (-EINVAL); } /* Validate duplex mode */ if (pdata->phy.duplex != DUPLEX_FULL) - return -EINVAL; + return (-EINVAL); - return 0; + return (0); } -static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) +static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode) { + int ret; + + sx_xlock(&pdata->an_mutex); + set_bit(XGBE_LINK_INIT, &pdata->dev_state); pdata->link_check = ticks; - if (pdata->phy.autoneg != AUTONEG_ENABLE) - return xgbe_phy_config_fixed(pdata); + ret = pdata->phy_if.phy_impl.an_config(pdata); + if (ret) + goto out; + + if (pdata->phy.autoneg != AUTONEG_ENABLE) { + ret = xgbe_phy_config_fixed(pdata); + if (ret || !pdata->kr_redrv) + goto out; + } /* Disable auto-negotiation interrupt */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); @@ -824,18 +807,23 @@ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); /* Start auto-negotiation in a supported mode */ - if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) { - xgbe_set_mode(pdata, XGBE_MODE_KR); - } else if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) || - (pdata->phy.advertising & ADVERTISED_2500baseX_Full)) { - xgbe_set_mode(pdata, XGBE_MODE_KX); - } else { - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); - return -EINVAL; + if (set_mode) { + /* Start auto-negotiation in a supported mode */ + if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { + xgbe_set_mode(pdata, XGBE_MODE_KR); + } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { + xgbe_set_mode(pdata, XGBE_MODE_KX_2500); + } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { + xgbe_set_mode(pdata, XGBE_MODE_KX_1000); + } else { + XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); + ret = -EINVAL; + goto out; + } } /* Disable and stop any in progress auto-negotiation */ - xgbe_disable_an(pdata); + xgbe_an_disable_all(pdata); /* Clear any auto-negotitation interrupts */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); @@ -852,18 +840,9 @@ xgbe_an_init(pdata); /* Enable and start auto-negotiation */ - xgbe_restart_an(pdata); - - return 0; -} - -static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) -{ - int ret; - - sx_xlock(&pdata->an_mutex); + xgbe_an_restart(pdata); - ret = __xgbe_phy_config_aneg(pdata); +out: if (ret) set_bit(XGBE_LINK_ERR, &pdata->dev_state); else @@ -871,7 +850,17 @@ sx_unlock(&pdata->an_mutex); - return ret; + return (ret); +} + +static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) +{ + return __xgbe_phy_config_aneg(pdata, true); +} + +static int xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata) +{ + return __xgbe_phy_config_aneg(pdata, false); } static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata) @@ -889,104 +878,47 @@ } } -static void xgbe_phy_status_force(struct xgbe_prv_data *pdata) +static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata) { - if (xgbe_in_kr_mode(pdata)) { - pdata->phy.speed = SPEED_10000; - } else { - switch (pdata->speed_set) { - case XGBE_SPEEDSET_1000_10000: - pdata->phy.speed = SPEED_1000; - break; - - case XGBE_SPEEDSET_2500_10000: - pdata->phy.speed = SPEED_2500; - break; - } - } - pdata->phy.duplex = DUPLEX_FULL; + return pdata->phy_if.phy_impl.an_outcome(pdata); } -static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata) +static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) { - unsigned int ad_reg, lp_reg; + enum xgbe_mode mode; - pdata->phy.lp_advertising = 0; + XGBE_ZERO_LP_ADV(&pdata->phy); if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect) - return xgbe_phy_status_force(pdata); - - pdata->phy.lp_advertising |= ADVERTISED_Autoneg; - pdata->phy.lp_advertising |= ADVERTISED_Backplane; - - /* Compare Advertisement and Link Partner register 1 */ - ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); - lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); - if (lp_reg & 0x400) - pdata->phy.lp_advertising |= ADVERTISED_Pause; - if (lp_reg & 0x800) - pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; - - if (pdata->phy.pause_autoneg) { - /* Set flow control based on auto-negotiation result */ - pdata->phy.tx_pause = 0; - pdata->phy.rx_pause = 0; - - if (ad_reg & lp_reg & 0x400) { - pdata->phy.tx_pause = 1; - pdata->phy.rx_pause = 1; - } else if (ad_reg & lp_reg & 0x800) { - if (ad_reg & 0x400) - pdata->phy.rx_pause = 1; - else if (lp_reg & 0x400) - pdata->phy.tx_pause = 1; - } - } - - /* Compare Advertisement and Link Partner register 2 */ - ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); - lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); - if (lp_reg & 0x80) - pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; - if (lp_reg & 0x20) { - switch (pdata->speed_set) { - case XGBE_SPEEDSET_1000_10000: - pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; - break; - case XGBE_SPEEDSET_2500_10000: - pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full; - break; - } - } + mode = xgbe_cur_mode(pdata); + else + mode = xgbe_phy_status_aneg(pdata); - ad_reg &= lp_reg; - if (ad_reg & 0x80) { + switch (mode) { + case XGBE_MODE_KX_1000: + pdata->phy.speed = SPEED_1000; + break; + case XGBE_MODE_KX_2500: + pdata->phy.speed = SPEED_2500; + break; + case XGBE_MODE_KR: pdata->phy.speed = SPEED_10000; - xgbe_set_mode(pdata, XGBE_MODE_KR); - } else if (ad_reg & 0x20) { - switch (pdata->speed_set) { - case XGBE_SPEEDSET_1000_10000: - pdata->phy.speed = SPEED_1000; - break; - - case XGBE_SPEEDSET_2500_10000: - pdata->phy.speed = SPEED_2500; - break; - } - - xgbe_set_mode(pdata, XGBE_MODE_KX); - } else { + break; + case XGBE_MODE_UNKNOWN: + default: pdata->phy.speed = SPEED_UNKNOWN; } - /* Compare Advertisement and Link Partner register 3 */ - ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); - lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); + pdata->phy.duplex = DUPLEX_FULL; + + if (xgbe_set_mode(pdata, mode) && pdata->an_again) + xgbe_phy_reconfig_aneg(pdata); } static void xgbe_phy_status(struct xgbe_prv_data *pdata) { - unsigned int reg, link_aneg; + bool link_aneg; + int an_restart; if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) { pdata->phy.link = 0; @@ -998,9 +930,8 @@ /* Get the link status. Link status is latched low, so read * once to clear and then read again to get current state */ - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); - pdata->phy.link = (reg & MDIO_STAT1_LSTATUS) ? 1 : 0; + pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata, + &an_restart); if (pdata->phy.link) { if (link_aneg && !xgbe_phy_aneg_done(pdata)) { @@ -1008,7 +939,7 @@ return; } - xgbe_phy_status_aneg(pdata); + xgbe_phy_status_result(pdata); if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) clear_bit(XGBE_LINK_INIT, &pdata->dev_state); @@ -1020,7 +951,7 @@ return; } - xgbe_phy_status_aneg(pdata); + xgbe_phy_status_result(pdata); } adjust_link: @@ -1029,15 +960,19 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata) { + if (!pdata->phy_started) + return; - /* Disable auto-negotiation */ - xgbe_disable_an(pdata); + /* Indicate the PHY is down */ + pdata->phy_started = 0; - /* Disable auto-negotiation interrupts */ - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); + /* Disable auto-negotiation */ + xgbe_an_disable_all(pdata); bus_teardown_intr(pdata->dev, pdata->an_irq_res, pdata->an_irq_tag); + pdata->phy_if.phy_impl.stop(pdata); + pdata->phy.link = 0; xgbe_phy_adjust_link(pdata); @@ -1047,94 +982,96 @@ { int ret; + ret = pdata->phy_if.phy_impl.start(pdata); + if (ret) { + device_printf(pdata->dev, "%s: impl start ret %d\n", __func__, ret); + return (-ret); + } + ret = bus_setup_intr(pdata->dev, pdata->an_irq_res, INTR_MPSAFE | INTR_TYPE_NET, NULL, xgbe_an_isr, pdata, &pdata->an_irq_tag); if (ret) { - return -ret; + return (-ret); } /* Set initial mode - call the mode setting routines * directly to insure we are properly configured */ - if (xgbe_use_xgmii_mode(pdata)) { - xgbe_xgmii_mode(pdata); - } else if (xgbe_use_gmii_mode(pdata)) { - xgbe_gmii_mode(pdata); - } else if (xgbe_use_gmii_2500_mode(pdata)) { - xgbe_gmii_2500_mode(pdata); + if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { + xgbe_kr_mode(pdata); + } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { + xgbe_kx_2500_mode(pdata); + } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { + xgbe_kx_1000_mode(pdata); } else { ret = -EINVAL; - goto err_irq; + goto err_stop; } + /* Indicate the PHY is up and running */ + pdata->phy_started = 1; + /* Set up advertisement registers based on current settings */ xgbe_an_init(pdata); /* Enable auto-negotiation interrupts */ - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); + xgbe_an_enable_interrupts(pdata); return xgbe_phy_config_aneg(pdata); -err_irq: +err_stop: bus_teardown_intr(pdata->dev, pdata->an_irq_res, pdata->an_irq_tag); - return ret; + pdata->phy_if.phy_impl.stop(pdata); + + return (ret); } static int xgbe_phy_reset(struct xgbe_prv_data *pdata) { - unsigned int count, reg; - - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); - reg |= MDIO_CTRL1_RESET; - XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); - - count = 50; - do { - DELAY(20); - reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); - } while ((reg & MDIO_CTRL1_RESET) && --count); + int ret; - if (reg & MDIO_CTRL1_RESET) - return -ETIMEDOUT; + ret = pdata->phy_if.phy_impl.reset(pdata); + if (ret) { + device_printf(pdata->dev, "%s: impl phy reset %d\n", __func__, ret); + return (ret); + } /* Disable auto-negotiation for now */ - xgbe_disable_an(pdata); + xgbe_an_disable_all(pdata); /* Clear auto-negotiation interrupts */ - XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); + xgbe_an_clear_interrupts_all(pdata); - return 0; + return (0); } -static void xgbe_phy_init(struct xgbe_prv_data *pdata) +static void xgbe_phy_exit(struct xgbe_prv_data *pdata) { + pdata->phy_if.phy_impl.exit(pdata); +} + +static int xgbe_phy_init(struct xgbe_prv_data *pdata) +{ + int ret = 0; + sx_init(&pdata->an_mutex, "axgbe AN lock"); pdata->mdio_mmd = MDIO_MMD_PCS; /* Initialize supported features */ - pdata->phy.supported = SUPPORTED_Autoneg; - pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; - pdata->phy.supported |= SUPPORTED_Backplane; - pdata->phy.supported |= SUPPORTED_10000baseKR_Full; - switch (pdata->speed_set) { - case XGBE_SPEEDSET_1000_10000: - pdata->phy.supported |= SUPPORTED_1000baseKX_Full; - break; - case XGBE_SPEEDSET_2500_10000: - pdata->phy.supported |= SUPPORTED_2500baseX_Full; - break; - } - pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECABLE); pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE); - if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) - pdata->phy.supported |= SUPPORTED_10000baseR_FEC; - pdata->phy.advertising = pdata->phy.supported; + /* Setup the phy (including supported features) */ + ret = pdata->phy_if.phy_impl.init(pdata); + if (ret) + return (ret); + + /* Copy supported link modes to advertising link modes */ + XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, supported); pdata->phy.address = 0; @@ -1149,25 +1086,33 @@ pdata->phy.rx_pause = pdata->rx_pause; /* Fix up Flow Control advertising */ - pdata->phy.advertising &= ~ADVERTISED_Pause; - pdata->phy.advertising &= ~ADVERTISED_Asym_Pause; + XGBE_CLR_ADV(&pdata->phy, Pause); + XGBE_CLR_ADV(&pdata->phy, Asym_Pause); if (pdata->rx_pause) { - pdata->phy.advertising |= ADVERTISED_Pause; - pdata->phy.advertising |= ADVERTISED_Asym_Pause; + XGBE_SET_ADV(&pdata->phy, Pause); + XGBE_SET_ADV(&pdata->phy, Asym_Pause); + } + + if (pdata->tx_pause) { + /* Equivalent to XOR of Asym_Pause */ + if (XGBE_ADV(&pdata->phy, Asym_Pause)) + XGBE_CLR_ADV(&pdata->phy, Asym_Pause); + else + XGBE_SET_ADV(&pdata->phy, Asym_Pause); } - if (pdata->tx_pause) - pdata->phy.advertising ^= ADVERTISED_Asym_Pause; + return (0); } void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if) { - phy_if->phy_init = xgbe_phy_init; + phy_if->phy_init = xgbe_phy_init; + phy_if->phy_exit = xgbe_phy_exit; phy_if->phy_reset = xgbe_phy_reset; phy_if->phy_start = xgbe_phy_start; - phy_if->phy_stop = xgbe_phy_stop; + phy_if->phy_stop = xgbe_phy_stop; phy_if->phy_status = xgbe_phy_status; phy_if->phy_config_aneg = xgbe_phy_config_aneg; Index: sys/dev/axgbe/xgbe-phy-v1.c =================================================================== --- /dev/null +++ sys/dev/axgbe/xgbe-phy-v1.c @@ -0,0 +1,757 @@ +/* + * AMD 10Gb Ethernet driver + * + * This file is available to you under your choice of the following two + * licenses: + * + * License 1: GPLv2 + * + * Copyright (c) 2016 Advanced Micro Devices, Inc. + * + * This file is free software; you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or (at + * your option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * The Synopsys DWC ETHER XGMAC Software Driver and documentation + * (hereinafter "Software") is an unsupported proprietary work of Synopsys, + * Inc. unless otherwise expressly agreed to in writing between Synopsys + * and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for Licensed + * Product with Synopsys or any supplement thereto. Permission is hereby + * granted, free of charge, to any person obtaining a copy of this software + * annotated with this license and the Software, to deal in the Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * + * License 2: Modified BSD + * + * Copyright (c) 2016 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Advanced Micro Devices, Inc. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * The Synopsys DWC ETHER XGMAC Software Driver and documentation + * (hereinafter "Software") is an unsupported proprietary work of Synopsys, + * Inc. unless otherwise expressly agreed to in writing between Synopsys + * and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for Licensed + * Product with Synopsys or any supplement thereto. Permission is hereby + * granted, free of charge, to any person obtaining a copy of this software + * annotated with this license and the Software, to deal in the Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include "xgbe.h" +#include "xgbe-common.h" + +extern unsigned int g_axgbe_debug_level; + +struct xgbe_phy_data { + /* 1000/10000 vs 2500/10000 indicator */ + unsigned int speed_set; + + /* SerDes UEFI configurable settings. + * Switching between modes/speeds requires new values for some + * SerDes settings. The values can be supplied as device + * properties in array format. The first array entry is for + * 1GbE, second for 2.5GbE and third for 10GbE + */ + u32 blwc[XGBE_SPEEDS]; + u32 cdr_rate[XGBE_SPEEDS]; + u32 pq_skew[XGBE_SPEEDS]; + u32 tx_amp[XGBE_SPEEDS]; + u32 dfe_tap_cfg[XGBE_SPEEDS]; + u32 dfe_tap_ena[XGBE_SPEEDS]; +}; + +static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata) +{ + XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 1); +} + +static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) +{ + XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 0); +} + +static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + enum xgbe_mode mode; + unsigned int ad_reg, lp_reg; + + XGBE_SET_LP_ADV(&pdata->phy, Autoneg); + XGBE_SET_LP_ADV(&pdata->phy, Backplane); + + /* Compare Advertisement and Link Partner register 1 */ + ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); + lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); + if (lp_reg & 0x400) + XGBE_SET_LP_ADV(&pdata->phy, Pause); + if (lp_reg & 0x800) + XGBE_SET_LP_ADV(&pdata->phy, Asym_Pause); + + device_printf(pdata->dev, "%s: pause_autoneg %d ad_reg 0x%x lp_reg 0x%x\n", + __func__, pdata->phy.pause_autoneg, ad_reg, lp_reg); + + if (pdata->phy.pause_autoneg) { + /* Set flow control based on auto-negotiation result */ + pdata->phy.tx_pause = 0; + pdata->phy.rx_pause = 0; + + if (ad_reg & lp_reg & 0x400) { + pdata->phy.tx_pause = 1; + pdata->phy.rx_pause = 1; + } else if (ad_reg & lp_reg & 0x800) { + if (ad_reg & 0x400) + pdata->phy.rx_pause = 1; + else if (lp_reg & 0x400) + pdata->phy.tx_pause = 1; + } + } + + /* Compare Advertisement and Link Partner register 2 */ + ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); + lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); + if (lp_reg & 0x80) + XGBE_SET_LP_ADV(&pdata->phy, 10000baseKR_Full); + if (lp_reg & 0x20) { + if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) + XGBE_SET_LP_ADV(&pdata->phy, 2500baseX_Full); + else + XGBE_SET_LP_ADV(&pdata->phy, 1000baseKX_Full); + } + + ad_reg &= lp_reg; + if (ad_reg & 0x80) { + pdata->phy.speed = SPEED_10000; + mode = XGBE_MODE_KR; + } else if (ad_reg & 0x20) { + switch (phy_data->speed_set) { + case XGBE_SPEEDSET_1000_10000: + pdata->phy.speed = SPEED_1000; + mode = XGBE_MODE_KX_1000; + break; + case XGBE_SPEEDSET_2500_10000: + pdata->phy.speed = SPEED_2500; + mode = XGBE_MODE_KX_2500; + break; + } + } else { + mode = XGBE_MODE_UNKNOWN; + pdata->phy.speed = SPEED_UNKNOWN; + } + + /* Compare Advertisement and Link Partner register 3 */ + ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); + lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); + if (lp_reg & 0xc000) + XGBE_SET_LP_ADV(&pdata->phy, 10000baseR_FEC); + + return (mode); +} + +static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata, + struct xgbe_phy *dphy) +{ + XGBE_LM_COPY(dphy, advertising, &pdata->phy, advertising); +} + +static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) +{ + /* Nothing uniquely required for an configuration */ + return 0; +} + +static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata) +{ + return XGBE_AN_MODE_CL73; +} + +static void xgbe_phy_pcs_power_cycle(struct xgbe_prv_data *pdata) +{ + unsigned int reg; + + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); + + reg |= MDIO_CTRL1_LPOWER; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); + + DELAY(75); + + reg &= ~MDIO_CTRL1_LPOWER; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); +} + +static void xgbe_phy_start_ratechange(struct xgbe_prv_data *pdata) +{ + /* Assert Rx and Tx ratechange */ + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 1); +} + +static void xgbe_phy_complete_ratechange(struct xgbe_prv_data *pdata) +{ + unsigned int wait; + u16 status; + + /* Release Rx and Tx ratechange */ + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 0); + + /* Wait for Rx and Tx ready */ + wait = XGBE_RATECHANGE_COUNT; + while (wait--) { + DELAY(50); + + status = XSIR0_IOREAD(pdata, SIR0_STATUS); + if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) && + XSIR_GET_BITS(status, SIR0_STATUS, TX_READY)) + goto rx_reset; + } + +rx_reset: + /* Perform Rx reset for the DFE changes */ + XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 0); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 1); +} + +static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int reg; + + /* Set PCS to KR/10G speed */ + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); + reg &= ~MDIO_PCS_CTRL2_TYPE; + reg |= MDIO_PCS_CTRL2_10GBR; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); + + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); + reg &= ~MDIO_CTRL1_SPEEDSEL; + reg |= MDIO_CTRL1_SPEED10G; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); + + xgbe_phy_pcs_power_cycle(pdata); + + /* Set SerDes to 10G speed */ + xgbe_phy_start_ratechange(pdata); + + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_10000_RATE); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_10000_WORD); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_10000_PLL); + + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, + phy_data->cdr_rate[XGBE_SPEED_10000]); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, + phy_data->tx_amp[XGBE_SPEED_10000]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, + phy_data->blwc[XGBE_SPEED_10000]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, + phy_data->pq_skew[XGBE_SPEED_10000]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, + phy_data->dfe_tap_cfg[XGBE_SPEED_10000]); + XRXTX_IOWRITE(pdata, RXTX_REG22, + phy_data->dfe_tap_ena[XGBE_SPEED_10000]); + + xgbe_phy_complete_ratechange(pdata); +} + +static void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int reg; + + /* Set PCS to KX/1G speed */ + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); + reg &= ~MDIO_PCS_CTRL2_TYPE; + reg |= MDIO_PCS_CTRL2_10GBX; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); + + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); + reg &= ~MDIO_CTRL1_SPEEDSEL; + reg |= MDIO_CTRL1_SPEED1G; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); + + xgbe_phy_pcs_power_cycle(pdata); + + /* Set SerDes to 2.5G speed */ + xgbe_phy_start_ratechange(pdata); + + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_2500_RATE); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_2500_WORD); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_2500_PLL); + + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, + phy_data->cdr_rate[XGBE_SPEED_2500]); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, + phy_data->tx_amp[XGBE_SPEED_2500]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, + phy_data->blwc[XGBE_SPEED_2500]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, + phy_data->pq_skew[XGBE_SPEED_2500]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, + phy_data->dfe_tap_cfg[XGBE_SPEED_2500]); + XRXTX_IOWRITE(pdata, RXTX_REG22, + phy_data->dfe_tap_ena[XGBE_SPEED_2500]); + + xgbe_phy_complete_ratechange(pdata); +} + +static void xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + unsigned int reg; + + /* Set PCS to KX/1G speed */ + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); + reg &= ~MDIO_PCS_CTRL2_TYPE; + reg |= MDIO_PCS_CTRL2_10GBX; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); + + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); + reg &= ~MDIO_CTRL1_SPEEDSEL; + reg |= MDIO_CTRL1_SPEED1G; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); + + xgbe_phy_pcs_power_cycle(pdata); + + /* Set SerDes to 1G speed */ + xgbe_phy_start_ratechange(pdata); + + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_1000_RATE); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_1000_WORD); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_1000_PLL); + + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, + phy_data->cdr_rate[XGBE_SPEED_1000]); + XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, + phy_data->tx_amp[XGBE_SPEED_1000]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, + phy_data->blwc[XGBE_SPEED_1000]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, + phy_data->pq_skew[XGBE_SPEED_1000]); + XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, + phy_data->dfe_tap_cfg[XGBE_SPEED_1000]); + XRXTX_IOWRITE(pdata, RXTX_REG22, + phy_data->dfe_tap_ena[XGBE_SPEED_1000]); + + xgbe_phy_complete_ratechange(pdata); +} + +static enum xgbe_mode xgbe_phy_cur_mode(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + enum xgbe_mode mode; + unsigned int reg; + + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); + reg &= MDIO_PCS_CTRL2_TYPE; + + if (reg == MDIO_PCS_CTRL2_10GBR) { + mode = XGBE_MODE_KR; + } else { + if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) + mode = XGBE_MODE_KX_2500; + else + mode = XGBE_MODE_KX_1000; + } + + return mode; +} + +static enum xgbe_mode xgbe_phy_switch_mode(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + enum xgbe_mode mode; + + /* If we are in KR switch to KX, and vice-versa */ + if (xgbe_phy_cur_mode(pdata) == XGBE_MODE_KR) { + if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) + mode = XGBE_MODE_KX_2500; + else + mode = XGBE_MODE_KX_1000; + } else { + mode = XGBE_MODE_KR; + } + + return mode; +} + +static enum xgbe_mode xgbe_phy_get_mode(struct xgbe_prv_data *pdata, + int speed) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + switch (speed) { + case SPEED_1000: + return (phy_data->speed_set == XGBE_SPEEDSET_1000_10000) + ? XGBE_MODE_KX_1000 : XGBE_MODE_UNKNOWN; + case SPEED_2500: + return (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) + ? XGBE_MODE_KX_2500 : XGBE_MODE_UNKNOWN; + case SPEED_10000: + return XGBE_MODE_KR; + default: + return XGBE_MODE_UNKNOWN; + } +} + +static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) +{ + switch (mode) { + case XGBE_MODE_KX_1000: + xgbe_phy_kx_1000_mode(pdata); + break; + case XGBE_MODE_KX_2500: + xgbe_phy_kx_2500_mode(pdata); + break; + case XGBE_MODE_KR: + xgbe_phy_kr_mode(pdata); + break; + default: + break; + } +} + +static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, + enum xgbe_mode mode, bool advert) +{ + if (pdata->phy.autoneg == AUTONEG_ENABLE) { + return advert; + } else { + enum xgbe_mode cur_mode; + + cur_mode = xgbe_phy_get_mode(pdata, pdata->phy.speed); + if (cur_mode == mode) + return true; + } + + return false; +} + +static bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) +{ + + switch (mode) { + case XGBE_MODE_KX_1000: + return xgbe_phy_check_mode(pdata, mode, + XGBE_ADV(&pdata->phy, 1000baseKX_Full)); + case XGBE_MODE_KX_2500: + return xgbe_phy_check_mode(pdata, mode, + XGBE_ADV(&pdata->phy, 2500baseX_Full)); + case XGBE_MODE_KR: + return xgbe_phy_check_mode(pdata, mode, + XGBE_ADV(&pdata->phy, 10000baseKR_Full)); + default: + return false; + } +} + +static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + switch (speed) { + case SPEED_1000: + if (phy_data->speed_set != XGBE_SPEEDSET_1000_10000) + return false; + return true; + case SPEED_2500: + if (phy_data->speed_set != XGBE_SPEEDSET_2500_10000) + return false; + return true; + case SPEED_10000: + return true; + default: + return false; + } +} + +static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) +{ + unsigned int reg; + + *an_restart = 0; + + /* Link status is latched low, so read once to clear + * and then read again to get current state + */ + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); + + return (reg & MDIO_STAT1_LSTATUS) ? 1 : 0; +} + +static void xgbe_phy_stop(struct xgbe_prv_data *pdata) +{ + /* Nothing uniquely required for stop */ +} + +static int xgbe_phy_start(struct xgbe_prv_data *pdata) +{ + /* Nothing uniquely required for start */ + return 0; +} + +static int xgbe_phy_reset(struct xgbe_prv_data *pdata) +{ + unsigned int reg, count; + + /* Perform a software reset of the PCS */ + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); + reg |= MDIO_CTRL1_RESET; + XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); + + count = 50; + do { + DELAY(20); + reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); + } while ((reg & MDIO_CTRL1_RESET) && --count); + + if (reg & MDIO_CTRL1_RESET) + return -ETIMEDOUT; + + return 0; +} + +static void xgbe_phy_exit(struct xgbe_prv_data *pdata) +{ + /* Nothing uniquely required for exit */ + + /* free phy_data structure */ + free(pdata->phy_data, M_AXGBE); +} + +static int +xgbe_get_optional_prop(struct xgbe_prv_data *pdata, const char *name, int *data, + size_t len) +{ + + if (!OF_hasprop(pdata->phy_node, name)) + return (-1); + + if (OF_getencprop(pdata->phy_node, name, data, len) <= 0) { + device_printf(pdata->dev,"%s property is invalid\n", name); + return (ENXIO); + } + + return (0); +} + +static int xgbe_phy_init(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data; + int error = 0; + + phy_data = malloc(sizeof(*phy_data), M_AXGBE, M_WAITOK | M_ZERO); + + /* + * Read the needed properties from the phy node. + */ + + /* This is documented as optional, but Linux requires it */ + if (OF_getencprop(pdata->phy_node, XGBE_SPEEDSET_PROPERTY, + &phy_data->speed_set, sizeof(phy_data->speed_set)) <= 0) { + device_printf(pdata->dev, "%s property is missing\n", + XGBE_SPEEDSET_PROPERTY); + return (EINVAL); + } + + error = xgbe_get_optional_prop(pdata, XGBE_BLWC_PROPERTY, + phy_data->blwc, sizeof(phy_data->blwc)); + if (error > 0) { + return (error); + } else if (error < 0) { + phy_data->blwc[0] = XGBE_SPEED_1000_BLWC; + phy_data->blwc[1] = XGBE_SPEED_2500_BLWC; + phy_data->blwc[2] = XGBE_SPEED_10000_BLWC; + } + + error = xgbe_get_optional_prop(pdata, XGBE_CDR_RATE_PROPERTY, + phy_data->cdr_rate, sizeof(phy_data->cdr_rate)); + if (error > 0) { + return (error); + } else if (error < 0) { + phy_data->cdr_rate[0] = XGBE_SPEED_1000_CDR; + phy_data->cdr_rate[1] = XGBE_SPEED_2500_CDR; + phy_data->cdr_rate[2] = XGBE_SPEED_10000_CDR; + } + + error = xgbe_get_optional_prop(pdata, XGBE_PQ_SKEW_PROPERTY, + phy_data->pq_skew, sizeof(phy_data->pq_skew)); + if (error > 0) { + return (error); + } else if (error < 0) { + phy_data->pq_skew[0] = XGBE_SPEED_1000_PQ; + phy_data->pq_skew[1] = XGBE_SPEED_2500_PQ; + phy_data->pq_skew[2] = XGBE_SPEED_10000_PQ; + } + + error = xgbe_get_optional_prop(pdata, XGBE_TX_AMP_PROPERTY, + phy_data->tx_amp, sizeof(phy_data->tx_amp)); + if (error > 0) { + return (error); + } else if (error < 0) { + phy_data->tx_amp[0] = XGBE_SPEED_1000_TXAMP; + phy_data->tx_amp[1] = XGBE_SPEED_2500_TXAMP; + phy_data->tx_amp[2] = XGBE_SPEED_10000_TXAMP; + } + + error = xgbe_get_optional_prop(pdata, XGBE_DFE_CFG_PROPERTY, + phy_data->dfe_tap_cfg, sizeof(phy_data->dfe_tap_cfg)); + if (error > 0) { + return (error); + } else if (error < 0) { + phy_data->dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG; + phy_data->dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG; + phy_data->dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG; + } + + error = xgbe_get_optional_prop(pdata, XGBE_DFE_ENA_PROPERTY, + phy_data->dfe_tap_ena, sizeof(phy_data->dfe_tap_ena)); + if (error > 0) { + return (error); + } else if (error < 0) { + phy_data->dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE; + phy_data->dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE; + phy_data->dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE; + } + + /* Initialize supported features */ + XGBE_ZERO_SUP(&pdata->phy); + XGBE_SET_SUP(&pdata->phy, Autoneg); + XGBE_SET_SUP(&pdata->phy, Pause); + XGBE_SET_SUP(&pdata->phy, Asym_Pause); + XGBE_SET_SUP(&pdata->phy, Backplane); + XGBE_SET_SUP(&pdata->phy, 10000baseKR_Full); + switch (phy_data->speed_set) { + case XGBE_SPEEDSET_1000_10000: + XGBE_SET_SUP(&pdata->phy, 1000baseKX_Full); + break; + case XGBE_SPEEDSET_2500_10000: + XGBE_SET_SUP(&pdata->phy, 2500baseX_Full); + break; + } + + if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) + XGBE_SET_SUP(&pdata->phy, 10000baseR_FEC); + + pdata->phy_data = phy_data; + + return 0; +} + +void xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *phy_if) +{ + struct xgbe_phy_impl_if *phy_impl = &phy_if->phy_impl; + + phy_impl->init = xgbe_phy_init; + phy_impl->exit = xgbe_phy_exit; + + phy_impl->reset = xgbe_phy_reset; + phy_impl->start = xgbe_phy_start; + phy_impl->stop = xgbe_phy_stop; + + phy_impl->link_status = xgbe_phy_link_status; + + phy_impl->valid_speed = xgbe_phy_valid_speed; + + phy_impl->use_mode = xgbe_phy_use_mode; + phy_impl->set_mode = xgbe_phy_set_mode; + phy_impl->get_mode = xgbe_phy_get_mode; + phy_impl->switch_mode = xgbe_phy_switch_mode; + phy_impl->cur_mode = xgbe_phy_cur_mode; + + phy_impl->an_mode = xgbe_phy_an_mode; + + phy_impl->an_config = xgbe_phy_an_config; + + phy_impl->an_advertising = xgbe_phy_an_advertising; + + phy_impl->an_outcome = xgbe_phy_an_outcome; + + phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; + phy_impl->kr_training_post = xgbe_phy_kr_training_post; +} Index: sys/dev/axgbe/xgbe.h =================================================================== --- sys/dev/axgbe/xgbe.h +++ sys/dev/axgbe/xgbe.h @@ -119,6 +119,10 @@ #ifndef __XGBE_H__ #define __XGBE_H__ +#include +#include +#include + #include "xgbe_osdep.h" /* From linux/dcbnl.h */ @@ -281,6 +285,46 @@ #define XGBE_SPEED_1000_DFE_TAP_CONFIG 0x3 #define XGBE_SPEED_1000_DFE_TAP_ENABLE 0x0 +/* Link mode bit operations */ +#define XGBE_ZERO_SUP(_phy) \ + ((_phy)->supported = 0) + +#define XGBE_SET_SUP(_phy, _mode) \ + ((_phy)->supported |= SUPPORTED_##_mode) + +#define XGBE_CLR_SUP(_phy, _mode) \ + ((_phy)->supported &= ~SUPPORTED_##_mode) + +#define XGBE_IS_SUP(_phy, _mode) \ + ((_phy)->supported & SUPPORTED_##_mode) + +#define XGBE_ZERO_ADV(_phy) \ + ((_phy)->advertising = 0) + +#define XGBE_SET_ADV(_phy, _mode) \ + ((_phy)->advertising |= ADVERTISED_##_mode) + +#define XGBE_CLR_ADV(_phy, _mode) \ + ((_phy)->advertising &= ~ADVERTISED_##_mode) + +#define XGBE_ADV(_phy, _mode) \ + ((_phy)->advertising & ADVERTISED_##_mode) + +#define XGBE_ZERO_LP_ADV(_phy) \ + ((_phy)->lp_advertising = 0) + +#define XGBE_SET_LP_ADV(_phy, _mode) \ + ((_phy)->lp_advertising |= ADVERTISED_##_mode) + +#define XGBE_CLR_LP_ADV(_phy, _mode) \ + ((_phy)->lp_advertising &= ~ADVERTISED_##_mode) + +#define XGBE_LP_ADV(_phy, _mode) \ + ((_phy)->lp_advertising & ADVERTISED_##_mode) + +#define XGBE_LM_COPY(_dphy, _dname, _sphy, _sname) \ + ((_dphy)->_dname = (_sphy)->_sname) + struct xgbe_prv_data; struct xgbe_packet_data { @@ -438,6 +482,19 @@ XGBE_SPEEDS, }; +enum xgbe_xpcs_access { + XGBE_XPCS_ACCESS_V1 = 0, + XGBE_XPCS_ACCESS_V2, +}; + +enum xgbe_an_mode { + XGBE_AN_MODE_CL73 = 0, + XGBE_AN_MODE_CL73_REDRV, + XGBE_AN_MODE_CL37, + XGBE_AN_MODE_CL37_SGMII, + XGBE_AN_MODE_NONE, +}; + enum xgbe_an { XGBE_AN_READY = 0, XGBE_AN_PAGE_RECEIVED, @@ -455,8 +512,10 @@ }; enum xgbe_mode { - XGBE_MODE_KR = 0, - XGBE_MODE_KX, + XGBE_MODE_KX_1000 = 0, + XGBE_MODE_KX_2500, + XGBE_MODE_KR, + XGBE_MODE_UNKNOWN, }; enum xgbe_speedset { @@ -552,9 +611,7 @@ int (*read_mmd_regs)(struct xgbe_prv_data *, int, int); void (*write_mmd_regs)(struct xgbe_prv_data *, int, int, int); - int (*set_gmii_speed)(struct xgbe_prv_data *); - int (*set_gmii_2500_speed)(struct xgbe_prv_data *); - int (*set_xgmii_speed)(struct xgbe_prv_data *); + int (*set_speed)(struct xgbe_prv_data *, int); void (*enable_tx)(struct xgbe_prv_data *); void (*disable_tx)(struct xgbe_prv_data *); @@ -619,9 +676,69 @@ int (*disable_rss)(struct xgbe_prv_data *); }; +/* This structure represents implementation specific routines for an + * implementation of a PHY. All routines are required unless noted below. + * Optional routines: + * an_pre, an_post + * kr_training_pre, kr_training_post + * module_info, module_eeprom + */ +struct xgbe_phy_impl_if { + /* Perform Setup/teardown actions */ + int (*init)(struct xgbe_prv_data *); + void (*exit)(struct xgbe_prv_data *); + + /* Perform start/stop specific actions */ + int (*reset)(struct xgbe_prv_data *); + int (*start)(struct xgbe_prv_data *); + void (*stop)(struct xgbe_prv_data *); + + /* Return the link status */ + int (*link_status)(struct xgbe_prv_data *, int *); + + /* Indicate if a particular speed is valid */ + bool (*valid_speed)(struct xgbe_prv_data *, int); + + /* Check if the specified mode can/should be used */ + bool (*use_mode)(struct xgbe_prv_data *, enum xgbe_mode); + /* Switch the PHY into various modes */ + void (*set_mode)(struct xgbe_prv_data *, enum xgbe_mode); + /* Retrieve mode needed for a specific speed */ + enum xgbe_mode (*get_mode)(struct xgbe_prv_data *, int); + /* Retrieve new/next mode when trying to auto-negotiate */ + enum xgbe_mode (*switch_mode)(struct xgbe_prv_data *); + /* Retrieve current mode */ + enum xgbe_mode (*cur_mode)(struct xgbe_prv_data *); + + /* Retrieve current auto-negotiation mode */ + enum xgbe_an_mode (*an_mode)(struct xgbe_prv_data *); + + /* Configure auto-negotiation settings */ + int (*an_config)(struct xgbe_prv_data *); + + /* Set/override auto-negotiation advertisement settings */ + void (*an_advertising)(struct xgbe_prv_data *, struct xgbe_phy *); + + /* Process results of auto-negotiation */ + enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *); + + /* Pre/Post auto-negotiation support */ + void (*an_pre)(struct xgbe_prv_data *); + void (*an_post)(struct xgbe_prv_data *); + + /* Pre/Post KR training enablement support */ + void (*kr_training_pre)(struct xgbe_prv_data *); + void (*kr_training_post)(struct xgbe_prv_data *); + + /* SFP module related info */ + int (*module_info)(struct xgbe_prv_data *pdata); + int (*module_eeprom)(struct xgbe_prv_data *pdata); +}; + struct xgbe_phy_if { /* For initial PHY setup */ - void (*phy_init)(struct xgbe_prv_data *); + int (*phy_init)(struct xgbe_prv_data *); + void (*phy_exit)(struct xgbe_prv_data *); /* For PHY support when setting device up/down */ int (*phy_reset)(struct xgbe_prv_data *); @@ -631,6 +748,9 @@ /* For PHY support while device is up */ void (*phy_status)(struct xgbe_prv_data *); int (*phy_config_aneg)(struct xgbe_prv_data *); + + /* PHY implementation specific services */ + struct xgbe_phy_impl_if phy_impl; }; struct xgbe_desc_if { @@ -690,12 +810,30 @@ unsigned int aux_snap_num; /* Number of Aux snapshot inputs */ }; +struct xgbe_version_data { + void (*init_function_ptrs_phy_impl)(struct xgbe_phy_if *); + enum xgbe_xpcs_access xpcs_access; + unsigned int mmc_64bit; + unsigned int tx_max_fifo_size; + unsigned int rx_max_fifo_size; + unsigned int tx_tstamp_workaround; + unsigned int ecc_support; + unsigned int i2c_support; + unsigned int irq_reissue_support; + unsigned int tx_desc_prefetch; + unsigned int rx_desc_prefetch; + unsigned int an_cdr_workaround; +}; + struct xgbe_prv_data { struct ifnet *netdev; struct platform_device *pdev; struct acpi_device *adev; device_t dev; + /* Version related data */ + struct xgbe_version_data *vdata; + /* ACPI or DT flag */ unsigned int use_acpi; @@ -815,30 +953,19 @@ int phy_speed; /* MDIO/PHY related settings */ + unsigned int phy_started; + void *phy_data; struct xgbe_phy phy; int mdio_mmd; unsigned long link_check; + unsigned int kr_redrv; + char an_name[IFNAMSIZ + 32]; struct resource *an_irq_res; void *an_irq_tag; - unsigned int speed_set; - - /* SerDes UEFI configurable settings. - * Switching between modes/speeds requires new values for some - * SerDes settings. The values can be supplied as device - * properties in array format. The first array entry is for - * 1GbE, second for 2.5GbE and third for 10GbE - */ - u32 serdes_blwc[XGBE_SPEEDS]; - u32 serdes_cdr_rate[XGBE_SPEEDS]; - u32 serdes_pq_skew[XGBE_SPEEDS]; - u32 serdes_tx_amp[XGBE_SPEEDS]; - u32 serdes_dfe_tap_cfg[XGBE_SPEEDS]; - u32 serdes_dfe_tap_ena[XGBE_SPEEDS]; - /* Auto-negotiation state machine support */ unsigned int an_int; struct sx an_mutex; @@ -846,12 +973,15 @@ enum xgbe_an an_state; enum xgbe_rx kr_state; enum xgbe_rx kx_state; + unsigned int an_again; unsigned int an_supported; unsigned int parallel_detect; unsigned int fec_ability; unsigned long an_start; + enum xgbe_an_mode an_mode; unsigned int lpm_ctrl; /* CTRL1 for resume */ + phandle_t phy_node; }; /* Function prototypes*/ @@ -862,6 +992,7 @@ int xgbe_change_mtu(struct ifnet *, int); void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *); void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *); +void xgbe_init_function_ptrs_phy_v1(struct xgbe_phy_if *); void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *); void xgbe_get_all_hw_features(struct xgbe_prv_data *); void xgbe_init_rx_coalesce(struct xgbe_prv_data *); Index: sys/dev/axgbe/xgbe_osdep.h =================================================================== --- sys/dev/axgbe/xgbe_osdep.h +++ sys/dev/axgbe/xgbe_osdep.h @@ -110,13 +110,51 @@ MALLOC_DECLARE(M_AXGBE); -#define ADVERTISED_Pause 0x01 -#define ADVERTISED_Asym_Pause 0x02 -#define ADVERTISED_Autoneg 0x04 -#define ADVERTISED_Backplane 0x08 -#define ADVERTISED_10000baseKR_Full 0x10 -#define ADVERTISED_2500baseX_Full 0x20 -#define ADVERTISED_1000baseKX_Full 0x40 +#define ADVERTISED_Pause (1 << 0) +#define ADVERTISED_Asym_Pause (1 << 1) +#define ADVERTISED_Autoneg (1 << 2) +#define ADVERTISED_Backplane (1 << 3) +#define ADVERTISED_10000baseKR_Full (1 << 4) +#define ADVERTISED_2500baseX_Full (1 << 5) +#define ADVERTISED_1000baseKX_Full (1 << 6) +#define ADVERTISED_100baseT_Full (1 << 7) +#define ADVERTISED_10000baseR_FEC (1 << 8) +#define ADVERTISED_10000baseT_Full (1 << 9) +#define ADVERTISED_2500baseT_Full (1 << 10) +#define ADVERTISED_1000baseT_Full (1 << 11) +#define ADVERTISED_TP (1 << 12) +#define ADVERTISED_FIBRE (1 << 13) +#define ADVERTISED_1000baseX_Full (1 << 14) +#define ADVERTISED_10000baseSR_Full (1 << 15) +#define ADVERTISED_10000baseLR_Full (1 << 16) +#define ADVERTISED_10000baseLRM_Full (1 << 17) +#define ADVERTISED_10000baseER_Full (1 << 18) +#define ADVERTISED_10000baseCR_Full (1 << 19) +#define ADVERTISED_100baseT_Half (1 << 20) +#define ADVERTISED_1000baseT_Half (1 << 21) + +#define SUPPORTED_Pause (1 << 0) +#define SUPPORTED_Asym_Pause (1 << 1) +#define SUPPORTED_Autoneg (1 << 2) +#define SUPPORTED_Backplane (1 << 3) +#define SUPPORTED_10000baseKR_Full (1 << 4) +#define SUPPORTED_2500baseX_Full (1 << 5) +#define SUPPORTED_1000baseKX_Full (1 << 6) +#define SUPPORTED_100baseT_Full (1 << 7) +#define SUPPORTED_10000baseR_FEC (1 << 8) +#define SUPPORTED_10000baseT_Full (1 << 9) +#define SUPPORTED_2500baseT_Full (1 << 10) +#define SUPPORTED_1000baseT_Full (1 << 11) +#define SUPPORTED_TP (1 << 12) +#define SUPPORTED_FIBRE (1 << 13) +#define SUPPORTED_1000baseX_Full (1 << 14) +#define SUPPORTED_10000baseSR_Full (1 << 15) +#define SUPPORTED_10000baseLR_Full (1 << 16) +#define SUPPORTED_10000baseLRM_Full (1 << 17) +#define SUPPORTED_10000baseER_Full (1 << 18) +#define SUPPORTED_10000baseCR_Full (1 << 19) +#define SUPPORTED_100baseT_Half (1 << 20) +#define SUPPORTED_1000baseT_Half (1 << 21) #define AUTONEG_DISABLE 0 #define AUTONEG_ENABLE 1 @@ -129,15 +167,6 @@ #define SPEED_2500 3 #define SPEED_1000 4 -#define SUPPORTED_Autoneg 0x01 -#define SUPPORTED_Pause 0x02 -#define SUPPORTED_Asym_Pause 0x04 -#define SUPPORTED_Backplane 0x08 -#define SUPPORTED_10000baseKR_Full 0x10 -#define SUPPORTED_1000baseKX_Full 0x20 -#define SUPPORTED_2500baseX_Full 0x40 -#define SUPPORTED_10000baseR_FEC 0x80 - #define BMCR_SPEED100 0x2000 #define MDIO_MMD_PMAPMD 1 Index: sys/modules/axgbe/Makefile =================================================================== --- /dev/null +++ sys/modules/axgbe/Makefile @@ -0,0 +1,10 @@ +#$FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/axgbe + +KMOD = if_axa +SRCS = device_if.h bus_if.h ofw_bus_if.h miibus_if.h ifdi_if.h opt_inet.h opt_inet6.h opt_rss.h +SRCS += if_axgbe.c xgbe-desc.c xgbe-dev.c xgbe-drv.c xgbe-mdio.c xgbe-phy-v1.c + +.include +