diff options
author | Stas Sergeev <stsp@list.ru> | 2015-04-01 13:32:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-04-03 15:08:20 -0400 |
commit | 898b2970e2c91e4543b579998922822894325866 (patch) | |
tree | 11065a9cf7570f455b747eab454dfc9b48916175 /drivers/net/ethernet | |
parent | a3bebdce4135a44d09e96ba66c40797c8f9fa902 (diff) |
mvneta: implement SGMII-based in-band link state signaling
When MDIO bus is unavailable (common setup for SGMII), the in-band
signaling must be used to correctly track link state.
This patch enables the in-band status delivery for link state changes, namely:
- link up/down
- link speed
- duplex full/half
fixed_phy_update_state() is used to update phy status.
CC: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
CC: Florian Fainelli <f.fainelli@gmail.com>
CC: netdev@vger.kernel.org
CC: linux-kernel@vger.kernel.org
Signed-off-by: Stas Sergeev <stsp@users.sourceforge.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/marvell/mvneta.c | 106 |
1 files changed, 95 insertions, 11 deletions
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 96208f17bb53..a7a9271f64b1 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c | |||
@@ -100,6 +100,8 @@ | |||
100 | #define MVNETA_TXQ_CMD 0x2448 | 100 | #define MVNETA_TXQ_CMD 0x2448 |
101 | #define MVNETA_TXQ_DISABLE_SHIFT 8 | 101 | #define MVNETA_TXQ_DISABLE_SHIFT 8 |
102 | #define MVNETA_TXQ_ENABLE_MASK 0x000000ff | 102 | #define MVNETA_TXQ_ENABLE_MASK 0x000000ff |
103 | #define MVNETA_GMAC_CLOCK_DIVIDER 0x24f4 | ||
104 | #define MVNETA_GMAC_1MS_CLOCK_ENABLE BIT(31) | ||
103 | #define MVNETA_ACC_MODE 0x2500 | 105 | #define MVNETA_ACC_MODE 0x2500 |
104 | #define MVNETA_CPU_MAP(cpu) (0x2540 + ((cpu) << 2)) | 106 | #define MVNETA_CPU_MAP(cpu) (0x2540 + ((cpu) << 2)) |
105 | #define MVNETA_CPU_RXQ_ACCESS_ALL_MASK 0x000000ff | 107 | #define MVNETA_CPU_RXQ_ACCESS_ALL_MASK 0x000000ff |
@@ -122,6 +124,7 @@ | |||
122 | #define MVNETA_TX_INTR_MASK_ALL (0xff << 0) | 124 | #define MVNETA_TX_INTR_MASK_ALL (0xff << 0) |
123 | #define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8) | 125 | #define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8) |
124 | #define MVNETA_RX_INTR_MASK_ALL (0xff << 8) | 126 | #define MVNETA_RX_INTR_MASK_ALL (0xff << 8) |
127 | #define MVNETA_MISCINTR_INTR_MASK BIT(31) | ||
125 | 128 | ||
126 | #define MVNETA_INTR_OLD_CAUSE 0x25a8 | 129 | #define MVNETA_INTR_OLD_CAUSE 0x25a8 |
127 | #define MVNETA_INTR_OLD_MASK 0x25ac | 130 | #define MVNETA_INTR_OLD_MASK 0x25ac |
@@ -165,6 +168,7 @@ | |||
165 | #define MVNETA_GMAC_MAX_RX_SIZE_MASK 0x7ffc | 168 | #define MVNETA_GMAC_MAX_RX_SIZE_MASK 0x7ffc |
166 | #define MVNETA_GMAC0_PORT_ENABLE BIT(0) | 169 | #define MVNETA_GMAC0_PORT_ENABLE BIT(0) |
167 | #define MVNETA_GMAC_CTRL_2 0x2c08 | 170 | #define MVNETA_GMAC_CTRL_2 0x2c08 |
171 | #define MVNETA_GMAC2_INBAND_AN_ENABLE BIT(0) | ||
168 | #define MVNETA_GMAC2_PCS_ENABLE BIT(3) | 172 | #define MVNETA_GMAC2_PCS_ENABLE BIT(3) |
169 | #define MVNETA_GMAC2_PORT_RGMII BIT(4) | 173 | #define MVNETA_GMAC2_PORT_RGMII BIT(4) |
170 | #define MVNETA_GMAC2_PORT_RESET BIT(6) | 174 | #define MVNETA_GMAC2_PORT_RESET BIT(6) |
@@ -180,9 +184,11 @@ | |||
180 | #define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c | 184 | #define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c |
181 | #define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0) | 185 | #define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0) |
182 | #define MVNETA_GMAC_FORCE_LINK_PASS BIT(1) | 186 | #define MVNETA_GMAC_FORCE_LINK_PASS BIT(1) |
187 | #define MVNETA_GMAC_INBAND_AN_ENABLE BIT(2) | ||
183 | #define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5) | 188 | #define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5) |
184 | #define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6) | 189 | #define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6) |
185 | #define MVNETA_GMAC_AN_SPEED_EN BIT(7) | 190 | #define MVNETA_GMAC_AN_SPEED_EN BIT(7) |
191 | #define MVNETA_GMAC_AN_FLOW_CTRL_EN BIT(11) | ||
186 | #define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12) | 192 | #define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12) |
187 | #define MVNETA_GMAC_AN_DUPLEX_EN BIT(13) | 193 | #define MVNETA_GMAC_AN_DUPLEX_EN BIT(13) |
188 | #define MVNETA_MIB_COUNTERS_BASE 0x3080 | 194 | #define MVNETA_MIB_COUNTERS_BASE 0x3080 |
@@ -304,6 +310,7 @@ struct mvneta_port { | |||
304 | unsigned int link; | 310 | unsigned int link; |
305 | unsigned int duplex; | 311 | unsigned int duplex; |
306 | unsigned int speed; | 312 | unsigned int speed; |
313 | int use_inband_status:1; | ||
307 | }; | 314 | }; |
308 | 315 | ||
309 | /* The mvneta_tx_desc and mvneta_rx_desc structures describe the | 316 | /* The mvneta_tx_desc and mvneta_rx_desc structures describe the |
@@ -994,6 +1001,20 @@ static void mvneta_defaults_set(struct mvneta_port *pp) | |||
994 | val &= ~MVNETA_PHY_POLLING_ENABLE; | 1001 | val &= ~MVNETA_PHY_POLLING_ENABLE; |
995 | mvreg_write(pp, MVNETA_UNIT_CONTROL, val); | 1002 | mvreg_write(pp, MVNETA_UNIT_CONTROL, val); |
996 | 1003 | ||
1004 | if (pp->use_inband_status) { | ||
1005 | val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); | ||
1006 | val &= ~(MVNETA_GMAC_FORCE_LINK_PASS | | ||
1007 | MVNETA_GMAC_FORCE_LINK_DOWN | | ||
1008 | MVNETA_GMAC_AN_FLOW_CTRL_EN); | ||
1009 | val |= MVNETA_GMAC_INBAND_AN_ENABLE | | ||
1010 | MVNETA_GMAC_AN_SPEED_EN | | ||
1011 | MVNETA_GMAC_AN_DUPLEX_EN; | ||
1012 | mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); | ||
1013 | val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER); | ||
1014 | val |= MVNETA_GMAC_1MS_CLOCK_ENABLE; | ||
1015 | mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val); | ||
1016 | } | ||
1017 | |||
997 | mvneta_set_ucast_table(pp, -1); | 1018 | mvneta_set_ucast_table(pp, -1); |
998 | mvneta_set_special_mcast_table(pp, -1); | 1019 | mvneta_set_special_mcast_table(pp, -1); |
999 | mvneta_set_other_mcast_table(pp, -1); | 1020 | mvneta_set_other_mcast_table(pp, -1); |
@@ -2043,6 +2064,28 @@ static irqreturn_t mvneta_isr(int irq, void *dev_id) | |||
2043 | return IRQ_HANDLED; | 2064 | return IRQ_HANDLED; |
2044 | } | 2065 | } |
2045 | 2066 | ||
2067 | static int mvneta_fixed_link_update(struct mvneta_port *pp, | ||
2068 | struct phy_device *phy) | ||
2069 | { | ||
2070 | struct fixed_phy_status status; | ||
2071 | struct fixed_phy_status changed = {}; | ||
2072 | u32 gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS); | ||
2073 | |||
2074 | status.link = !!(gmac_stat & MVNETA_GMAC_LINK_UP); | ||
2075 | if (gmac_stat & MVNETA_GMAC_SPEED_1000) | ||
2076 | status.speed = SPEED_1000; | ||
2077 | else if (gmac_stat & MVNETA_GMAC_SPEED_100) | ||
2078 | status.speed = SPEED_100; | ||
2079 | else | ||
2080 | status.speed = SPEED_10; | ||
2081 | status.duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX); | ||
2082 | changed.link = 1; | ||
2083 | changed.speed = 1; | ||
2084 | changed.duplex = 1; | ||
2085 | fixed_phy_update_state(phy, &status, &changed); | ||
2086 | return 0; | ||
2087 | } | ||
2088 | |||
2046 | /* NAPI handler | 2089 | /* NAPI handler |
2047 | * Bits 0 - 7 of the causeRxTx register indicate that are transmitted | 2090 | * Bits 0 - 7 of the causeRxTx register indicate that are transmitted |
2048 | * packets on the corresponding TXQ (Bit 0 is for TX queue 1). | 2091 | * packets on the corresponding TXQ (Bit 0 is for TX queue 1). |
@@ -2063,8 +2106,18 @@ static int mvneta_poll(struct napi_struct *napi, int budget) | |||
2063 | } | 2106 | } |
2064 | 2107 | ||
2065 | /* Read cause register */ | 2108 | /* Read cause register */ |
2066 | cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE) & | 2109 | cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE); |
2067 | (MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); | 2110 | if (cause_rx_tx & MVNETA_MISCINTR_INTR_MASK) { |
2111 | u32 cause_misc = mvreg_read(pp, MVNETA_INTR_MISC_CAUSE); | ||
2112 | |||
2113 | mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); | ||
2114 | if (pp->use_inband_status && (cause_misc & | ||
2115 | (MVNETA_CAUSE_PHY_STATUS_CHANGE | | ||
2116 | MVNETA_CAUSE_LINK_CHANGE | | ||
2117 | MVNETA_CAUSE_PSC_SYNC_CHANGE))) { | ||
2118 | mvneta_fixed_link_update(pp, pp->phy_dev); | ||
2119 | } | ||
2120 | } | ||
2068 | 2121 | ||
2069 | /* Release Tx descriptors */ | 2122 | /* Release Tx descriptors */ |
2070 | if (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL) { | 2123 | if (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL) { |
@@ -2109,7 +2162,9 @@ static int mvneta_poll(struct napi_struct *napi, int budget) | |||
2109 | napi_complete(napi); | 2162 | napi_complete(napi); |
2110 | local_irq_save(flags); | 2163 | local_irq_save(flags); |
2111 | mvreg_write(pp, MVNETA_INTR_NEW_MASK, | 2164 | mvreg_write(pp, MVNETA_INTR_NEW_MASK, |
2112 | MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); | 2165 | MVNETA_RX_INTR_MASK(rxq_number) | |
2166 | MVNETA_TX_INTR_MASK(txq_number) | | ||
2167 | MVNETA_MISCINTR_INTR_MASK); | ||
2113 | local_irq_restore(flags); | 2168 | local_irq_restore(flags); |
2114 | } | 2169 | } |
2115 | 2170 | ||
@@ -2373,7 +2428,13 @@ static void mvneta_start_dev(struct mvneta_port *pp) | |||
2373 | 2428 | ||
2374 | /* Unmask interrupts */ | 2429 | /* Unmask interrupts */ |
2375 | mvreg_write(pp, MVNETA_INTR_NEW_MASK, | 2430 | mvreg_write(pp, MVNETA_INTR_NEW_MASK, |
2376 | MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); | 2431 | MVNETA_RX_INTR_MASK(rxq_number) | |
2432 | MVNETA_TX_INTR_MASK(txq_number) | | ||
2433 | MVNETA_MISCINTR_INTR_MASK); | ||
2434 | mvreg_write(pp, MVNETA_INTR_MISC_MASK, | ||
2435 | MVNETA_CAUSE_PHY_STATUS_CHANGE | | ||
2436 | MVNETA_CAUSE_LINK_CHANGE | | ||
2437 | MVNETA_CAUSE_PSC_SYNC_CHANGE); | ||
2377 | 2438 | ||
2378 | phy_start(pp->phy_dev); | 2439 | phy_start(pp->phy_dev); |
2379 | netif_tx_start_all_queues(pp->dev); | 2440 | netif_tx_start_all_queues(pp->dev); |
@@ -2523,9 +2584,7 @@ static void mvneta_adjust_link(struct net_device *ndev) | |||
2523 | val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); | 2584 | val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); |
2524 | val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED | | 2585 | val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED | |
2525 | MVNETA_GMAC_CONFIG_GMII_SPEED | | 2586 | MVNETA_GMAC_CONFIG_GMII_SPEED | |
2526 | MVNETA_GMAC_CONFIG_FULL_DUPLEX | | 2587 | MVNETA_GMAC_CONFIG_FULL_DUPLEX); |
2527 | MVNETA_GMAC_AN_SPEED_EN | | ||
2528 | MVNETA_GMAC_AN_DUPLEX_EN); | ||
2529 | 2588 | ||
2530 | if (phydev->duplex) | 2589 | if (phydev->duplex) |
2531 | val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; | 2590 | val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; |
@@ -2554,12 +2613,24 @@ static void mvneta_adjust_link(struct net_device *ndev) | |||
2554 | 2613 | ||
2555 | if (status_change) { | 2614 | if (status_change) { |
2556 | if (phydev->link) { | 2615 | if (phydev->link) { |
2557 | u32 val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); | 2616 | if (!pp->use_inband_status) { |
2558 | val |= (MVNETA_GMAC_FORCE_LINK_PASS | | 2617 | u32 val = mvreg_read(pp, |
2559 | MVNETA_GMAC_FORCE_LINK_DOWN); | 2618 | MVNETA_GMAC_AUTONEG_CONFIG); |
2560 | mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); | 2619 | val &= ~MVNETA_GMAC_FORCE_LINK_DOWN; |
2620 | val |= MVNETA_GMAC_FORCE_LINK_PASS; | ||
2621 | mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, | ||
2622 | val); | ||
2623 | } | ||
2561 | mvneta_port_up(pp); | 2624 | mvneta_port_up(pp); |
2562 | } else { | 2625 | } else { |
2626 | if (!pp->use_inband_status) { | ||
2627 | u32 val = mvreg_read(pp, | ||
2628 | MVNETA_GMAC_AUTONEG_CONFIG); | ||
2629 | val &= ~MVNETA_GMAC_FORCE_LINK_PASS; | ||
2630 | val |= MVNETA_GMAC_FORCE_LINK_DOWN; | ||
2631 | mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, | ||
2632 | val); | ||
2633 | } | ||
2563 | mvneta_port_down(pp); | 2634 | mvneta_port_down(pp); |
2564 | } | 2635 | } |
2565 | phy_print_status(phydev); | 2636 | phy_print_status(phydev); |
@@ -2910,6 +2981,9 @@ static int mvneta_port_power_up(struct mvneta_port *pp, int phy_mode) | |||
2910 | return -EINVAL; | 2981 | return -EINVAL; |
2911 | } | 2982 | } |
2912 | 2983 | ||
2984 | if (pp->use_inband_status) | ||
2985 | ctrl |= MVNETA_GMAC2_INBAND_AN_ENABLE; | ||
2986 | |||
2913 | /* Cancel Port Reset */ | 2987 | /* Cancel Port Reset */ |
2914 | ctrl &= ~MVNETA_GMAC2_PORT_RESET; | 2988 | ctrl &= ~MVNETA_GMAC2_PORT_RESET; |
2915 | mvreg_write(pp, MVNETA_GMAC_CTRL_2, ctrl); | 2989 | mvreg_write(pp, MVNETA_GMAC_CTRL_2, ctrl); |
@@ -2934,6 +3008,7 @@ static int mvneta_probe(struct platform_device *pdev) | |||
2934 | char hw_mac_addr[ETH_ALEN]; | 3008 | char hw_mac_addr[ETH_ALEN]; |
2935 | const char *mac_from; | 3009 | const char *mac_from; |
2936 | int phy_mode; | 3010 | int phy_mode; |
3011 | int fixed_phy = 0; | ||
2937 | int err; | 3012 | int err; |
2938 | 3013 | ||
2939 | /* Our multiqueue support is not complete, so for now, only | 3014 | /* Our multiqueue support is not complete, so for now, only |
@@ -2967,6 +3042,7 @@ static int mvneta_probe(struct platform_device *pdev) | |||
2967 | dev_err(&pdev->dev, "cannot register fixed PHY\n"); | 3042 | dev_err(&pdev->dev, "cannot register fixed PHY\n"); |
2968 | goto err_free_irq; | 3043 | goto err_free_irq; |
2969 | } | 3044 | } |
3045 | fixed_phy = 1; | ||
2970 | 3046 | ||
2971 | /* In the case of a fixed PHY, the DT node associated | 3047 | /* In the case of a fixed PHY, the DT node associated |
2972 | * to the PHY is the Ethernet MAC DT node. | 3048 | * to the PHY is the Ethernet MAC DT node. |
@@ -2990,6 +3066,8 @@ static int mvneta_probe(struct platform_device *pdev) | |||
2990 | pp = netdev_priv(dev); | 3066 | pp = netdev_priv(dev); |
2991 | pp->phy_node = phy_node; | 3067 | pp->phy_node = phy_node; |
2992 | pp->phy_interface = phy_mode; | 3068 | pp->phy_interface = phy_mode; |
3069 | pp->use_inband_status = (phy_mode == PHY_INTERFACE_MODE_SGMII) && | ||
3070 | fixed_phy; | ||
2993 | 3071 | ||
2994 | pp->clk = devm_clk_get(&pdev->dev, NULL); | 3072 | pp->clk = devm_clk_get(&pdev->dev, NULL); |
2995 | if (IS_ERR(pp->clk)) { | 3073 | if (IS_ERR(pp->clk)) { |
@@ -3067,6 +3145,12 @@ static int mvneta_probe(struct platform_device *pdev) | |||
3067 | 3145 | ||
3068 | platform_set_drvdata(pdev, pp->dev); | 3146 | platform_set_drvdata(pdev, pp->dev); |
3069 | 3147 | ||
3148 | if (pp->use_inband_status) { | ||
3149 | struct phy_device *phy = of_phy_find_device(dn); | ||
3150 | |||
3151 | mvneta_fixed_link_update(pp, phy); | ||
3152 | } | ||
3153 | |||
3070 | return 0; | 3154 | return 0; |
3071 | 3155 | ||
3072 | err_free_stats: | 3156 | err_free_stats: |