diff options
Diffstat (limited to 'drivers/net/ethernet/amd')
-rw-r--r-- | drivers/net/ethernet/amd/amd8111e.c | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 137 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 217 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-main.c | 20 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 167 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 36 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 349 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe.h | 31 |
8 files changed, 705 insertions, 268 deletions
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index c99e3e845ac0..a90080f12e67 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -1074,16 +1074,12 @@ static int amd8111e_calc_coalesce(struct net_device *dev) amd8111e_set_coalesce(dev,TX_INTR_COAL); coal_conf->tx_coal_type = MEDIUM_COALESCE; } - - } - else if(tx_pkt_size >= 1024){ - if (tx_pkt_size >= 1024){ - if(coal_conf->tx_coal_type != HIGH_COALESCE){ - coal_conf->tx_timeout = 4; - coal_conf->tx_event_count = 8; - amd8111e_set_coalesce(dev,TX_INTR_COAL); - coal_conf->tx_coal_type = HIGH_COALESCE; - } + } else if (tx_pkt_size >= 1024) { + if (coal_conf->tx_coal_type != HIGH_COALESCE) { + coal_conf->tx_timeout = 4; + coal_conf->tx_event_count = 8; + amd8111e_set_coalesce(dev, TX_INTR_COAL); + coal_conf->tx_coal_type = HIGH_COALESCE; } } } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 7c204f05b418..24f1053b8785 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 ff397bb25042..a880f10e3e70 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 441d0973957b..b41f23679a08 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 1b45cd73a258..4b5d625de8f0 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 82d1f416ee2a..7b86240ecd5f 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 aac884314000..3ceb4f95ca7c 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 95d4b56448c6..47bcbcf58048 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 *); |