Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144361872
D21728.id62341.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
79 KB
Referenced Files
None
Subscribers
None
D21728.id62341.diff
View Options
Index: sys/dev/axgbe/if_axgbe.c
===================================================================
--- sys/dev/axgbe/if_axgbe.c
+++ sys/dev/axgbe/if_axgbe.c
@@ -51,10 +51,6 @@
#include <net/if_media.h>
#include <net/if_types.h>
-#include <dev/ofw/openfirm.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
-
#include <machine/bus.h>
#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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <COPYRIGHT HOLDER> 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/module.h>
+
+#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 <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
#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 <bsd.kmod.mk>
+
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 9, 1:26 AM (6 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28520808
Default Alt Text
D21728.id62341.diff (79 KB)
Attached To
Mode
D21728: Changes to update the FreeBSD axgbe driver on-par to the Linux axgbe driver
Attached
Detach File
Event Timeline
Log In to Comment