summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/amd/xgbe
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/amd/xgbe')
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c137
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c217
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-main.c20
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-mdio.c167
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-pci.c36
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c349
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h31
7 files changed, 699 insertions, 258 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 7c204f05b4183..24f1053b8785e 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1312,14 +1312,83 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
return 0;
}
+static void xgbe_free_memory(struct xgbe_prv_data *pdata)
+{
+ struct xgbe_desc_if *desc_if = &pdata->desc_if;
+
+ /* Free the ring descriptors and buffers */
+ desc_if->free_ring_resources(pdata);
+
+ /* Free the channel and ring structures */
+ xgbe_free_channels(pdata);
+}
+
+static int xgbe_alloc_memory(struct xgbe_prv_data *pdata)
+{
+ struct xgbe_desc_if *desc_if = &pdata->desc_if;
+ struct net_device *netdev = pdata->netdev;
+ int ret;
+
+ if (pdata->new_tx_ring_count) {
+ pdata->tx_ring_count = pdata->new_tx_ring_count;
+ pdata->tx_q_count = pdata->tx_ring_count;
+ pdata->new_tx_ring_count = 0;
+ }
+
+ if (pdata->new_rx_ring_count) {
+ pdata->rx_ring_count = pdata->new_rx_ring_count;
+ pdata->new_rx_ring_count = 0;
+ }
+
+ /* Calculate the Rx buffer size before allocating rings */
+ pdata->rx_buf_size = xgbe_calc_rx_buf_size(netdev, netdev->mtu);
+
+ /* Allocate the channel and ring structures */
+ ret = xgbe_alloc_channels(pdata);
+ if (ret)
+ return ret;
+
+ /* Allocate the ring descriptors and buffers */
+ ret = desc_if->alloc_ring_resources(pdata);
+ if (ret)
+ goto err_channels;
+
+ /* Initialize the service and Tx timers */
+ xgbe_init_timers(pdata);
+
+ return 0;
+
+err_channels:
+ xgbe_free_memory(pdata);
+
+ return ret;
+}
+
static int xgbe_start(struct xgbe_prv_data *pdata)
{
struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_phy_if *phy_if = &pdata->phy_if;
struct net_device *netdev = pdata->netdev;
+ unsigned int i;
int ret;
- DBGPR("-->xgbe_start\n");
+ /* Set the number of queues */
+ ret = netif_set_real_num_tx_queues(netdev, pdata->tx_ring_count);
+ if (ret) {
+ netdev_err(netdev, "error setting real tx queue count\n");
+ return ret;
+ }
+
+ ret = netif_set_real_num_rx_queues(netdev, pdata->rx_ring_count);
+ if (ret) {
+ netdev_err(netdev, "error setting real rx queue count\n");
+ return ret;
+ }
+
+ /* Set RSS lookup table data for programming */
+ for (i = 0; i < XGBE_RSS_MAX_TABLE_SIZE; i++)
+ XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH,
+ i % pdata->rx_ring_count);
ret = hw_if->init(pdata);
if (ret)
@@ -1347,8 +1416,6 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
clear_bit(XGBE_STOPPED, &pdata->dev_state);
- DBGPR("<--xgbe_start\n");
-
return 0;
err_irqs:
@@ -1426,10 +1493,22 @@ static void xgbe_stopdev(struct work_struct *work)
netdev_alert(pdata->netdev, "device stopped\n");
}
-static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
+void xgbe_full_restart_dev(struct xgbe_prv_data *pdata)
{
- DBGPR("-->xgbe_restart_dev\n");
+ /* If not running, "restart" will happen on open */
+ if (!netif_running(pdata->netdev))
+ return;
+
+ xgbe_stop(pdata);
+
+ xgbe_free_memory(pdata);
+ xgbe_alloc_memory(pdata);
+
+ xgbe_start(pdata);
+}
+void xgbe_restart_dev(struct xgbe_prv_data *pdata)
+{
/* If not running, "restart" will happen on open */
if (!netif_running(pdata->netdev))
return;
@@ -1440,8 +1519,6 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
xgbe_free_rx_data(pdata);
xgbe_start(pdata);
-
- DBGPR("<--xgbe_restart_dev\n");
}
static void xgbe_restart(struct work_struct *work)
@@ -1827,11 +1904,8 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata,
static int xgbe_open(struct net_device *netdev)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
- struct xgbe_desc_if *desc_if = &pdata->desc_if;
int ret;
- DBGPR("-->xgbe_open\n");
-
/* Create the various names based on netdev name */
snprintf(pdata->an_name, sizeof(pdata->an_name) - 1, "%s-pcs",
netdev_name(netdev));
@@ -1876,43 +1950,25 @@ static int xgbe_open(struct net_device *netdev)
goto err_sysclk;
}
- /* Calculate the Rx buffer size before allocating rings */
- ret = xgbe_calc_rx_buf_size(netdev, netdev->mtu);
- if (ret < 0)
- goto err_ptpclk;
- pdata->rx_buf_size = ret;
-
- /* Allocate the channel and ring structures */
- ret = xgbe_alloc_channels(pdata);
- if (ret)
- goto err_ptpclk;
-
- /* Allocate the ring descriptors and buffers */
- ret = desc_if->alloc_ring_resources(pdata);
- if (ret)
- goto err_channels;
-
INIT_WORK(&pdata->service_work, xgbe_service);
INIT_WORK(&pdata->restart_work, xgbe_restart);
INIT_WORK(&pdata->stopdev_work, xgbe_stopdev);
INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp);
- xgbe_init_timers(pdata);
+
+ ret = xgbe_alloc_memory(pdata);
+ if (ret)
+ goto err_ptpclk;
ret = xgbe_start(pdata);
if (ret)
- goto err_rings;
+ goto err_mem;
clear_bit(XGBE_DOWN, &pdata->dev_state);
- DBGPR("<--xgbe_open\n");
-
return 0;
-err_rings:
- desc_if->free_ring_resources(pdata);
-
-err_channels:
- xgbe_free_channels(pdata);
+err_mem:
+ xgbe_free_memory(pdata);
err_ptpclk:
clk_disable_unprepare(pdata->ptpclk);
@@ -1932,18 +1988,11 @@ err_dev_wq:
static int xgbe_close(struct net_device *netdev)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
- struct xgbe_desc_if *desc_if = &pdata->desc_if;
-
- DBGPR("-->xgbe_close\n");
/* Stop the device */
xgbe_stop(pdata);
- /* Free the ring descriptors and buffers */
- desc_if->free_ring_resources(pdata);
-
- /* Free the channel and ring structures */
- xgbe_free_channels(pdata);
+ xgbe_free_memory(pdata);
/* Disable the clocks */
clk_disable_unprepare(pdata->ptpclk);
@@ -1957,8 +2006,6 @@ static int xgbe_close(struct net_device *netdev)
set_bit(XGBE_DOWN, &pdata->dev_state);
- DBGPR("<--xgbe_close\n");
-
return 0;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
index ff397bb25042c..a880f10e3e703 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -626,6 +626,217 @@ static int xgbe_get_ts_info(struct net_device *netdev,
return 0;
}
+static int xgbe_get_module_info(struct net_device *netdev,
+ struct ethtool_modinfo *modinfo)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+
+ return pdata->phy_if.module_info(pdata, modinfo);
+}
+
+static int xgbe_get_module_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+
+ return pdata->phy_if.module_eeprom(pdata, eeprom, data);
+}
+
+static void xgbe_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ringparam)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+
+ ringparam->rx_max_pending = XGBE_RX_DESC_CNT_MAX;
+ ringparam->tx_max_pending = XGBE_TX_DESC_CNT_MAX;
+ ringparam->rx_pending = pdata->rx_desc_count;
+ ringparam->tx_pending = pdata->tx_desc_count;
+}
+
+static int xgbe_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ringparam)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+ unsigned int rx, tx;
+
+ if (ringparam->rx_mini_pending || ringparam->rx_jumbo_pending) {
+ netdev_err(netdev, "unsupported ring parameter\n");
+ return -EINVAL;
+ }
+
+ if ((ringparam->rx_pending < XGBE_RX_DESC_CNT_MIN) ||
+ (ringparam->rx_pending > XGBE_RX_DESC_CNT_MAX)) {
+ netdev_err(netdev,
+ "rx ring parameter must be between %u and %u\n",
+ XGBE_RX_DESC_CNT_MIN, XGBE_RX_DESC_CNT_MAX);
+ return -EINVAL;
+ }
+
+ if ((ringparam->tx_pending < XGBE_TX_DESC_CNT_MIN) ||
+ (ringparam->tx_pending > XGBE_TX_DESC_CNT_MAX)) {
+ netdev_err(netdev,
+ "tx ring parameter must be between %u and %u\n",
+ XGBE_TX_DESC_CNT_MIN, XGBE_TX_DESC_CNT_MAX);
+ return -EINVAL;
+ }
+
+ rx = __rounddown_pow_of_two(ringparam->rx_pending);
+ if (rx != ringparam->rx_pending)
+ netdev_notice(netdev,
+ "rx ring parameter rounded to power of two: %u\n",
+ rx);
+
+ tx = __rounddown_pow_of_two(ringparam->tx_pending);
+ if (tx != ringparam->tx_pending)
+ netdev_notice(netdev,
+ "tx ring parameter rounded to power of two: %u\n",
+ tx);
+
+ if ((rx == pdata->rx_desc_count) &&
+ (tx == pdata->tx_desc_count))
+ goto out;
+
+ pdata->rx_desc_count = rx;
+ pdata->tx_desc_count = tx;
+
+ xgbe_restart_dev(pdata);
+
+out:
+ return 0;
+}
+
+static void xgbe_get_channels(struct net_device *netdev,
+ struct ethtool_channels *channels)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+ unsigned int rx, tx, combined;
+
+ /* Calculate maximums allowed:
+ * - Take into account the number of available IRQs
+ * - Do not take into account the number of online CPUs so that
+ * the user can over-subscribe if desired
+ * - Tx is additionally limited by the number of hardware queues
+ */
+ rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count);
+ rx = min(rx, pdata->channel_irq_count);
+ tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count);
+ tx = min(tx, pdata->channel_irq_count);
+ tx = min(tx, pdata->tx_max_q_count);
+
+ combined = min(rx, tx);
+
+ channels->max_combined = combined;
+ channels->max_rx = rx ? rx - 1 : 0;
+ channels->max_tx = tx ? tx - 1 : 0;
+
+ /* Get current settings based on device state */
+ rx = pdata->new_rx_ring_count ? : pdata->rx_ring_count;
+ tx = pdata->new_tx_ring_count ? : pdata->tx_ring_count;
+
+ combined = min(rx, tx);
+ rx -= combined;
+ tx -= combined;
+
+ channels->combined_count = combined;
+ channels->rx_count = rx;
+ channels->tx_count = tx;
+}
+
+static void xgbe_print_set_channels_input(struct net_device *netdev,
+ struct ethtool_channels *channels)
+{
+ netdev_err(netdev, "channel inputs: combined=%u, rx-only=%u, tx-only=%u\n",
+ channels->combined_count, channels->rx_count,
+ channels->tx_count);
+}
+
+static int xgbe_set_channels(struct net_device *netdev,
+ struct ethtool_channels *channels)
+{
+ struct xgbe_prv_data *pdata = netdev_priv(netdev);
+ unsigned int rx, rx_curr, tx, tx_curr, combined;
+
+ /* Calculate maximums allowed:
+ * - Take into account the number of available IRQs
+ * - Do not take into account the number of online CPUs so that
+ * the user can over-subscribe if desired
+ * - Tx is additionally limited by the number of hardware queues
+ */
+ rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count);
+ rx = min(rx, pdata->channel_irq_count);
+ tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count);
+ tx = min(tx, pdata->tx_max_q_count);
+ tx = min(tx, pdata->channel_irq_count);
+
+ combined = min(rx, tx);
+
+ /* Should not be setting other count */
+ if (channels->other_count) {
+ netdev_err(netdev,
+ "other channel count must be zero\n");
+ return -EINVAL;
+ }
+
+ /* Require at least one Combined (Rx and Tx) channel */
+ if (!channels->combined_count) {
+ netdev_err(netdev,
+ "at least one combined Rx/Tx channel is required\n");
+ xgbe_print_set_channels_input(netdev, channels);
+ return -EINVAL;
+ }
+
+ /* Check combined channels */
+ if (channels->combined_count > combined) {
+ netdev_err(netdev,
+ "combined channel count cannot exceed %u\n",
+ combined);
+ xgbe_print_set_channels_input(netdev, channels);
+ return -EINVAL;
+ }
+
+ /* Can have some Rx-only or Tx-only channels, but not both */
+ if (channels->rx_count && channels->tx_count) {
+ netdev_err(netdev,
+ "cannot specify both Rx-only and Tx-only channels\n");
+ xgbe_print_set_channels_input(netdev, channels);
+ return -EINVAL;
+ }
+
+ /* Check that we don't exceed the maximum number of channels */
+ if ((channels->combined_count + channels->rx_count) > rx) {
+ netdev_err(netdev,
+ "total Rx channels (%u) requested exceeds maximum available (%u)\n",
+ channels->combined_count + channels->rx_count, rx);
+ xgbe_print_set_channels_input(netdev, channels);
+ return -EINVAL;
+ }
+
+ if ((channels->combined_count + channels->tx_count) > tx) {
+ netdev_err(netdev,
+ "total Tx channels (%u) requested exceeds maximum available (%u)\n",
+ channels->combined_count + channels->tx_count, tx);
+ xgbe_print_set_channels_input(netdev, channels);
+ return -EINVAL;
+ }
+
+ rx = channels->combined_count + channels->rx_count;
+ tx = channels->combined_count + channels->tx_count;
+
+ rx_curr = pdata->new_rx_ring_count ? : pdata->rx_ring_count;
+ tx_curr = pdata->new_tx_ring_count ? : pdata->tx_ring_count;
+
+ if ((rx == rx_curr) && (tx == tx_curr))
+ goto out;
+
+ pdata->new_rx_ring_count = rx;
+ pdata->new_tx_ring_count = tx;
+
+ xgbe_full_restart_dev(pdata);
+
+out:
+ return 0;
+}
+
static const struct ethtool_ops xgbe_ethtool_ops = {
.get_drvinfo = xgbe_get_drvinfo,
.get_msglevel = xgbe_get_msglevel,
@@ -646,6 +857,12 @@ static const struct ethtool_ops xgbe_ethtool_ops = {
.get_ts_info = xgbe_get_ts_info,
.get_link_ksettings = xgbe_get_link_ksettings,
.set_link_ksettings = xgbe_set_link_ksettings,
+ .get_module_info = xgbe_get_module_info,
+ .get_module_eeprom = xgbe_get_module_eeprom,
+ .get_ringparam = xgbe_get_ringparam,
+ .set_ringparam = xgbe_set_ringparam,
+ .get_channels = xgbe_get_channels,
+ .set_channels = xgbe_set_channels,
};
const struct ethtool_ops *xgbe_get_ethtool_ops(void)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index 441d0973957ba..b41f23679a087 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -265,7 +265,6 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
{
struct net_device *netdev = pdata->netdev;
struct device *dev = pdata->dev;
- unsigned int i;
int ret;
netdev->irq = pdata->dev_irq;
@@ -324,26 +323,9 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
pdata->tx_ring_count, pdata->rx_ring_count);
}
- /* Set the number of queues */
- ret = netif_set_real_num_tx_queues(netdev, pdata->tx_ring_count);
- if (ret) {
- dev_err(dev, "error setting real tx queue count\n");
- return ret;
- }
-
- ret = netif_set_real_num_rx_queues(netdev, pdata->rx_ring_count);
- if (ret) {
- dev_err(dev, "error setting real rx queue count\n");
- return ret;
- }
-
- /* Initialize RSS hash key and lookup table */
+ /* Initialize RSS hash key */
netdev_rss_key_fill(pdata->rss_key, sizeof(pdata->rss_key));
- for (i = 0; i < XGBE_RSS_MAX_TABLE_SIZE; i++)
- XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH,
- i % pdata->rx_ring_count);
-
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, IP2TE, 1);
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
index 1b45cd73a258f..4b5d625de8f0b 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -126,6 +126,24 @@
#include "xgbe.h"
#include "xgbe-common.h"
+static int xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ if (!pdata->phy_if.phy_impl.module_eeprom)
+ return -ENXIO;
+
+ return pdata->phy_if.phy_impl.module_eeprom(pdata, eeprom, data);
+}
+
+static int xgbe_phy_module_info(struct xgbe_prv_data *pdata,
+ struct ethtool_modinfo *modinfo)
+{
+ if (!pdata->phy_if.phy_impl.module_info)
+ return -ENXIO;
+
+ return pdata->phy_if.phy_impl.module_info(pdata, modinfo);
+}
+
static void xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata)
{
int reg;
@@ -198,31 +216,8 @@ static void xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata)
xgbe_an37_clear_interrupts(pdata);
}
-static void xgbe_an73_enable_kr_training(struct xgbe_prv_data *pdata)
-{
- unsigned int reg;
-
- reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
-
- reg |= XGBE_KR_TRAINING_ENABLE;
- XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
-}
-
-static void xgbe_an73_disable_kr_training(struct xgbe_prv_data *pdata)
-{
- unsigned int reg;
-
- reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
-
- reg &= ~XGBE_KR_TRAINING_ENABLE;
- XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
-}
-
static void xgbe_kr_mode(struct xgbe_prv_data *pdata)
{
- /* Enable KR training */
- xgbe_an73_enable_kr_training(pdata);
-
/* Set MAC to 10G speed */
pdata->hw_if.set_speed(pdata, SPEED_10000);
@@ -232,9 +227,6 @@ static void xgbe_kr_mode(struct xgbe_prv_data *pdata)
static void xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
{
- /* Disable KR training */
- xgbe_an73_disable_kr_training(pdata);
-
/* Set MAC to 2.5G speed */
pdata->hw_if.set_speed(pdata, SPEED_2500);
@@ -244,9 +236,6 @@ static void xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
{
- /* Disable KR training */
- xgbe_an73_disable_kr_training(pdata);
-
/* Set MAC to 1G speed */
pdata->hw_if.set_speed(pdata, SPEED_1000);
@@ -260,9 +249,6 @@ static void xgbe_sfi_mode(struct xgbe_prv_data *pdata)
if (pdata->kr_redrv)
return xgbe_kr_mode(pdata);
- /* Disable KR training */
- xgbe_an73_disable_kr_training(pdata);
-
/* Set MAC to 10G speed */
pdata->hw_if.set_speed(pdata, SPEED_10000);
@@ -272,9 +258,6 @@ static void xgbe_sfi_mode(struct xgbe_prv_data *pdata)
static void xgbe_x_mode(struct xgbe_prv_data *pdata)
{
- /* Disable KR training */
- xgbe_an73_disable_kr_training(pdata);
-
/* Set MAC to 1G speed */
pdata->hw_if.set_speed(pdata, SPEED_1000);
@@ -284,9 +267,6 @@ static void xgbe_x_mode(struct xgbe_prv_data *pdata)
static void xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
{
- /* Disable KR training */
- xgbe_an73_disable_kr_training(pdata);
-
/* Set MAC to 1G speed */
pdata->hw_if.set_speed(pdata, SPEED_1000);
@@ -296,9 +276,6 @@ static void xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
static void xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
{
- /* Disable KR training */
- xgbe_an73_disable_kr_training(pdata);
-
/* Set MAC to 1G speed */
pdata->hw_if.set_speed(pdata, SPEED_1000);
@@ -354,13 +331,15 @@ static void xgbe_switch_mode(struct xgbe_prv_data *pdata)
xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
}
-static void xgbe_set_mode(struct xgbe_prv_data *pdata,
+static bool xgbe_set_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode)
{
if (mode == xgbe_cur_mode(pdata))
- return;
+ return false;
xgbe_change_mode(pdata, mode);
+
+ return true;
}
static bool xgbe_use_mode(struct xgbe_prv_data *pdata,
@@ -407,6 +386,12 @@ static void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable,
{
unsigned int reg;
+ /* Disable KR training for now */
+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
+ reg &= ~XGBE_KR_TRAINING_ENABLE;
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
+
+ /* Update AN settings */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
reg &= ~MDIO_AN_CTRL1_ENABLE;
@@ -504,21 +489,19 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
/* Start KR training */
- reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- if (reg & XGBE_KR_TRAINING_ENABLE) {
- if (pdata->phy_if.phy_impl.kr_training_pre)
- pdata->phy_if.phy_impl.kr_training_pre(pdata);
+ 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 = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
+ reg |= XGBE_KR_TRAINING_ENABLE;
+ reg |= XGBE_KR_TRAINING_START;
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
- netif_dbg(pdata, link, pdata->netdev,
- "KR training initiated\n");
+ netif_dbg(pdata, link, pdata->netdev,
+ "KR training initiated\n");
- if (pdata->phy_if.phy_impl.kr_training_post)
- pdata->phy_if.phy_impl.kr_training_post(pdata);
- }
+ if (pdata->phy_if.phy_impl.kr_training_post)
+ pdata->phy_if.phy_impl.kr_training_post(pdata);
return XGBE_AN_PAGE_RECEIVED;
}
@@ -1197,21 +1180,23 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
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;
+ mutex_lock(&pdata->an_mutex);
+
set_bit(XGBE_LINK_INIT, &pdata->dev_state);
pdata->link_check = jiffies;
ret = pdata->phy_if.phy_impl.an_config(pdata);
if (ret)
- return ret;
+ goto out;
if (pdata->phy.autoneg != AUTONEG_ENABLE) {
ret = xgbe_phy_config_fixed(pdata);
if (ret || !pdata->kr_redrv)
- return ret;
+ goto out;
netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n");
} else {
@@ -1221,24 +1206,27 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
/* Disable auto-negotiation interrupt */
disable_irq(pdata->an_irq);
- /* 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 if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
- xgbe_set_mode(pdata, XGBE_MODE_SFI);
- } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
- xgbe_set_mode(pdata, XGBE_MODE_X);
- } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
- xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
- } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
- xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
- } else {
- enable_irq(pdata->an_irq);
- 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 if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
+ xgbe_set_mode(pdata, XGBE_MODE_SFI);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
+ xgbe_set_mode(pdata, XGBE_MODE_X);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
+ xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
+ xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
+ } else {
+ enable_irq(pdata->an_irq);
+ ret = -EINVAL;
+ goto out;
+ }
}
/* Disable and stop any in progress auto-negotiation */
@@ -1258,16 +1246,7 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
xgbe_an_init(pdata);
xgbe_an_restart(pdata);
- return 0;
-}
-
-static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
-{
- int ret;
-
- mutex_lock(&pdata->an_mutex);
-
- ret = __xgbe_phy_config_aneg(pdata);
+out:
if (ret)
set_bit(XGBE_LINK_ERR, &pdata->dev_state);
else
@@ -1278,6 +1257,16 @@ static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
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)
{
return (pdata->an_result == XGBE_AN_COMPLETE);
@@ -1334,7 +1323,8 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
pdata->phy.duplex = DUPLEX_FULL;
- xgbe_set_mode(pdata, mode);
+ if (xgbe_set_mode(pdata, mode) && pdata->an_again)
+ xgbe_phy_reconfig_aneg(pdata);
}
static void xgbe_phy_status(struct xgbe_prv_data *pdata)
@@ -1639,4 +1629,7 @@ void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
phy_if->phy_valid_speed = xgbe_phy_valid_speed;
phy_if->an_isr = xgbe_an_combined_isr;
+
+ phy_if->module_info = xgbe_phy_module_info;
+ phy_if->module_eeprom = xgbe_phy_module_eeprom;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c
index 82d1f416ee2ac..7b86240ecd5fe 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c
@@ -335,16 +335,33 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pdata->awcr = XGBE_DMA_PCI_AWCR;
pdata->awarcr = XGBE_DMA_PCI_AWARCR;
+ /* Read the port property registers */
+ pdata->pp0 = XP_IOREAD(pdata, XP_PROP_0);
+ pdata->pp1 = XP_IOREAD(pdata, XP_PROP_1);
+ pdata->pp2 = XP_IOREAD(pdata, XP_PROP_2);
+ pdata->pp3 = XP_IOREAD(pdata, XP_PROP_3);
+ pdata->pp4 = XP_IOREAD(pdata, XP_PROP_4);
+ if (netif_msg_probe(pdata)) {
+ dev_dbg(dev, "port property 0 = %#010x\n", pdata->pp0);
+ dev_dbg(dev, "port property 1 = %#010x\n", pdata->pp1);
+ dev_dbg(dev, "port property 2 = %#010x\n", pdata->pp2);
+ dev_dbg(dev, "port property 3 = %#010x\n", pdata->pp3);
+ dev_dbg(dev, "port property 4 = %#010x\n", pdata->pp4);
+ }
+
/* Set the maximum channels and queues */
- reg = XP_IOREAD(pdata, XP_PROP_1);
- pdata->tx_max_channel_count = XP_GET_BITS(reg, XP_PROP_1, MAX_TX_DMA);
- pdata->rx_max_channel_count = XP_GET_BITS(reg, XP_PROP_1, MAX_RX_DMA);
- pdata->tx_max_q_count = XP_GET_BITS(reg, XP_PROP_1, MAX_TX_QUEUES);
- pdata->rx_max_q_count = XP_GET_BITS(reg, XP_PROP_1, MAX_RX_QUEUES);
+ pdata->tx_max_channel_count = XP_GET_BITS(pdata->pp1, XP_PROP_1,
+ MAX_TX_DMA);
+ pdata->rx_max_channel_count = XP_GET_BITS(pdata->pp1, XP_PROP_1,
+ MAX_RX_DMA);
+ pdata->tx_max_q_count = XP_GET_BITS(pdata->pp1, XP_PROP_1,
+ MAX_TX_QUEUES);
+ pdata->rx_max_q_count = XP_GET_BITS(pdata->pp1, XP_PROP_1,
+ MAX_RX_QUEUES);
if (netif_msg_probe(pdata)) {
dev_dbg(dev, "max tx/rx channel count = %u/%u\n",
pdata->tx_max_channel_count,
- pdata->tx_max_channel_count);
+ pdata->rx_max_channel_count);
dev_dbg(dev, "max tx/rx hw queue count = %u/%u\n",
pdata->tx_max_q_count, pdata->rx_max_q_count);
}
@@ -353,12 +370,13 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
xgbe_set_counts(pdata);
/* Set the maximum fifo amounts */
- reg = XP_IOREAD(pdata, XP_PROP_2);
- pdata->tx_max_fifo_size = XP_GET_BITS(reg, XP_PROP_2, TX_FIFO_SIZE);
+ pdata->tx_max_fifo_size = XP_GET_BITS(pdata->pp2, XP_PROP_2,
+ TX_FIFO_SIZE);
pdata->tx_max_fifo_size *= 16384;
pdata->tx_max_fifo_size = min(pdata->tx_max_fifo_size,
pdata->vdata->tx_max_fifo_size);
- pdata->rx_max_fifo_size = XP_GET_BITS(reg, XP_PROP_2, RX_FIFO_SIZE);
+ pdata->rx_max_fifo_size = XP_GET_BITS(pdata->pp2, XP_PROP_2,
+ RX_FIFO_SIZE);
pdata->rx_max_fifo_size *= 16384;
pdata->rx_max_fifo_size = min(pdata->rx_max_fifo_size,
pdata->vdata->rx_max_fifo_size);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
index aac884314000c..3ceb4f95ca7ca 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -119,6 +119,7 @@
#include <linux/kmod.h>
#include <linux/mdio.h>
#include <linux/phy.h>
+#include <linux/ethtool.h>
#include "xgbe.h"
#include "xgbe-common.h"
@@ -270,6 +271,15 @@ struct xgbe_sfp_eeprom {
u8 vendor[32];
};
+#define XGBE_SFP_DIAGS_SUPPORTED(_x) \
+ ((_x)->extd[XGBE_SFP_EXTD_SFF_8472] && \
+ !((_x)->extd[XGBE_SFP_EXTD_DIAG] & XGBE_SFP_EXTD_DIAG_ADDR_CHANGE))
+
+#define XGBE_SFP_EEPROM_BASE_LEN 256
+#define XGBE_SFP_EEPROM_DIAG_LEN 256
+#define XGBE_SFP_EEPROM_MAX (XGBE_SFP_EEPROM_BASE_LEN + \
+ XGBE_SFP_EEPROM_DIAG_LEN)
+
#define XGBE_BEL_FUSE_VENDOR "BEL-FUSE "
#define XGBE_BEL_FUSE_PARTNO "1GBT-SFP06 "
@@ -327,8 +337,6 @@ struct xgbe_phy_data {
unsigned int mdio_addr;
- unsigned int comm_owned;
-
/* SFP Support */
enum xgbe_sfp_comm sfp_comm;
unsigned int sfp_mux_address;
@@ -345,7 +353,6 @@ struct xgbe_phy_data {
unsigned int sfp_rx_los;
unsigned int sfp_tx_fault;
unsigned int sfp_mod_absent;
- unsigned int sfp_diags;
unsigned int sfp_changed;
unsigned int sfp_phy_avail;
unsigned int sfp_cable_len;
@@ -382,12 +389,6 @@ static enum xgbe_an_mode xgbe_phy_an_mode(struct xgbe_prv_data *pdata);
static int xgbe_phy_i2c_xfer(struct xgbe_prv_data *pdata,
struct xgbe_i2c_op *i2c_op)
{
- struct xgbe_phy_data *phy_data = pdata->phy_data;
-
- /* Be sure we own the bus */
- if (WARN_ON(!phy_data->comm_owned))
- return -EIO;
-
return pdata->i2c_if.i2c_xfer(pdata, i2c_op);
}
@@ -549,10 +550,6 @@ static int xgbe_phy_sfp_get_mux(struct xgbe_prv_data *pdata)
static void xgbe_phy_put_comm_ownership(struct xgbe_prv_data *pdata)
{
- struct xgbe_phy_data *phy_data = pdata->phy_data;
-
- phy_data->comm_owned = 0;
-
mutex_unlock(&xgbe_phy_comm_lock);
}
@@ -562,9 +559,6 @@ static int xgbe_phy_get_comm_ownership(struct xgbe_prv_data *pdata)
unsigned long timeout;
unsigned int mutex_id;
- if (phy_data->comm_owned)
- return 0;
-
/* The I2C and MDIO/GPIO bus is multiplexed between multiple devices,
* the driver needs to take the software mutex and then the hardware
* mutexes before being able to use the busses.
@@ -593,7 +587,6 @@ static int xgbe_phy_get_comm_ownership(struct xgbe_prv_data *pdata)
XP_IOWRITE(pdata, XP_I2C_MUTEX, mutex_id);
XP_IOWRITE(pdata, XP_MDIO_MUTEX, mutex_id);
- phy_data->comm_owned = 1;
return 0;
}
@@ -867,6 +860,9 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata)
struct xgbe_phy_data *phy_data = pdata->phy_data;
unsigned int phy_id = phy_data->phydev->phy_id;
+ if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
+ return false;
+
if ((phy_id & 0xfffffff0) != 0x01ff0cc0)
return false;
@@ -892,8 +888,83 @@ static bool xgbe_phy_finisar_phy_quirks(struct xgbe_prv_data *pdata)
return true;
}
+static bool xgbe_phy_belfuse_phy_quirks(struct xgbe_prv_data *pdata)
+{
+ struct xgbe_phy_data *phy_data = pdata->phy_data;
+ struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
+ unsigned int phy_id = phy_data->phydev->phy_id;
+ int reg;
+
+ if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
+ return false;
+
+ if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
+ XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
+ return false;
+
+ /* For Bel-Fuse, use the extra AN flag */
+ pdata->an_again = 1;
+
+ if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
+ XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN))
+ return false;
+
+ if ((phy_id & 0xfffffff0) != 0x03625d10)
+ return false;
+
+ /* Disable RGMII mode */
+ phy_write(phy_data->phydev, 0x18, 0x7007);
+ reg = phy_read(phy_data->phydev, 0x18);
+ phy_write(phy_data->phydev, 0x18, reg & ~0x0080);
+
+ /* Enable fiber register bank */
+ phy_write(phy_data->phydev, 0x1c, 0x7c00);
+ reg = phy_read(phy_data->phydev, 0x1c);
+ reg &= 0x03ff;
+ reg &= ~0x0001;
+ phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0001);
+
+ /* Power down SerDes */
+ reg = phy_read(phy_data->phydev, 0x00);
+ phy_write(phy_data->phydev, 0x00, reg | 0x00800);
+
+ /* Configure SGMII-to-Copper mode */
+ phy_write(phy_data->phydev, 0x1c, 0x7c00);
+ reg = phy_read(phy_data->phydev, 0x1c);
+ reg &= 0x03ff;
+ reg &= ~0x0006;
+ phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg | 0x0004);
+
+ /* Power up SerDes */
+ reg = phy_read(phy_data->phydev, 0x00);
+ phy_write(phy_data->phydev, 0x00, reg & ~0x00800);
+
+ /* Enable copper register bank */
+ phy_write(phy_data->phydev, 0x1c, 0x7c00);
+ reg = phy_read(phy_data->phydev, 0x1c);
+ reg &= 0x03ff;
+ reg &= ~0x0001;
+ phy_write(phy_data->phydev, 0x1c, 0x8000 | 0x7c00 | reg);
+
+ /* Power up SerDes */
+ reg = phy_read(phy_data->phydev, 0x00);
+ phy_write(phy_data->phydev, 0x00, reg & ~0x00800);
+
+ phy_data->phydev->supported = PHY_GBIT_FEATURES;
+ phy_data->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+ phy_data->phydev->advertising = phy_data->phydev->supported;
+
+ netif_dbg(pdata, drv, pdata->netdev,
+ "BelFuse PHY quirk in place\n");
+
+ return true;
+}
+
static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata)
{
+ if (xgbe_phy_belfuse_phy_quirks(pdata))
+ return;
+
if (xgbe_phy_finisar_phy_quirks(pdata))
return;
}
@@ -910,6 +981,9 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
if (phy_data->phydev)
return 0;
+ /* Clear the extra AN flag */
+ pdata->an_again = 0;
+
/* Check for the use of an external PHY */
if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE)
return 0;
@@ -1034,37 +1108,6 @@ static bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data)
return false;
}
-static bool xgbe_phy_belfuse_parse_quirks(struct xgbe_prv_data *pdata)
-{
- struct xgbe_phy_data *phy_data = pdata->phy_data;
- struct xgbe_sfp_eeprom *sfp_eeprom = &phy_data->sfp_eeprom;
-
- if (memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_NAME],
- XGBE_BEL_FUSE_VENDOR, XGBE_SFP_BASE_VENDOR_NAME_LEN))
- return false;
-
- if (!memcmp(&sfp_eeprom->base[XGBE_SFP_BASE_VENDOR_PN],
- XGBE_BEL_FUSE_PARTNO, XGBE_SFP_BASE_VENDOR_PN_LEN)) {
- phy_data->sfp_base = XGBE_SFP_BASE_1000_SX;
- phy_data->sfp_cable = XGBE_SFP_CABLE_ACTIVE;
- phy_data->sfp_speed = XGBE_SFP_SPEED_1000;
- if (phy_data->sfp_changed)
- netif_dbg(pdata, drv, pdata->netdev,
- "Bel-Fuse SFP quirk in place\n");
- return true;
- }
-
- return false;
-}
-
-static bool xgbe_phy_sfp_parse_quirks(struct xgbe_prv_data *pdata)
-{
- if (xgbe_phy_belfuse_parse_quirks(pdata))
- return true;
-
- return false;
-}
-
static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -1083,9 +1126,6 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata)
phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data);
phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data);
- if (xgbe_phy_sfp_parse_quirks(pdata))
- return;
-
/* Assume ACTIVE cable unless told it is PASSIVE */
if (sfp_base[XGBE_SFP_BASE_CABLE] & XGBE_SFP_BASE_CABLE_PASSIVE) {
phy_data->sfp_cable = XGBE_SFP_CABLE_PASSIVE;
@@ -1227,13 +1267,6 @@ static int xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata)
memcpy(&phy_data->sfp_eeprom, &sfp_eeprom, sizeof(sfp_eeprom));
- if (sfp_eeprom.extd[XGBE_SFP_EXTD_SFF_8472]) {
- u8 diag_type = sfp_eeprom.extd[XGBE_SFP_EXTD_DIAG];
-
- if (!(diag_type & XGBE_SFP_EXTD_DIAG_ADDR_CHANGE))
- phy_data->sfp_diags = 1;
- }
-
xgbe_phy_free_phy_device(pdata);
} else {
phy_data->sfp_changed = 0;
@@ -1283,7 +1316,6 @@ static void xgbe_phy_sfp_reset(struct xgbe_phy_data *phy_data)
phy_data->sfp_rx_los = 0;
phy_data->sfp_tx_fault = 0;
phy_data->sfp_mod_absent = 1;
- phy_data->sfp_diags = 0;
phy_data->sfp_base = XGBE_SFP_BASE_UNKNOWN;
phy_data->sfp_cable = XGBE_SFP_CABLE_UNKNOWN;
phy_data->sfp_speed = XGBE_SFP_SPEED_UNKNOWN;
@@ -1326,6 +1358,130 @@ put:
xgbe_phy_put_comm_ownership(pdata);
}
+static int xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct xgbe_phy_data *phy_data = pdata->phy_data;
+ u8 eeprom_addr, eeprom_data[XGBE_SFP_EEPROM_MAX];
+ struct xgbe_sfp_eeprom *sfp_eeprom;
+ unsigned int i, j, rem;
+ int ret;
+
+ rem = eeprom->len;
+
+ if (!eeprom->len) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((eeprom->offset + eeprom->len) > XGBE_SFP_EEPROM_MAX) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (phy_data->port_mode != XGBE_PORT_MODE_SFP) {
+ ret = -ENXIO;
+ goto done;
+ }
+
+ if (!netif_running(pdata->netdev)) {
+ ret = -EIO;
+ goto done;
+ }
+
+ if (phy_data->sfp_mod_absent) {
+ ret = -EIO;
+ goto done;
+ }
+
+ ret = xgbe_phy_get_comm_ownership(pdata);
+ if (ret) {
+ ret = -EIO;
+ goto done;
+ }
+
+ ret = xgbe_phy_sfp_get_mux(pdata);
+ if (ret) {
+ netdev_err(pdata->netdev, "I2C error setting SFP MUX\n");
+ ret = -EIO;
+ goto put_own;
+ }
+
+ /* Read the SFP serial ID eeprom */
+ eeprom_addr = 0;
+ ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_SERIAL_ID_ADDRESS,
+ &eeprom_addr, sizeof(eeprom_addr),
+ eeprom_data, XGBE_SFP_EEPROM_BASE_LEN);
+ if (ret) {
+ netdev_err(pdata->netdev,
+ "I2C error reading SFP EEPROM\n");
+ ret = -EIO;
+ goto put_mux;
+ }
+
+ sfp_eeprom = (struct xgbe_sfp_eeprom *)eeprom_data;
+
+ if (XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom)) {
+ /* Read the SFP diagnostic eeprom */
+ eeprom_addr = 0;
+ ret = xgbe_phy_i2c_read(pdata, XGBE_SFP_DIAG_INFO_ADDRESS,
+ &eeprom_addr, sizeof(eeprom_addr),
+ eeprom_data + XGBE_SFP_EEPROM_BASE_LEN,
+ XGBE_SFP_EEPROM_DIAG_LEN);
+ if (ret) {
+ netdev_err(pdata->netdev,
+ "I2C error reading SFP DIAGS\n");
+ ret = -EIO;
+ goto put_mux;
+ }
+ }
+
+ for (i = 0, j = eeprom->offset; i < eeprom->len; i++, j++) {
+ if ((j >= XGBE_SFP_EEPROM_BASE_LEN) &&
+ !XGBE_SFP_DIAGS_SUPPORTED(sfp_eeprom))
+ break;
+
+ data[i] = eeprom_data[j];
+ rem--;
+ }
+
+put_mux:
+ xgbe_phy_sfp_put_mux(pdata);
+
+put_own:
+ xgbe_phy_put_comm_ownership(pdata);
+
+done:
+ eeprom->len -= rem;
+
+ return ret;
+}
+
+static int xgbe_phy_module_info(struct xgbe_prv_data *pdata,
+ struct ethtool_modinfo *modinfo)
+{
+ struct xgbe_phy_data *phy_data = pdata->phy_data;
+
+ if (phy_data->port_mode != XGBE_PORT_MODE_SFP)
+ return -ENXIO;
+
+ if (!netif_running(pdata->netdev))
+ return -EIO;
+
+ if (phy_data->sfp_mod_absent)
+ return -EIO;
+
+ if (XGBE_SFP_DIAGS_SUPPORTED(&phy_data->sfp_eeprom)) {
+ modinfo->type = ETH_MODULE_SFF_8472;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+ } else {
+ modinfo->type = ETH_MODULE_SFF_8079;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+ }
+
+ return 0;
+}
+
static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
{
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
@@ -1611,6 +1767,10 @@ static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
XGBE_CLR_ADV(dlks, 1000baseKX_Full);
XGBE_CLR_ADV(dlks, 10000baseKR_Full);
+ /* Advertise FEC support is present */
+ if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
+ XGBE_SET_ADV(dlks, 10000baseR_FEC);
+
switch (phy_data->port_mode) {
case XGBE_PORT_MODE_BACKPLANE:
XGBE_SET_ADV(dlks, 10000baseKR_Full);
@@ -2421,22 +2581,21 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
static void xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
- unsigned int reg;
-
- reg = XP_IOREAD(pdata, XP_PROP_3);
phy_data->sfp_gpio_address = XGBE_GPIO_ADDRESS_PCA9555 +
- XP_GET_BITS(reg, XP_PROP_3, GPIO_ADDR);
+ XP_GET_BITS(pdata->pp3, XP_PROP_3,
+ GPIO_ADDR);
- phy_data->sfp_gpio_mask = XP_GET_BITS(reg, XP_PROP_3, GPIO_MASK);
+ phy_data->sfp_gpio_mask = XP_GET_BITS(pdata->pp3, XP_PROP_3,
+ GPIO_MASK);
- phy_data->sfp_gpio_rx_los = XP_GET_BITS(reg, XP_PROP_3,
+ phy_data->sfp_gpio_rx_los = XP_GET_BITS(pdata->pp3, XP_PROP_3,
GPIO_RX_LOS);
- phy_data->sfp_gpio_tx_fault = XP_GET_BITS(reg, XP_PROP_3,
+ phy_data->sfp_gpio_tx_fault = XP_GET_BITS(pdata->pp3, XP_PROP_3,
GPIO_TX_FAULT);
- phy_data->sfp_gpio_mod_absent = XP_GET_BITS(reg, XP_PROP_3,
+ phy_data->sfp_gpio_mod_absent = XP_GET_BITS(pdata->pp3, XP_PROP_3,
GPIO_MOD_ABS);
- phy_data->sfp_gpio_rate_select = XP_GET_BITS(reg, XP_PROP_3,
+ phy_data->sfp_gpio_rate_select = XP_GET_BITS(pdata->pp3, XP_PROP_3,
GPIO_RATE_SELECT);
if (netif_msg_probe(pdata)) {
@@ -2458,18 +2617,17 @@ static void xgbe_phy_sfp_gpio_setup(struct xgbe_prv_data *pdata)
static void xgbe_phy_sfp_comm_setup(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
- unsigned int reg, mux_addr_hi, mux_addr_lo;
+ unsigned int mux_addr_hi, mux_addr_lo;
- reg = XP_IOREAD(pdata, XP_PROP_4);
-
- mux_addr_hi = XP_GET_BITS(reg, XP_PROP_4, MUX_ADDR_HI);
- mux_addr_lo = XP_GET_BITS(reg, XP_PROP_4, MUX_ADDR_LO);
+ mux_addr_hi = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_HI);
+ mux_addr_lo = XP_GET_BITS(pdata->pp4, XP_PROP_4, MUX_ADDR_LO);
if (mux_addr_lo == XGBE_SFP_DIRECT)
return;
phy_data->sfp_comm = XGBE_SFP_COMM_PCA9545;
phy_data->sfp_mux_address = (mux_addr_hi << 2) + mux_addr_lo;
- phy_data->sfp_mux_channel = XP_GET_BITS(reg, XP_PROP_4, MUX_CHAN);
+ phy_data->sfp_mux_channel = XP_GET_BITS(pdata->pp4, XP_PROP_4,
+ MUX_CHAN);
if (netif_msg_probe(pdata)) {
dev_dbg(pdata->dev, "SFP: mux_address=%#x\n",
@@ -2592,13 +2750,11 @@ static bool xgbe_phy_redrv_error(struct xgbe_phy_data *phy_data)
static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
- unsigned int reg;
if (phy_data->conn_type != XGBE_CONN_TYPE_MDIO)
return 0;
- reg = XP_IOREAD(pdata, XP_PROP_3);
- phy_data->mdio_reset = XP_GET_BITS(reg, XP_PROP_3, MDIO_RESET);
+ phy_data->mdio_reset = XP_GET_BITS(pdata->pp3, XP_PROP_3, MDIO_RESET);
switch (phy_data->mdio_reset) {
case XGBE_MDIO_RESET_NONE:
case XGBE_MDIO_RESET_I2C_GPIO:
@@ -2612,12 +2768,12 @@ static int xgbe_phy_mdio_reset_setup(struct xgbe_prv_data *pdata)
if (phy_data->mdio_reset == XGBE_MDIO_RESET_I2C_GPIO) {
phy_data->mdio_reset_addr = XGBE_GPIO_ADDRESS_PCA9555 +
- XP_GET_BITS(reg, XP_PROP_3,
+ XP_GET_BITS(pdata->pp3, XP_PROP_3,
MDIO_RESET_I2C_ADDR);
- phy_data->mdio_reset_gpio = XP_GET_BITS(reg, XP_PROP_3,
+ phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3,
MDIO_RESET_I2C_GPIO);
} else if (phy_data->mdio_reset == XGBE_MDIO_RESET_INT_GPIO) {
- phy_data->mdio_reset_gpio = XP_GET_BITS(reg, XP_PROP_3,
+ phy_data->mdio_reset_gpio = XP_GET_BITS(pdata->pp3, XP_PROP_3,
MDIO_RESET_INT_GPIO);
}
@@ -2707,12 +2863,9 @@ static bool xgbe_phy_conn_type_mismatch(struct xgbe_prv_data *pdata)
static bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata)
{
- unsigned int reg;
-
- reg = XP_IOREAD(pdata, XP_PROP_0);
- if (!XP_GET_BITS(reg, XP_PROP_0, PORT_SPEEDS))
+ if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS))
return false;
- if (!XP_GET_BITS(reg, XP_PROP_0, CONN_TYPE))
+ if (!XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE))
return false;
return true;
@@ -2921,7 +3074,6 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data;
struct mii_bus *mii;
- unsigned int reg;
int ret;
/* Check if enabled */
@@ -2940,12 +3092,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
return -ENOMEM;
pdata->phy_data = phy_data;
- reg = XP_IOREAD(pdata, XP_PROP_0);
- phy_data->port_mode = XP_GET_BITS(reg, XP_PROP_0, PORT_MODE);
- phy_data->port_id = XP_GET_BITS(reg, XP_PROP_0, PORT_ID);
- phy_data->port_speeds = XP_GET_BITS(reg, XP_PROP_0, PORT_SPEEDS);
- phy_data->conn_type = XP_GET_BITS(reg, XP_PROP_0, CONN_TYPE);
- phy_data->mdio_addr = XP_GET_BITS(reg, XP_PROP_0, MDIO_ADDR);
+ phy_data->port_mode = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_MODE);
+ phy_data->port_id = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_ID);
+ phy_data->port_speeds = XP_GET_BITS(pdata->pp0, XP_PROP_0, PORT_SPEEDS);
+ phy_data->conn_type = XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE);
+ phy_data->mdio_addr = XP_GET_BITS(pdata->pp0, XP_PROP_0, MDIO_ADDR);
if (netif_msg_probe(pdata)) {
dev_dbg(pdata->dev, "port mode=%u\n", phy_data->port_mode);
dev_dbg(pdata->dev, "port id=%u\n", phy_data->port_id);
@@ -2954,12 +3105,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
dev_dbg(pdata->dev, "mdio addr=%u\n", phy_data->mdio_addr);
}
- reg = XP_IOREAD(pdata, XP_PROP_4);
- phy_data->redrv = XP_GET_BITS(reg, XP_PROP_4, REDRV_PRESENT);
- phy_data->redrv_if = XP_GET_BITS(reg, XP_PROP_4, REDRV_IF);
- phy_data->redrv_addr = XP_GET_BITS(reg, XP_PROP_4, REDRV_ADDR);
- phy_data->redrv_lane = XP_GET_BITS(reg, XP_PROP_4, REDRV_LANE);
- phy_data->redrv_model = XP_GET_BITS(reg, XP_PROP_4, REDRV_MODEL);
+ phy_data->redrv = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_PRESENT);
+ phy_data->redrv_if = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_IF);
+ phy_data->redrv_addr = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_ADDR);
+ phy_data->redrv_lane = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_LANE);
+ phy_data->redrv_model = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_MODEL);
if (phy_data->redrv && netif_msg_probe(pdata)) {
dev_dbg(pdata->dev, "redrv present\n");
dev_dbg(pdata->dev, "redrv i/f=%u\n", phy_data->redrv_if);
@@ -3231,4 +3381,7 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if)
phy_impl->kr_training_pre = xgbe_phy_kr_training_pre;
phy_impl->kr_training_post = xgbe_phy_kr_training_post;
+
+ phy_impl->module_info = xgbe_phy_module_info;
+ phy_impl->module_eeprom = xgbe_phy_module_eeprom;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 95d4b56448c68..47bcbcf58048c 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -144,6 +144,11 @@
#define XGBE_TX_DESC_MAX_PROC (XGBE_TX_DESC_CNT >> 1)
#define XGBE_RX_DESC_CNT 512
+#define XGBE_TX_DESC_CNT_MIN 64
+#define XGBE_TX_DESC_CNT_MAX 4096
+#define XGBE_RX_DESC_CNT_MIN 64
+#define XGBE_RX_DESC_CNT_MAX 4096
+
#define XGBE_TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1))
/* Descriptors required for maximum contiguous TSO/GSO packet */
@@ -835,6 +840,7 @@ struct xgbe_hw_if {
* 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 */
@@ -883,6 +889,12 @@ struct xgbe_phy_impl_if {
/* 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,
+ struct ethtool_modinfo *modinfo);
+ int (*module_eeprom)(struct xgbe_prv_data *pdata,
+ struct ethtool_eeprom *eeprom, u8 *data);
};
struct xgbe_phy_if {
@@ -905,6 +917,12 @@ struct xgbe_phy_if {
/* For single interrupt support */
irqreturn_t (*an_isr)(struct xgbe_prv_data *);
+ /* For ethtool PHY support */
+ int (*module_info)(struct xgbe_prv_data *pdata,
+ struct ethtool_modinfo *modinfo);
+ int (*module_eeprom)(struct xgbe_prv_data *pdata,
+ struct ethtool_eeprom *eeprom, u8 *data);
+
/* PHY implementation specific services */
struct xgbe_phy_impl_if phy_impl;
};
@@ -1027,6 +1045,13 @@ struct xgbe_prv_data {
void __iomem *xprop_regs; /* XGBE property registers */
void __iomem *xi2c_regs; /* XGBE I2C CSRs */
+ /* Port property registers */
+ unsigned int pp0;
+ unsigned int pp1;
+ unsigned int pp2;
+ unsigned int pp3;
+ unsigned int pp4;
+
/* Overall device lock */
spinlock_t lock;
@@ -1097,6 +1122,9 @@ struct xgbe_prv_data {
unsigned int rx_ring_count;
unsigned int rx_desc_count;
+ unsigned int new_tx_ring_count;
+ unsigned int new_rx_ring_count;
+
unsigned int tx_max_q_count;
unsigned int rx_max_q_count;
unsigned int tx_q_count;
@@ -1233,6 +1261,7 @@ struct xgbe_prv_data {
enum xgbe_rx kr_state;
enum xgbe_rx kx_state;
struct work_struct an_work;
+ unsigned int an_again;
unsigned int an_supported;
unsigned int parallel_detect;
unsigned int fec_ability;
@@ -1310,6 +1339,8 @@ int xgbe_powerup(struct net_device *, unsigned int);
int xgbe_powerdown(struct net_device *, unsigned int);
void xgbe_init_rx_coalesce(struct xgbe_prv_data *);
void xgbe_init_tx_coalesce(struct xgbe_prv_data *);
+void xgbe_restart_dev(struct xgbe_prv_data *pdata);
+void xgbe_full_restart_dev(struct xgbe_prv_data *pdata);
#ifdef CONFIG_DEBUG_FS
void xgbe_debugfs_init(struct xgbe_prv_data *);