diff options
Diffstat (limited to 'target/linux/mvebu/patches-4.14/403-net-mvneta-convert-to-phylink.patch')
-rw-r--r-- | target/linux/mvebu/patches-4.14/403-net-mvneta-convert-to-phylink.patch | 979 |
1 files changed, 0 insertions, 979 deletions
diff --git a/target/linux/mvebu/patches-4.14/403-net-mvneta-convert-to-phylink.patch b/target/linux/mvebu/patches-4.14/403-net-mvneta-convert-to-phylink.patch deleted file mode 100644 index 34a2d342db..0000000000 --- a/target/linux/mvebu/patches-4.14/403-net-mvneta-convert-to-phylink.patch +++ /dev/null @@ -1,979 +0,0 @@ -From 36f29e6cf8071fed3854d9825217ed2a3c83b990 Mon Sep 17 00:00:00 2001 -From: Russell King <rmk+kernel@arm.linux.org.uk> -Date: Wed, 16 Sep 2015 21:27:10 +0100 -Subject: net: mvneta: convert to phylink - -Convert mvneta to use phylink, which models the MAC to PHY link in -a generic, reusable form. - -Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> - -- remove unused sync status ---- - drivers/net/ethernet/marvell/Kconfig | 2 +- - drivers/net/ethernet/marvell/mvneta.c | 594 ++++++++++++++++++++-------------- - 2 files changed, 349 insertions(+), 247 deletions(-) - ---- a/drivers/net/ethernet/marvell/Kconfig -+++ b/drivers/net/ethernet/marvell/Kconfig -@@ -60,7 +60,7 @@ config MVNETA - depends on ARCH_MVEBU || COMPILE_TEST - depends on HAS_DMA - select MVMDIO -- select FIXED_PHY -+ select PHYLINK - ---help--- - This driver supports the network interface units in the - Marvell ARMADA XP, ARMADA 370, ARMADA 38x and ---- a/drivers/net/ethernet/marvell/mvneta.c -+++ b/drivers/net/ethernet/marvell/mvneta.c -@@ -28,7 +28,7 @@ - #include <linux/of_mdio.h> - #include <linux/of_net.h> - #include <linux/phy.h> --#include <linux/phy_fixed.h> -+#include <linux/phylink.h> - #include <linux/platform_device.h> - #include <linux/skbuff.h> - #include <net/hwbm.h> -@@ -189,6 +189,7 @@ - #define MVNETA_GMAC_CTRL_0 0x2c00 - #define MVNETA_GMAC_MAX_RX_SIZE_SHIFT 2 - #define MVNETA_GMAC_MAX_RX_SIZE_MASK 0x7ffc -+#define MVNETA_GMAC0_PORT_1000BASE_X BIT(1) - #define MVNETA_GMAC0_PORT_ENABLE BIT(0) - #define MVNETA_GMAC_CTRL_2 0x2c08 - #define MVNETA_GMAC2_INBAND_AN_ENABLE BIT(0) -@@ -204,13 +205,19 @@ - #define MVNETA_GMAC_TX_FLOW_CTRL_ENABLE BIT(5) - #define MVNETA_GMAC_RX_FLOW_CTRL_ACTIVE BIT(6) - #define MVNETA_GMAC_TX_FLOW_CTRL_ACTIVE BIT(7) -+#define MVNETA_GMAC_AN_COMPLETE BIT(11) -+#define MVNETA_GMAC_SYNC_OK BIT(14) - #define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c - #define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0) - #define MVNETA_GMAC_FORCE_LINK_PASS BIT(1) - #define MVNETA_GMAC_INBAND_AN_ENABLE BIT(2) -+#define MVNETA_GMAC_AN_BYPASS_ENABLE BIT(3) -+#define MVNETA_GMAC_INBAND_RESTART_AN BIT(4) - #define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5) - #define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6) - #define MVNETA_GMAC_AN_SPEED_EN BIT(7) -+#define MVNETA_GMAC_CONFIG_FLOW_CTRL BIT(8) -+#define MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL BIT(9) - #define MVNETA_GMAC_AN_FLOW_CTRL_EN BIT(11) - #define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12) - #define MVNETA_GMAC_AN_DUPLEX_EN BIT(13) -@@ -237,6 +244,12 @@ - #define MVNETA_TXQ_TOKEN_SIZE_REG(q) (0x3e40 + ((q) << 2)) - #define MVNETA_TXQ_TOKEN_SIZE_MAX 0x7fffffff - -+#define MVNETA_LPI_CTRL_0 0x2cc0 -+#define MVNETA_LPI_CTRL_1 0x2cc4 -+#define MVNETA_LPI_REQUEST_ENABLE BIT(0) -+#define MVNETA_LPI_CTRL_2 0x2cc8 -+#define MVNETA_LPI_STATUS 0x2ccc -+ - #define MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff - - /* Descriptor ring Macros */ -@@ -313,6 +326,11 @@ - #define MVNETA_RX_GET_BM_POOL_ID(rxd) \ - (((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT) - -+enum { -+ ETHTOOL_STAT_EEE_WAKEUP, -+ ETHTOOL_MAX_STATS, -+}; -+ - struct mvneta_statistic { - unsigned short offset; - unsigned short type; -@@ -321,6 +339,7 @@ struct mvneta_statistic { - - #define T_REG_32 32 - #define T_REG_64 64 -+#define T_SW 1 - - static const struct mvneta_statistic mvneta_statistics[] = { - { 0x3000, T_REG_64, "good_octets_received", }, -@@ -355,6 +374,7 @@ static const struct mvneta_statistic mvn - { 0x304c, T_REG_32, "broadcast_frames_sent", }, - { 0x3054, T_REG_32, "fc_sent", }, - { 0x300c, T_REG_32, "internal_mac_transmit_err", }, -+ { ETHTOOL_STAT_EEE_WAKEUP, T_SW, "eee_wakeup_errors", }, - }; - - struct mvneta_pcpu_stats { -@@ -407,20 +427,19 @@ struct mvneta_port { - u16 tx_ring_size; - u16 rx_ring_size; - -- struct mii_bus *mii_bus; -- phy_interface_t phy_interface; -- struct device_node *phy_node; -- unsigned int link; -- unsigned int duplex; -- unsigned int speed; -+ struct device_node *dn; - unsigned int tx_csum_limit; -- unsigned int use_inband_status:1; -+ struct phylink *phylink; - - struct mvneta_bm *bm_priv; - struct mvneta_bm_pool *pool_long; - struct mvneta_bm_pool *pool_short; - int bm_win_id; - -+ bool eee_enabled; -+ bool eee_active; -+ bool tx_lpi_enabled; -+ - u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)]; - - u32 indir[MVNETA_RSS_LU_TABLE_SIZE]; -@@ -1215,10 +1234,6 @@ static void mvneta_port_disable(struct m - val &= ~MVNETA_GMAC0_PORT_ENABLE; - mvreg_write(pp, MVNETA_GMAC_CTRL_0, val); - -- pp->link = 0; -- pp->duplex = -1; -- pp->speed = 0; -- - udelay(200); - } - -@@ -1278,44 +1293,6 @@ static void mvneta_set_other_mcast_table - mvreg_write(pp, MVNETA_DA_FILT_OTH_MCAST + offset, val); - } - --static void mvneta_set_autoneg(struct mvneta_port *pp, int enable) --{ -- u32 val; -- -- if (enable) { -- val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); -- val &= ~(MVNETA_GMAC_FORCE_LINK_PASS | -- MVNETA_GMAC_FORCE_LINK_DOWN | -- MVNETA_GMAC_AN_FLOW_CTRL_EN); -- val |= MVNETA_GMAC_INBAND_AN_ENABLE | -- MVNETA_GMAC_AN_SPEED_EN | -- MVNETA_GMAC_AN_DUPLEX_EN; -- mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); -- -- val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER); -- val |= MVNETA_GMAC_1MS_CLOCK_ENABLE; -- mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val); -- -- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); -- val |= MVNETA_GMAC2_INBAND_AN_ENABLE; -- mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); -- } else { -- val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); -- val &= ~(MVNETA_GMAC_INBAND_AN_ENABLE | -- MVNETA_GMAC_AN_SPEED_EN | -- MVNETA_GMAC_AN_DUPLEX_EN); -- mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); -- -- val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER); -- val &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE; -- mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val); -- -- val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); -- val &= ~MVNETA_GMAC2_INBAND_AN_ENABLE; -- mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); -- } --} -- - static void mvneta_percpu_unmask_interrupt(void *arg) - { - struct mvneta_port *pp = arg; -@@ -1468,7 +1445,6 @@ static void mvneta_defaults_set(struct m - val &= ~MVNETA_PHY_POLLING_ENABLE; - mvreg_write(pp, MVNETA_UNIT_CONTROL, val); - -- mvneta_set_autoneg(pp, pp->use_inband_status); - mvneta_set_ucast_table(pp, -1); - mvneta_set_special_mcast_table(pp, -1); - mvneta_set_other_mcast_table(pp, -1); -@@ -2693,26 +2669,11 @@ static irqreturn_t mvneta_percpu_isr(int - return IRQ_HANDLED; - } - --static int mvneta_fixed_link_update(struct mvneta_port *pp, -- struct phy_device *phy) -+static void mvneta_link_change(struct mvneta_port *pp) - { -- struct fixed_phy_status status; -- struct fixed_phy_status changed = {}; - u32 gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS); - -- status.link = !!(gmac_stat & MVNETA_GMAC_LINK_UP); -- if (gmac_stat & MVNETA_GMAC_SPEED_1000) -- status.speed = SPEED_1000; -- else if (gmac_stat & MVNETA_GMAC_SPEED_100) -- status.speed = SPEED_100; -- else -- status.speed = SPEED_10; -- status.duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX); -- changed.link = 1; -- changed.speed = 1; -- changed.duplex = 1; -- fixed_phy_update_state(phy, &status, &changed); -- return 0; -+ phylink_mac_change(pp->phylink, !!(gmac_stat & MVNETA_GMAC_LINK_UP)); - } - - /* NAPI handler -@@ -2728,7 +2689,6 @@ static int mvneta_poll(struct napi_struc - u32 cause_rx_tx; - int rx_queue; - struct mvneta_port *pp = netdev_priv(napi->dev); -- struct net_device *ndev = pp->dev; - struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports); - - if (!netif_running(pp->dev)) { -@@ -2742,12 +2702,11 @@ static int mvneta_poll(struct napi_struc - u32 cause_misc = mvreg_read(pp, MVNETA_INTR_MISC_CAUSE); - - mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); -- if (pp->use_inband_status && (cause_misc & -- (MVNETA_CAUSE_PHY_STATUS_CHANGE | -- MVNETA_CAUSE_LINK_CHANGE | -- MVNETA_CAUSE_PSC_SYNC_CHANGE))) { -- mvneta_fixed_link_update(pp, ndev->phydev); -- } -+ -+ if (cause_misc & (MVNETA_CAUSE_PHY_STATUS_CHANGE | -+ MVNETA_CAUSE_LINK_CHANGE | -+ MVNETA_CAUSE_PSC_SYNC_CHANGE)) -+ mvneta_link_change(pp); - } - - /* Release Tx descriptors */ -@@ -3061,7 +3020,6 @@ static int mvneta_setup_txqs(struct mvne - static void mvneta_start_dev(struct mvneta_port *pp) - { - int cpu; -- struct net_device *ndev = pp->dev; - - mvneta_max_rx_size_set(pp, pp->pkt_size); - mvneta_txq_max_tx_size_set(pp, pp->pkt_size); -@@ -3089,16 +3047,15 @@ static void mvneta_start_dev(struct mvne - MVNETA_CAUSE_LINK_CHANGE | - MVNETA_CAUSE_PSC_SYNC_CHANGE); - -- phy_start(ndev->phydev); -+ phylink_start(pp->phylink); - netif_tx_start_all_queues(pp->dev); - } - - static void mvneta_stop_dev(struct mvneta_port *pp) - { - unsigned int cpu; -- struct net_device *ndev = pp->dev; - -- phy_stop(ndev->phydev); -+ phylink_stop(pp->phylink); - - if (!pp->neta_armada3700) { - for_each_online_cpu(cpu) { -@@ -3251,103 +3208,232 @@ static int mvneta_set_mac_addr(struct ne - return 0; - } - --static void mvneta_adjust_link(struct net_device *ndev) -+static void mvneta_validate(struct net_device *ndev, unsigned long *supported, -+ struct phylink_link_state *state) -+{ -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -+ -+ /* Allow all the expected bits */ -+ phylink_set(mask, Autoneg); -+ phylink_set_port_modes(mask); -+ -+ /* Asymmetric pause is unsupported */ -+ phylink_set(mask, Pause); -+ /* Half-duplex at speeds higher than 100Mbit is unsupported */ -+ phylink_set(mask, 1000baseT_Full); -+ phylink_set(mask, 1000baseX_Full); -+ -+ if (state->interface != PHY_INTERFACE_MODE_1000BASEX) { -+ /* 10M and 100M are only supported in non-802.3z mode */ -+ phylink_set(mask, 10baseT_Half); -+ phylink_set(mask, 10baseT_Full); -+ phylink_set(mask, 100baseT_Half); -+ phylink_set(mask, 100baseT_Full); -+ } -+ -+ bitmap_and(supported, supported, mask, -+ __ETHTOOL_LINK_MODE_MASK_NBITS); -+ bitmap_and(state->advertising, state->advertising, mask, -+ __ETHTOOL_LINK_MODE_MASK_NBITS); -+} -+ -+static int mvneta_mac_link_state(struct net_device *ndev, -+ struct phylink_link_state *state) - { - struct mvneta_port *pp = netdev_priv(ndev); -- struct phy_device *phydev = ndev->phydev; -- int status_change = 0; -+ u32 gmac_stat; - -- if (phydev->link) { -- if ((pp->speed != phydev->speed) || -- (pp->duplex != phydev->duplex)) { -- u32 val; -- -- val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); -- val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED | -- MVNETA_GMAC_CONFIG_GMII_SPEED | -- MVNETA_GMAC_CONFIG_FULL_DUPLEX); -- -- if (phydev->duplex) -- val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; -- -- if (phydev->speed == SPEED_1000) -- val |= MVNETA_GMAC_CONFIG_GMII_SPEED; -- else if (phydev->speed == SPEED_100) -- val |= MVNETA_GMAC_CONFIG_MII_SPEED; -+ gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS); - -- mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); -+ if (gmac_stat & MVNETA_GMAC_SPEED_1000) -+ state->speed = SPEED_1000; -+ else if (gmac_stat & MVNETA_GMAC_SPEED_100) -+ state->speed = SPEED_100; -+ else -+ state->speed = SPEED_10; - -- pp->duplex = phydev->duplex; -- pp->speed = phydev->speed; -- } -+ state->an_complete = !!(gmac_stat & MVNETA_GMAC_AN_COMPLETE); -+ state->link = !!(gmac_stat & MVNETA_GMAC_LINK_UP); -+ state->duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX); -+ -+ state->pause = 0; -+ if (gmac_stat & MVNETA_GMAC_RX_FLOW_CTRL_ENABLE) -+ state->pause |= MLO_PAUSE_RX; -+ if (gmac_stat & MVNETA_GMAC_TX_FLOW_CTRL_ENABLE) -+ state->pause |= MLO_PAUSE_TX; -+ -+ return 1; -+} -+ -+static void mvneta_mac_an_restart(struct net_device *ndev) -+{ -+ struct mvneta_port *pp = netdev_priv(ndev); -+ u32 gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); -+ -+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, -+ gmac_an | MVNETA_GMAC_INBAND_RESTART_AN); -+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, -+ gmac_an & ~MVNETA_GMAC_INBAND_RESTART_AN); -+} -+ -+static void mvneta_mac_config(struct net_device *ndev, unsigned int mode, -+ const struct phylink_link_state *state) -+{ -+ struct mvneta_port *pp = netdev_priv(ndev); -+ u32 new_ctrl0, gmac_ctrl0 = mvreg_read(pp, MVNETA_GMAC_CTRL_0); -+ u32 new_ctrl2, gmac_ctrl2 = mvreg_read(pp, MVNETA_GMAC_CTRL_2); -+ u32 new_clk, gmac_clk = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER); -+ u32 new_an, gmac_an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); -+ -+ new_ctrl0 = gmac_ctrl0 & ~MVNETA_GMAC0_PORT_1000BASE_X; -+ new_ctrl2 = gmac_ctrl2 & ~MVNETA_GMAC2_INBAND_AN_ENABLE; -+ new_clk = gmac_clk & ~MVNETA_GMAC_1MS_CLOCK_ENABLE; -+ new_an = gmac_an & ~(MVNETA_GMAC_INBAND_AN_ENABLE | -+ MVNETA_GMAC_INBAND_RESTART_AN | -+ MVNETA_GMAC_CONFIG_MII_SPEED | -+ MVNETA_GMAC_CONFIG_GMII_SPEED | -+ MVNETA_GMAC_AN_SPEED_EN | -+ MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL | -+ MVNETA_GMAC_CONFIG_FLOW_CTRL | -+ MVNETA_GMAC_AN_FLOW_CTRL_EN | -+ MVNETA_GMAC_CONFIG_FULL_DUPLEX | -+ MVNETA_GMAC_AN_DUPLEX_EN); -+ -+ if (phylink_test(state->advertising, Pause)) -+ new_an |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL; -+ if (state->pause & MLO_PAUSE_TXRX_MASK) -+ new_an |= MVNETA_GMAC_CONFIG_FLOW_CTRL; -+ -+ if (!phylink_autoneg_inband(mode)) { -+ /* Phy or fixed speed */ -+ if (state->duplex) -+ new_an |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; -+ -+ if (state->speed == SPEED_1000) -+ new_an |= MVNETA_GMAC_CONFIG_GMII_SPEED; -+ else if (state->speed == SPEED_100) -+ new_an |= MVNETA_GMAC_CONFIG_MII_SPEED; -+ } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { -+ /* SGMII mode receives the state from the PHY */ -+ new_ctrl2 |= MVNETA_GMAC2_INBAND_AN_ENABLE; -+ new_clk |= MVNETA_GMAC_1MS_CLOCK_ENABLE; -+ new_an = (new_an & ~(MVNETA_GMAC_FORCE_LINK_DOWN | -+ MVNETA_GMAC_FORCE_LINK_PASS)) | -+ MVNETA_GMAC_INBAND_AN_ENABLE | -+ MVNETA_GMAC_AN_SPEED_EN | -+ MVNETA_GMAC_AN_DUPLEX_EN; -+ } else { -+ /* 802.3z negotiation - only 1000base-X */ -+ new_ctrl0 |= MVNETA_GMAC0_PORT_1000BASE_X; -+ new_clk |= MVNETA_GMAC_1MS_CLOCK_ENABLE; -+ new_an = (new_an & ~(MVNETA_GMAC_FORCE_LINK_DOWN | -+ MVNETA_GMAC_FORCE_LINK_PASS)) | -+ MVNETA_GMAC_INBAND_AN_ENABLE | -+ MVNETA_GMAC_CONFIG_GMII_SPEED | -+ /* The MAC only supports FD mode */ -+ MVNETA_GMAC_CONFIG_FULL_DUPLEX; -+ -+ if (state->pause & MLO_PAUSE_AN && state->an_enabled) -+ new_an |= MVNETA_GMAC_AN_FLOW_CTRL_EN; -+ } -+ -+ /* Armada 370 documentation says we can only change the port mode -+ * and in-band enable when the link is down, so force it down -+ * while making these changes. We also do this for GMAC_CTRL2 */ -+ if ((new_ctrl0 ^ gmac_ctrl0) & MVNETA_GMAC0_PORT_1000BASE_X || -+ (new_ctrl2 ^ gmac_ctrl2) & MVNETA_GMAC2_INBAND_AN_ENABLE || -+ (new_an ^ gmac_an) & MVNETA_GMAC_INBAND_AN_ENABLE) { -+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, -+ (gmac_an & ~MVNETA_GMAC_FORCE_LINK_PASS) | -+ MVNETA_GMAC_FORCE_LINK_DOWN); -+ } -+ -+ if (new_ctrl0 != gmac_ctrl0) -+ mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0); -+ if (new_ctrl2 != gmac_ctrl2) -+ mvreg_write(pp, MVNETA_GMAC_CTRL_2, new_ctrl2); -+ if (new_clk != gmac_clk) -+ mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, new_clk); -+ if (new_an != gmac_an) -+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, new_an); -+} -+ -+static void mvneta_set_eee(struct mvneta_port *pp, bool enable) -+{ -+ u32 lpi_ctl1; -+ -+ lpi_ctl1 = mvreg_read(pp, MVNETA_LPI_CTRL_1); -+ if (enable) -+ lpi_ctl1 |= MVNETA_LPI_REQUEST_ENABLE; -+ else -+ lpi_ctl1 &= ~MVNETA_LPI_REQUEST_ENABLE; -+ mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1); -+} -+ -+static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode) -+{ -+ struct mvneta_port *pp = netdev_priv(ndev); -+ u32 val; -+ -+ mvneta_port_down(pp); -+ -+ if (!phylink_autoneg_inband(mode)) { -+ val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); -+ val &= ~MVNETA_GMAC_FORCE_LINK_PASS; -+ val |= MVNETA_GMAC_FORCE_LINK_DOWN; -+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); - } - -- if (phydev->link != pp->link) { -- if (!phydev->link) { -- pp->duplex = -1; -- pp->speed = 0; -- } -+ pp->eee_active = false; -+ mvneta_set_eee(pp, false); -+} -+ -+static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode, -+ struct phy_device *phy) -+{ -+ struct mvneta_port *pp = netdev_priv(ndev); -+ u32 val; - -- pp->link = phydev->link; -- status_change = 1; -+ if (!phylink_autoneg_inband(mode)) { -+ val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); -+ val &= ~MVNETA_GMAC_FORCE_LINK_DOWN; -+ val |= MVNETA_GMAC_FORCE_LINK_PASS; -+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); - } - -- if (status_change) { -- if (phydev->link) { -- if (!pp->use_inband_status) { -- u32 val = mvreg_read(pp, -- MVNETA_GMAC_AUTONEG_CONFIG); -- val &= ~MVNETA_GMAC_FORCE_LINK_DOWN; -- val |= MVNETA_GMAC_FORCE_LINK_PASS; -- mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, -- val); -- } -- mvneta_port_up(pp); -- } else { -- if (!pp->use_inband_status) { -- u32 val = mvreg_read(pp, -- MVNETA_GMAC_AUTONEG_CONFIG); -- val &= ~MVNETA_GMAC_FORCE_LINK_PASS; -- val |= MVNETA_GMAC_FORCE_LINK_DOWN; -- mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, -- val); -- } -- mvneta_port_down(pp); -- } -- phy_print_status(phydev); -+ mvneta_port_up(pp); -+ -+ if (phy && pp->eee_enabled) { -+ pp->eee_active = phy_init_eee(phy, 0) >= 0; -+ mvneta_set_eee(pp, pp->eee_active && pp->tx_lpi_enabled); - } - } - -+static const struct phylink_mac_ops mvneta_phylink_ops = { -+ .validate = mvneta_validate, -+ .mac_link_state = mvneta_mac_link_state, -+ .mac_an_restart = mvneta_mac_an_restart, -+ .mac_config = mvneta_mac_config, -+ .mac_link_down = mvneta_mac_link_down, -+ .mac_link_up = mvneta_mac_link_up, -+}; -+ - static int mvneta_mdio_probe(struct mvneta_port *pp) - { -- struct phy_device *phy_dev; - struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; -+ int err = phylink_of_phy_connect(pp->phylink, pp->dn); -+ if (err) -+ netdev_err(pp->dev, "could not attach PHY\n"); - -- phy_dev = of_phy_connect(pp->dev, pp->phy_node, mvneta_adjust_link, 0, -- pp->phy_interface); -- if (!phy_dev) { -- netdev_err(pp->dev, "could not find the PHY\n"); -- return -ENODEV; -- } -- -- phy_ethtool_get_wol(phy_dev, &wol); -+ phylink_ethtool_get_wol(pp->phylink, &wol); - device_set_wakeup_capable(&pp->dev->dev, !!wol.supported); - -- phy_dev->supported &= PHY_GBIT_FEATURES; -- phy_dev->advertising = phy_dev->supported; -- -- pp->link = 0; -- pp->duplex = 0; -- pp->speed = 0; -- -- return 0; -+ return err; - } - - static void mvneta_mdio_remove(struct mvneta_port *pp) - { -- struct net_device *ndev = pp->dev; -- -- phy_disconnect(ndev->phydev); -+ phylink_disconnect_phy(pp->phylink); - } - - /* Electing a CPU must be done in an atomic way: it should be done -@@ -3626,10 +3712,9 @@ static int mvneta_stop(struct net_device - - static int mvneta_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) - { -- if (!dev->phydev) -- return -ENOTSUPP; -+ struct mvneta_port *pp = netdev_priv(dev); - -- return phy_mii_ioctl(dev->phydev, ifr, cmd); -+ return phylink_mii_ioctl(pp->phylink, ifr, cmd); - } - - /* Ethtool methods */ -@@ -3640,44 +3725,25 @@ mvneta_ethtool_set_link_ksettings(struct - const struct ethtool_link_ksettings *cmd) - { - struct mvneta_port *pp = netdev_priv(ndev); -- struct phy_device *phydev = ndev->phydev; - -- if (!phydev) -- return -ENODEV; -- -- if ((cmd->base.autoneg == AUTONEG_ENABLE) != pp->use_inband_status) { -- u32 val; -- -- mvneta_set_autoneg(pp, cmd->base.autoneg == AUTONEG_ENABLE); -- -- if (cmd->base.autoneg == AUTONEG_DISABLE) { -- val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); -- val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED | -- MVNETA_GMAC_CONFIG_GMII_SPEED | -- MVNETA_GMAC_CONFIG_FULL_DUPLEX); -- -- if (phydev->duplex) -- val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; -+ return phylink_ethtool_ksettings_set(pp->phylink, cmd); -+} - -- if (phydev->speed == SPEED_1000) -- val |= MVNETA_GMAC_CONFIG_GMII_SPEED; -- else if (phydev->speed == SPEED_100) -- val |= MVNETA_GMAC_CONFIG_MII_SPEED; -+/* Get link ksettings for ethtools */ -+static int -+mvneta_ethtool_get_link_ksettings(struct net_device *ndev, -+ struct ethtool_link_ksettings *cmd) -+{ -+ struct mvneta_port *pp = netdev_priv(ndev); - -- mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); -- } -+ return phylink_ethtool_ksettings_get(pp->phylink, cmd); -+} - -- pp->use_inband_status = (cmd->base.autoneg == AUTONEG_ENABLE); -- netdev_info(pp->dev, "autoneg status set to %i\n", -- pp->use_inband_status); -- -- if (netif_running(ndev)) { -- mvneta_port_down(pp); -- mvneta_port_up(pp); -- } -- } -+static int mvneta_ethtool_nway_reset(struct net_device *dev) -+{ -+ struct mvneta_port *pp = netdev_priv(dev); - -- return phy_ethtool_ksettings_set(ndev->phydev, cmd); -+ return phylink_ethtool_nway_reset(pp->phylink); - } - - /* Set interrupt coalescing for ethtools */ -@@ -3769,6 +3835,22 @@ static int mvneta_ethtool_set_ringparam( - return 0; - } - -+static void mvneta_ethtool_get_pauseparam(struct net_device *dev, -+ struct ethtool_pauseparam *pause) -+{ -+ struct mvneta_port *pp = netdev_priv(dev); -+ -+ phylink_ethtool_get_pauseparam(pp->phylink, pause); -+} -+ -+static int mvneta_ethtool_set_pauseparam(struct net_device *dev, -+ struct ethtool_pauseparam *pause) -+{ -+ struct mvneta_port *pp = netdev_priv(dev); -+ -+ return phylink_ethtool_set_pauseparam(pp->phylink, pause); -+} -+ - static void mvneta_ethtool_get_strings(struct net_device *netdev, u32 sset, - u8 *data) - { -@@ -3785,26 +3867,35 @@ static void mvneta_ethtool_update_stats( - { - const struct mvneta_statistic *s; - void __iomem *base = pp->base; -- u32 high, low, val; -- u64 val64; -+ u32 high, low; -+ u64 val; - int i; - - for (i = 0, s = mvneta_statistics; - s < mvneta_statistics + ARRAY_SIZE(mvneta_statistics); - s++, i++) { -+ val = 0; -+ - switch (s->type) { - case T_REG_32: - val = readl_relaxed(base + s->offset); -- pp->ethtool_stats[i] += val; - break; - case T_REG_64: - /* Docs say to read low 32-bit then high */ - low = readl_relaxed(base + s->offset); - high = readl_relaxed(base + s->offset + 4); -- val64 = (u64)high << 32 | low; -- pp->ethtool_stats[i] += val64; -+ val = (u64)high << 32 | low; -+ break; -+ case T_SW: -+ switch (s->offset) { -+ case ETHTOOL_STAT_EEE_WAKEUP: -+ val = phylink_get_eee_err(pp->phylink); -+ break; -+ } - break; - } -+ -+ pp->ethtool_stats[i] += val; - } - } - -@@ -3939,28 +4030,65 @@ static int mvneta_ethtool_get_rxfh(struc - static void mvneta_ethtool_get_wol(struct net_device *dev, - struct ethtool_wolinfo *wol) - { -- wol->supported = 0; -- wol->wolopts = 0; -+ struct mvneta_port *pp = netdev_priv(dev); - -- if (dev->phydev) -- phy_ethtool_get_wol(dev->phydev, wol); -+ phylink_ethtool_get_wol(pp->phylink, wol); - } - - static int mvneta_ethtool_set_wol(struct net_device *dev, - struct ethtool_wolinfo *wol) - { -+ struct mvneta_port *pp = netdev_priv(dev); - int ret; - -- if (!dev->phydev) -- return -EOPNOTSUPP; -- -- ret = phy_ethtool_set_wol(dev->phydev, wol); -+ ret = phylink_ethtool_set_wol(pp->phylink, wol); - if (!ret) - device_set_wakeup_enable(&dev->dev, !!wol->wolopts); - - return ret; - } - -+static int mvneta_ethtool_get_eee(struct net_device *dev, -+ struct ethtool_eee *eee) -+{ -+ struct mvneta_port *pp = netdev_priv(dev); -+ u32 lpi_ctl0; -+ -+ lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0); -+ -+ eee->eee_enabled = pp->eee_enabled; -+ eee->eee_active = pp->eee_active; -+ eee->tx_lpi_enabled = pp->tx_lpi_enabled; -+ eee->tx_lpi_timer = (lpi_ctl0) >> 8; // * scale; -+ -+ return phylink_ethtool_get_eee(pp->phylink, eee); -+} -+ -+static int mvneta_ethtool_set_eee(struct net_device *dev, -+ struct ethtool_eee *eee) -+{ -+ struct mvneta_port *pp = netdev_priv(dev); -+ u32 lpi_ctl0; -+ -+ /* The Armada 37x documents do not give limits for this other than -+ * it being an 8-bit register. */ -+ if (eee->tx_lpi_enabled && -+ (eee->tx_lpi_timer < 0 || eee->tx_lpi_timer > 255)) -+ return -EINVAL; -+ -+ lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0); -+ lpi_ctl0 &= ~(0xff << 8); -+ lpi_ctl0 |= eee->tx_lpi_timer << 8; -+ mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi_ctl0); -+ -+ pp->eee_enabled = eee->eee_enabled; -+ pp->tx_lpi_enabled = eee->tx_lpi_enabled; -+ -+ mvneta_set_eee(pp, eee->tx_lpi_enabled && eee->eee_enabled); -+ -+ return phylink_ethtool_set_eee(pp->phylink, eee); -+} -+ - static u16 mvneta_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv, - select_queue_fallback_t fallback) -@@ -3984,13 +4112,15 @@ static const struct net_device_ops mvnet - }; - - static const struct ethtool_ops mvneta_eth_tool_ops = { -- .nway_reset = phy_ethtool_nway_reset, -+ .nway_reset = mvneta_ethtool_nway_reset, - .get_link = ethtool_op_get_link, - .set_coalesce = mvneta_ethtool_set_coalesce, - .get_coalesce = mvneta_ethtool_get_coalesce, - .get_drvinfo = mvneta_ethtool_get_drvinfo, - .get_ringparam = mvneta_ethtool_get_ringparam, - .set_ringparam = mvneta_ethtool_set_ringparam, -+ .get_pauseparam = mvneta_ethtool_get_pauseparam, -+ .set_pauseparam = mvneta_ethtool_set_pauseparam, - .get_strings = mvneta_ethtool_get_strings, - .get_ethtool_stats = mvneta_ethtool_get_stats, - .get_sset_count = mvneta_ethtool_get_sset_count, -@@ -3998,10 +4128,12 @@ static const struct ethtool_ops mvneta_e - .get_rxnfc = mvneta_ethtool_get_rxnfc, - .get_rxfh = mvneta_ethtool_get_rxfh, - .set_rxfh = mvneta_ethtool_set_rxfh, -- .get_link_ksettings = phy_ethtool_get_link_ksettings, -+ .get_link_ksettings = mvneta_ethtool_get_link_ksettings, - .set_link_ksettings = mvneta_ethtool_set_link_ksettings, - .get_wol = mvneta_ethtool_get_wol, - .set_wol = mvneta_ethtool_set_wol, -+ .get_eee = mvneta_ethtool_get_eee, -+ .set_eee = mvneta_ethtool_set_eee, - }; - - /* Initialize hw */ -@@ -4146,14 +4278,13 @@ static int mvneta_probe(struct platform_ - { - struct resource *res; - struct device_node *dn = pdev->dev.of_node; -- struct device_node *phy_node; - struct device_node *bm_node; - struct mvneta_port *pp; - struct net_device *dev; -+ struct phylink *phylink; - const char *dt_mac_addr; - char hw_mac_addr[ETH_ALEN]; - const char *mac_from; -- const char *managed; - int tx_csum_limit; - int phy_mode; - int err; -@@ -4169,31 +4300,11 @@ static int mvneta_probe(struct platform_ - goto err_free_netdev; - } - -- phy_node = of_parse_phandle(dn, "phy", 0); -- if (!phy_node) { -- if (!of_phy_is_fixed_link(dn)) { -- dev_err(&pdev->dev, "no PHY specified\n"); -- err = -ENODEV; -- goto err_free_irq; -- } -- -- err = of_phy_register_fixed_link(dn); -- if (err < 0) { -- dev_err(&pdev->dev, "cannot register fixed PHY\n"); -- goto err_free_irq; -- } -- -- /* In the case of a fixed PHY, the DT node associated -- * to the PHY is the Ethernet MAC DT node. -- */ -- phy_node = of_node_get(dn); -- } -- - phy_mode = of_get_phy_mode(dn); - if (phy_mode < 0) { - dev_err(&pdev->dev, "incorrect phy-mode\n"); - err = -EINVAL; -- goto err_put_phy_node; -+ goto err_free_irq; - } - - dev->tx_queue_len = MVNETA_MAX_TXD; -@@ -4204,12 +4315,7 @@ static int mvneta_probe(struct platform_ - - pp = netdev_priv(dev); - spin_lock_init(&pp->lock); -- pp->phy_node = phy_node; -- pp->phy_interface = phy_mode; -- -- err = of_property_read_string(dn, "managed", &managed); -- pp->use_inband_status = (err == 0 && -- strcmp(managed, "in-band-status") == 0); -+ pp->dn = dn; - - pp->rxq_def = rxq_def; - -@@ -4231,7 +4337,7 @@ static int mvneta_probe(struct platform_ - pp->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pp->clk)) { - err = PTR_ERR(pp->clk); -- goto err_put_phy_node; -+ goto err_free_irq; - } - - clk_prepare_enable(pp->clk); -@@ -4357,6 +4463,14 @@ static int mvneta_probe(struct platform_ - /* 9676 == 9700 - 20 and rounding to 8 */ - dev->max_mtu = 9676; - -+ phylink = phylink_create(dev, dn, phy_mode, &mvneta_phylink_ops); -+ if (IS_ERR(phylink)) { -+ err = PTR_ERR(phylink); -+ goto err_netdev; -+ } -+ -+ pp->phylink = phylink; -+ - err = register_netdev(dev); - if (err < 0) { - dev_err(&pdev->dev, "failed to register\n"); -@@ -4368,14 +4482,6 @@ static int mvneta_probe(struct platform_ - - platform_set_drvdata(pdev, pp->dev); - -- if (pp->use_inband_status) { -- struct phy_device *phy = of_phy_find_device(dn); -- -- mvneta_fixed_link_update(pp, phy); -- -- put_device(&phy->mdio.dev); -- } -- - return 0; - - err_netdev: -@@ -4384,16 +4490,14 @@ err_netdev: - mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_short, - 1 << pp->id); - } -+ if (pp->phylink) -+ phylink_destroy(pp->phylink); - free_percpu(pp->stats); - err_free_ports: - free_percpu(pp->ports); - err_clk: - clk_disable_unprepare(pp->clk_bus); - clk_disable_unprepare(pp->clk); --err_put_phy_node: -- of_node_put(phy_node); -- if (of_phy_is_fixed_link(dn)) -- of_phy_deregister_fixed_link(dn); - err_free_irq: - irq_dispose_mapping(dev->irq); - err_free_netdev: -@@ -4405,7 +4509,6 @@ err_free_netdev: - static int mvneta_remove(struct platform_device *pdev) - { - struct net_device *dev = platform_get_drvdata(pdev); -- struct device_node *dn = pdev->dev.of_node; - struct mvneta_port *pp = netdev_priv(dev); - - unregister_netdev(dev); -@@ -4413,10 +4516,8 @@ static int mvneta_remove(struct platform - clk_disable_unprepare(pp->clk); - free_percpu(pp->ports); - free_percpu(pp->stats); -- if (of_phy_is_fixed_link(dn)) -- of_phy_deregister_fixed_link(dn); - irq_dispose_mapping(dev->irq); -- of_node_put(pp->phy_node); -+ phylink_destroy(pp->phylink); - free_netdev(dev); - - if (pp->bm_priv) { -@@ -4468,9 +4569,6 @@ static int mvneta_resume(struct device * - return err; - } - -- if (pp->use_inband_status) -- mvneta_fixed_link_update(pp, dev->phydev); -- - netif_device_attach(dev); - if (netif_running(dev)) { - mvneta_open(dev); |