amd-xgbe: Move the PHY support into amd-xgbe

The AMD XGBE device is intended to work with a specific integrated PHY
and that PHY is not meant to be a standalone PHY for use by other
devices. As such this patch removes the phylib driver and implements
the PHY support in the amd-xgbe driver (the majority of the logic from
the phylib driver is moved into the amd-xgbe driver).

Update the driver version to 1.0.1.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Lendacky, Thomas
2015-05-14 11:44:15 -05:00
committed by David S. Miller
parent 7d9ca345b5
commit 7c12aa0877
14 changed files with 1835 additions and 2281 deletions

View File

@@ -179,10 +179,8 @@ config SUNLANCE
config AMD_XGBE
tristate "AMD 10GbE Ethernet driver"
depends on (OF_NET || ACPI) && HAS_IOMEM && HAS_DMA
depends on ((OF_NET && OF_ADDRESS) || ACPI) && HAS_IOMEM && HAS_DMA
depends on ARM64 || COMPILE_TEST
select PHYLIB
select AMD_XGBE_PHY
select BITREVERSE
select CRC32
select PTP_1588_CLOCK

View File

@@ -857,6 +857,48 @@
*/
#define PCS_MMD_SELECT 0xff
/* SerDes integration register offsets */
#define SIR0_KR_RT_1 0x002c
#define SIR0_STATUS 0x0040
#define SIR1_SPEED 0x0000
/* SerDes integration register entry bit positions and sizes */
#define SIR0_KR_RT_1_RESET_INDEX 11
#define SIR0_KR_RT_1_RESET_WIDTH 1
#define SIR0_STATUS_RX_READY_INDEX 0
#define SIR0_STATUS_RX_READY_WIDTH 1
#define SIR0_STATUS_TX_READY_INDEX 8
#define SIR0_STATUS_TX_READY_WIDTH 1
#define SIR1_SPEED_CDR_RATE_INDEX 12
#define SIR1_SPEED_CDR_RATE_WIDTH 4
#define SIR1_SPEED_DATARATE_INDEX 4
#define SIR1_SPEED_DATARATE_WIDTH 2
#define SIR1_SPEED_PLLSEL_INDEX 3
#define SIR1_SPEED_PLLSEL_WIDTH 1
#define SIR1_SPEED_RATECHANGE_INDEX 6
#define SIR1_SPEED_RATECHANGE_WIDTH 1
#define SIR1_SPEED_TXAMP_INDEX 8
#define SIR1_SPEED_TXAMP_WIDTH 4
#define SIR1_SPEED_WORDMODE_INDEX 0
#define SIR1_SPEED_WORDMODE_WIDTH 3
/* SerDes RxTx register offsets */
#define RXTX_REG6 0x0018
#define RXTX_REG20 0x0050
#define RXTX_REG22 0x0058
#define RXTX_REG114 0x01c8
#define RXTX_REG129 0x0204
/* SerDes RxTx register entry bit positions and sizes */
#define RXTX_REG6_RESETB_RXD_INDEX 8
#define RXTX_REG6_RESETB_RXD_WIDTH 1
#define RXTX_REG20_BLWC_ENA_INDEX 2
#define RXTX_REG20_BLWC_ENA_WIDTH 1
#define RXTX_REG114_PQ_REG_INDEX 9
#define RXTX_REG114_PQ_REG_WIDTH 7
#define RXTX_REG129_RXDFE_CONFIG_INDEX 14
#define RXTX_REG129_RXDFE_CONFIG_WIDTH 2
/* Descriptor/Packet entry bit positions and sizes */
#define RX_PACKET_ERRORS_CRC_INDEX 2
#define RX_PACKET_ERRORS_CRC_WIDTH 1
@@ -973,10 +1015,47 @@
#define TX_NORMAL_DESC2_VLAN_INSERT 0x2
/* MDIO undefined or vendor specific registers */
#ifndef MDIO_PMA_10GBR_PMD_CTRL
#define MDIO_PMA_10GBR_PMD_CTRL 0x0096
#endif
#ifndef MDIO_PMA_10GBR_FECCTRL
#define MDIO_PMA_10GBR_FECCTRL 0x00ab
#endif
#ifndef MDIO_AN_XNP
#define MDIO_AN_XNP 0x0016
#endif
#ifndef MDIO_AN_LPX
#define MDIO_AN_LPX 0x0019
#endif
#ifndef MDIO_AN_COMP_STAT
#define MDIO_AN_COMP_STAT 0x0030
#endif
#ifndef MDIO_AN_INTMASK
#define MDIO_AN_INTMASK 0x8001
#endif
#ifndef MDIO_AN_INT
#define MDIO_AN_INT 0x8002
#endif
#ifndef MDIO_CTRL1_SPEED1G
#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
#endif
/* MDIO mask values */
#define XGBE_XNP_MCF_NULL_MESSAGE 0x001
#define XGBE_XNP_ACK_PROCESSED BIT(12)
#define XGBE_XNP_MP_FORMATTED BIT(13)
#define XGBE_XNP_NP_EXCHANGE BIT(15)
#define XGBE_KR_TRAINING_START BIT(0)
#define XGBE_KR_TRAINING_ENABLE BIT(1)
/* Bit setting and getting macros
* The get macro will extract the current bit field value from within
* the variable
@@ -1118,6 +1197,82 @@ do { \
#define XPCS_IOREAD(_pdata, _off) \
ioread32((_pdata)->xpcs_regs + (_off))
/* Macros for building, reading or writing register values or bits
* within the register values of SerDes integration registers.
*/
#define XSIR_GET_BITS(_var, _prefix, _field) \
GET_BITS((_var), \
_prefix##_##_field##_INDEX, \
_prefix##_##_field##_WIDTH)
#define XSIR_SET_BITS(_var, _prefix, _field, _val) \
SET_BITS((_var), \
_prefix##_##_field##_INDEX, \
_prefix##_##_field##_WIDTH, (_val))
#define XSIR0_IOREAD(_pdata, _reg) \
ioread16((_pdata)->sir0_regs + _reg)
#define XSIR0_IOREAD_BITS(_pdata, _reg, _field) \
GET_BITS(XSIR0_IOREAD((_pdata), _reg), \
_reg##_##_field##_INDEX, \
_reg##_##_field##_WIDTH)
#define XSIR0_IOWRITE(_pdata, _reg, _val) \
iowrite16((_val), (_pdata)->sir0_regs + _reg)
#define XSIR0_IOWRITE_BITS(_pdata, _reg, _field, _val) \
do { \
u16 reg_val = XSIR0_IOREAD((_pdata), _reg); \
SET_BITS(reg_val, \
_reg##_##_field##_INDEX, \
_reg##_##_field##_WIDTH, (_val)); \
XSIR0_IOWRITE((_pdata), _reg, reg_val); \
} while (0)
#define XSIR1_IOREAD(_pdata, _reg) \
ioread16((_pdata)->sir1_regs + _reg)
#define XSIR1_IOREAD_BITS(_pdata, _reg, _field) \
GET_BITS(XSIR1_IOREAD((_pdata), _reg), \
_reg##_##_field##_INDEX, \
_reg##_##_field##_WIDTH)
#define XSIR1_IOWRITE(_pdata, _reg, _val) \
iowrite16((_val), (_pdata)->sir1_regs + _reg)
#define XSIR1_IOWRITE_BITS(_pdata, _reg, _field, _val) \
do { \
u16 reg_val = XSIR1_IOREAD((_pdata), _reg); \
SET_BITS(reg_val, \
_reg##_##_field##_INDEX, \
_reg##_##_field##_WIDTH, (_val)); \
XSIR1_IOWRITE((_pdata), _reg, reg_val); \
} while (0)
/* Macros for building, reading or writing register values or bits
* within the register values of SerDes RxTx registers.
*/
#define XRXTX_IOREAD(_pdata, _reg) \
ioread16((_pdata)->rxtx_regs + _reg)
#define XRXTX_IOREAD_BITS(_pdata, _reg, _field) \
GET_BITS(XRXTX_IOREAD((_pdata), _reg), \
_reg##_##_field##_INDEX, \
_reg##_##_field##_WIDTH)
#define XRXTX_IOWRITE(_pdata, _reg, _val) \
iowrite16((_val), (_pdata)->rxtx_regs + _reg)
#define XRXTX_IOWRITE_BITS(_pdata, _reg, _field, _val) \
do { \
u16 reg_val = XRXTX_IOREAD((_pdata), _reg); \
SET_BITS(reg_val, \
_reg##_##_field##_INDEX, \
_reg##_##_field##_WIDTH, (_val)); \
XRXTX_IOWRITE((_pdata), _reg, reg_val); \
} while (0)
/* Macros for building, reading or writing register values or bits
* using MDIO. Different from above because of the use of standardized
* Linux include values. No shifting is performed with the bit

View File

@@ -910,23 +910,6 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
else
mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
/* If the PCS is changing modes, match the MAC speed to it */
if (((mmd_address >> 16) == MDIO_MMD_PCS) &&
((mmd_address & 0xffff) == MDIO_CTRL2)) {
struct phy_device *phydev = pdata->phydev;
if (mmd_data & MDIO_PCS_CTRL2_TYPE) {
/* KX mode */
if (phydev->supported & SUPPORTED_1000baseKX_Full)
xgbe_set_gmii_speed(pdata);
else
xgbe_set_gmii_2500_speed(pdata);
} else {
/* KR mode */
xgbe_set_xgmii_speed(pdata);
}
}
/* The PCS registers are accessed using mmio. The underlying APB3
* management interface uses indirect addressing to access the MMD
* register sets. This requires accessing of the PCS register in two

View File

@@ -437,12 +437,31 @@ static void xgbe_tx_timer(unsigned long data)
DBGPR("<--xgbe_tx_timer\n");
}
static void xgbe_init_tx_timers(struct xgbe_prv_data *pdata)
static void xgbe_service(struct work_struct *work)
{
struct xgbe_prv_data *pdata = container_of(work,
struct xgbe_prv_data,
service_work);
pdata->phy_if.phy_status(pdata);
}
static void xgbe_service_timer(unsigned long data)
{
struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
schedule_work(&pdata->service_work);
mod_timer(&pdata->service_timer, jiffies + HZ);
}
static void xgbe_init_timers(struct xgbe_prv_data *pdata)
{
struct xgbe_channel *channel;
unsigned int i;
DBGPR("-->xgbe_init_tx_timers\n");
setup_timer(&pdata->service_timer, xgbe_service_timer,
(unsigned long)pdata);
channel = pdata->channel;
for (i = 0; i < pdata->channel_count; i++, channel++) {
@@ -452,16 +471,19 @@ static void xgbe_init_tx_timers(struct xgbe_prv_data *pdata)
setup_timer(&channel->tx_timer, xgbe_tx_timer,
(unsigned long)channel);
}
DBGPR("<--xgbe_init_tx_timers\n");
}
static void xgbe_stop_tx_timers(struct xgbe_prv_data *pdata)
static void xgbe_start_timers(struct xgbe_prv_data *pdata)
{
mod_timer(&pdata->service_timer, jiffies + HZ);
}
static void xgbe_stop_timers(struct xgbe_prv_data *pdata)
{
struct xgbe_channel *channel;
unsigned int i;
DBGPR("-->xgbe_stop_tx_timers\n");
del_timer_sync(&pdata->service_timer);
channel = pdata->channel;
for (i = 0; i < pdata->channel_count; i++, channel++) {
@@ -470,8 +492,6 @@ static void xgbe_stop_tx_timers(struct xgbe_prv_data *pdata)
del_timer_sync(&channel->tx_timer);
}
DBGPR("<--xgbe_stop_tx_timers\n");
}
void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
@@ -758,113 +778,14 @@ static void xgbe_free_rx_data(struct xgbe_prv_data *pdata)
DBGPR("<--xgbe_free_rx_data\n");
}
static void xgbe_adjust_link(struct net_device *netdev)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct phy_device *phydev = pdata->phydev;
int new_state = 0;
if (!phydev)
return;
if (phydev->link) {
/* Flow control support */
if (pdata->pause_autoneg) {
if (phydev->pause || phydev->asym_pause) {
pdata->tx_pause = 1;
pdata->rx_pause = 1;
} else {
pdata->tx_pause = 0;
pdata->rx_pause = 0;
}
}
if (pdata->tx_pause != pdata->phy_tx_pause) {
hw_if->config_tx_flow_control(pdata);
pdata->phy_tx_pause = pdata->tx_pause;
}
if (pdata->rx_pause != pdata->phy_rx_pause) {
hw_if->config_rx_flow_control(pdata);
pdata->phy_rx_pause = pdata->rx_pause;
}
/* Speed support */
if (phydev->speed != pdata->phy_speed) {
new_state = 1;
switch (phydev->speed) {
case SPEED_10000:
hw_if->set_xgmii_speed(pdata);
break;
case SPEED_2500:
hw_if->set_gmii_2500_speed(pdata);
break;
case SPEED_1000:
hw_if->set_gmii_speed(pdata);
break;
}
pdata->phy_speed = phydev->speed;
}
if (phydev->link != pdata->phy_link) {
new_state = 1;
pdata->phy_link = 1;
}
} else if (pdata->phy_link) {
new_state = 1;
pdata->phy_link = 0;
pdata->phy_speed = SPEED_UNKNOWN;
}
if (new_state)
phy_print_status(phydev);
}
static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{
struct net_device *netdev = pdata->netdev;
struct phy_device *phydev = pdata->phydev;
int ret;
pdata->phy_link = -1;
pdata->phy_speed = SPEED_UNKNOWN;
pdata->phy_tx_pause = pdata->tx_pause;
pdata->phy_rx_pause = pdata->rx_pause;
ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link,
pdata->phy_mode);
if (ret) {
netdev_err(netdev, "phy_connect_direct failed\n");
return ret;
}
if (!phydev->drv || (phydev->drv->phy_id == 0)) {
netdev_err(netdev, "phy_id not valid\n");
ret = -ENODEV;
goto err_phy_connect;
}
netif_dbg(pdata, ifup, pdata->netdev,
"phy_connect_direct succeeded for PHY %s\n",
dev_name(&phydev->dev));
return 0;
err_phy_connect:
phy_disconnect(phydev);
return ret;
}
static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
{
if (!pdata->phydev)
return;
phy_disconnect(pdata->phydev);
return pdata->phy_if.phy_reset(pdata);
}
int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
@@ -889,13 +810,14 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
netif_tx_stop_all_queues(netdev);
xgbe_stop_timers(pdata);
flush_workqueue(pdata->dev_workqueue);
hw_if->powerdown_tx(pdata);
hw_if->powerdown_rx(pdata);
xgbe_napi_disable(pdata, 0);
phy_stop(pdata->phydev);
pdata->power_down = 1;
spin_unlock_irqrestore(&pdata->lock, flags);
@@ -924,8 +846,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
pdata->power_down = 0;
phy_start(pdata->phydev);
xgbe_napi_enable(pdata, 0);
hw_if->powerup_tx(pdata);
@@ -936,6 +856,8 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
netif_tx_start_all_queues(netdev);
xgbe_start_timers(pdata);
spin_unlock_irqrestore(&pdata->lock, flags);
DBGPR("<--xgbe_powerup\n");
@@ -946,6 +868,7 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
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;
int ret;
@@ -953,7 +876,9 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
hw_if->init(pdata);
phy_start(pdata->phydev);
ret = phy_if->phy_start(pdata);
if (ret)
goto err_phy;
xgbe_napi_enable(pdata, 1);
@@ -964,10 +889,11 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
hw_if->enable_tx(pdata);
hw_if->enable_rx(pdata);
xgbe_init_tx_timers(pdata);
netif_tx_start_all_queues(netdev);
xgbe_start_timers(pdata);
schedule_work(&pdata->service_work);
DBGPR("<--xgbe_start\n");
return 0;
@@ -975,8 +901,9 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
err_napi:
xgbe_napi_disable(pdata, 1);
phy_stop(pdata->phydev);
phy_if->phy_stop(pdata);
err_phy:
hw_if->exit(pdata);
return ret;
@@ -985,6 +912,7 @@ err_napi:
static void xgbe_stop(struct xgbe_prv_data *pdata)
{
struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_phy_if *phy_if = &pdata->phy_if;
struct xgbe_channel *channel;
struct net_device *netdev = pdata->netdev;
struct netdev_queue *txq;
@@ -994,7 +922,8 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
netif_tx_stop_all_queues(netdev);
xgbe_stop_tx_timers(pdata);
xgbe_stop_timers(pdata);
flush_workqueue(pdata->dev_workqueue);
hw_if->disable_tx(pdata);
hw_if->disable_rx(pdata);
@@ -1003,7 +932,7 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
xgbe_napi_disable(pdata, 1);
phy_stop(pdata->phydev);
phy_if->phy_stop(pdata);
hw_if->exit(pdata);
@@ -1374,7 +1303,7 @@ static int xgbe_open(struct net_device *netdev)
ret = clk_prepare_enable(pdata->sysclk);
if (ret) {
netdev_alert(netdev, "dma clk_prepare_enable failed\n");
goto err_phy_init;
return ret;
}
ret = clk_prepare_enable(pdata->ptpclk);
@@ -1399,14 +1328,17 @@ static int xgbe_open(struct net_device *netdev)
if (ret)
goto err_channels;
/* Initialize the device restart and Tx timestamp work struct */
INIT_WORK(&pdata->service_work, xgbe_service);
INIT_WORK(&pdata->restart_work, xgbe_restart);
INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp);
xgbe_init_timers(pdata);
ret = xgbe_start(pdata);
if (ret)
goto err_rings;
clear_bit(XGBE_DOWN, &pdata->dev_state);
DBGPR("<--xgbe_open\n");
return 0;
@@ -1423,9 +1355,6 @@ err_ptpclk:
err_sysclk:
clk_disable_unprepare(pdata->sysclk);
err_phy_init:
xgbe_phy_exit(pdata);
return ret;
}
@@ -1449,8 +1378,7 @@ static int xgbe_close(struct net_device *netdev)
clk_disable_unprepare(pdata->ptpclk);
clk_disable_unprepare(pdata->sysclk);
/* Release the phy */
xgbe_phy_exit(pdata);
set_bit(XGBE_DOWN, &pdata->dev_state);
DBGPR("<--xgbe_close\n");

View File

@@ -258,7 +258,6 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct phy_device *phydev = pdata->phydev;
int ret = 0;
DBGPR("-->xgbe_set_pauseparam\n");
@@ -268,19 +267,19 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
pdata->pause_autoneg = pause->autoneg;
if (pause->autoneg) {
phydev->advertising |= ADVERTISED_Pause;
phydev->advertising |= ADVERTISED_Asym_Pause;
pdata->phy.advertising |= ADVERTISED_Pause;
pdata->phy.advertising |= ADVERTISED_Asym_Pause;
} else {
phydev->advertising &= ~ADVERTISED_Pause;
phydev->advertising &= ~ADVERTISED_Asym_Pause;
pdata->phy.advertising &= ~ADVERTISED_Pause;
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
pdata->tx_pause = pause->tx_pause;
pdata->rx_pause = pause->rx_pause;
}
if (netif_running(netdev))
ret = phy_start_aneg(phydev);
ret = pdata->phy_if.phy_config_aneg(pdata);
DBGPR("<--xgbe_set_pauseparam\n");
@@ -291,36 +290,39 @@ static int xgbe_get_settings(struct net_device *netdev,
struct ethtool_cmd *cmd)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
int ret;
DBGPR("-->xgbe_get_settings\n");
if (!pdata->phydev)
return -ENODEV;
cmd->phy_address = pdata->phy.address;
ret = phy_ethtool_gset(pdata->phydev, cmd);
cmd->supported = pdata->phy.supported;
cmd->advertising = pdata->phy.advertising;
cmd->lp_advertising = pdata->phy.lp_advertising;
cmd->autoneg = pdata->phy.autoneg;
ethtool_cmd_speed_set(cmd, pdata->phy.speed);
cmd->duplex = pdata->phy.duplex;
cmd->port = PORT_NONE;
cmd->transceiver = XCVR_INTERNAL;
DBGPR("<--xgbe_get_settings\n");
return ret;
return 0;
}
static int xgbe_set_settings(struct net_device *netdev,
struct ethtool_cmd *cmd)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct phy_device *phydev = pdata->phydev;
u32 speed;
int ret;
DBGPR("-->xgbe_set_settings\n");
if (!pdata->phydev)
return -ENODEV;
speed = ethtool_cmd_speed(cmd);
if (cmd->phy_address != phydev->addr)
if (cmd->phy_address != pdata->phy.address)
return -EINVAL;
if ((cmd->autoneg != AUTONEG_ENABLE) &&
@@ -341,23 +343,23 @@ static int xgbe_set_settings(struct net_device *netdev,
return -EINVAL;
}
cmd->advertising &= phydev->supported;
cmd->advertising &= pdata->phy.supported;
if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising)
return -EINVAL;
ret = 0;
phydev->autoneg = cmd->autoneg;
phydev->speed = speed;
phydev->duplex = cmd->duplex;
phydev->advertising = cmd->advertising;
pdata->phy.autoneg = cmd->autoneg;
pdata->phy.speed = speed;
pdata->phy.duplex = cmd->duplex;
pdata->phy.advertising = cmd->advertising;
if (cmd->autoneg == AUTONEG_ENABLE)
phydev->advertising |= ADVERTISED_Autoneg;
pdata->phy.advertising |= ADVERTISED_Autoneg;
else
phydev->advertising &= ~ADVERTISED_Autoneg;
pdata->phy.advertising &= ~ADVERTISED_Autoneg;
if (netif_running(netdev))
ret = phy_start_aneg(phydev);
ret = pdata->phy_if.phy_config_aneg(pdata);
DBGPR("<--xgbe_set_settings\n");

View File

@@ -124,9 +124,11 @@
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/property.h>
#include <linux/acpi.h>
#include <linux/mdio.h>
#include "xgbe.h"
#include "xgbe-common.h"
@@ -143,6 +145,42 @@ MODULE_PARM_DESC(debug, " Network interface message level setting");
static const u32 default_msg_level = (NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
NETIF_MSG_IFUP);
static const u32 xgbe_serdes_blwc[] = {
XGBE_SPEED_1000_BLWC,
XGBE_SPEED_2500_BLWC,
XGBE_SPEED_10000_BLWC,
};
static const u32 xgbe_serdes_cdr_rate[] = {
XGBE_SPEED_1000_CDR,
XGBE_SPEED_2500_CDR,
XGBE_SPEED_10000_CDR,
};
static const u32 xgbe_serdes_pq_skew[] = {
XGBE_SPEED_1000_PQ,
XGBE_SPEED_2500_PQ,
XGBE_SPEED_10000_PQ,
};
static const u32 xgbe_serdes_tx_amp[] = {
XGBE_SPEED_1000_TXAMP,
XGBE_SPEED_2500_TXAMP,
XGBE_SPEED_10000_TXAMP,
};
static const u32 xgbe_serdes_dfe_tap_cfg[] = {
XGBE_SPEED_1000_DFE_TAP_CONFIG,
XGBE_SPEED_2500_DFE_TAP_CONFIG,
XGBE_SPEED_10000_DFE_TAP_CONFIG,
};
static const u32 xgbe_serdes_dfe_tap_ena[] = {
XGBE_SPEED_1000_DFE_TAP_ENABLE,
XGBE_SPEED_2500_DFE_TAP_ENABLE,
XGBE_SPEED_10000_DFE_TAP_ENABLE,
};
static void xgbe_default_config(struct xgbe_prv_data *pdata)
{
DBGPR("-->xgbe_default_config\n");
@@ -160,8 +198,6 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata)
pdata->rx_pause = 1;
pdata->phy_speed = SPEED_UNKNOWN;
pdata->power_down = 0;
pdata->default_autoneg = AUTONEG_ENABLE;
pdata->default_speed = SPEED_10000;
DBGPR("<--xgbe_default_config\n");
}
@@ -169,6 +205,7 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata)
static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
{
xgbe_init_function_ptrs_dev(&pdata->hw_if);
xgbe_init_function_ptrs_phy(&pdata->phy_if);
xgbe_init_function_ptrs_desc(&pdata->desc_if);
}
@@ -255,23 +292,75 @@ static int xgbe_of_support(struct xgbe_prv_data *pdata)
return 0;
}
static struct platform_device *xgbe_of_get_phy_pdev(struct xgbe_prv_data *pdata)
{
struct device *dev = pdata->dev;
struct device_node *phy_node;
struct platform_device *phy_pdev;
phy_node = of_parse_phandle(dev->of_node, "phy-handle", 0);
if (!phy_node) {
dev_err(dev, "unable to locate phy device\n");
return NULL;
}
phy_pdev = of_find_device_by_node(phy_node);
of_node_put(phy_node);
return phy_pdev;
}
#else /* CONFIG_OF */
static int xgbe_of_support(struct xgbe_prv_data *pdata)
{
return -EINVAL;
}
#endif /*CONFIG_OF */
static struct platform_device *xgbe_of_get_phy_pdev(struct xgbe_prv_data *pdata)
{
return NULL;
}
#endif /* CONFIG_OF */
static unsigned int xgbe_resource_count(struct platform_device *pdev,
unsigned int type)
{
unsigned int count;
int i;
for (i = 0, count = 0; i < pdev->num_resources; i++) {
struct resource *res = &pdev->resource[i];
if (type == resource_type(res))
count++;
}
return count;
}
static struct platform_device *xgbe_get_phy_pdev(struct xgbe_prv_data *pdata)
{
struct platform_device *phy_pdev;
if (pdata->use_acpi) {
get_device(pdata->dev);
phy_pdev = pdata->pdev;
} else {
phy_pdev = xgbe_of_get_phy_pdev(pdata);
}
return phy_pdev;
}
static int xgbe_probe(struct platform_device *pdev)
{
struct xgbe_prv_data *pdata;
struct xgbe_hw_if *hw_if;
struct xgbe_desc_if *desc_if;
struct net_device *netdev;
struct device *dev = &pdev->dev;
struct device *dev = &pdev->dev, *phy_dev;
struct platform_device *phy_pdev;
struct resource *res;
const char *phy_mode;
unsigned int i;
unsigned int i, phy_memnum, phy_irqnum;
int ret;
DBGPR("--> xgbe_probe\n");
@@ -298,9 +387,34 @@ static int xgbe_probe(struct platform_device *pdev)
pdata->msg_enable = netif_msg_init(debug, default_msg_level);
set_bit(XGBE_DOWN, &pdata->dev_state);
/* Check if we should use ACPI or DT */
pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1;
phy_pdev = xgbe_get_phy_pdev(pdata);
if (!phy_pdev) {
dev_err(dev, "unable to obtain phy device\n");
ret = -EINVAL;
goto err_phydev;
}
phy_dev = &phy_pdev->dev;
if (pdev == phy_pdev) {
/* ACPI:
* The XGBE and PHY resources are grouped together with
* the PHY resources listed last
*/
phy_memnum = xgbe_resource_count(pdev, IORESOURCE_MEM) - 3;
phy_irqnum = xgbe_resource_count(pdev, IORESOURCE_IRQ) - 1;
} else {
/* Device tree:
* The XGBE and PHY resources are separate
*/
phy_memnum = 0;
phy_irqnum = 0;
}
/* Set and validate the number of descriptors for a ring */
BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
pdata->tx_desc_count = XGBE_TX_DESC_CNT;
@@ -340,6 +454,36 @@ static int xgbe_probe(struct platform_device *pdev)
if (netif_msg_probe(pdata))
dev_dbg(dev, "xpcs_regs = %p\n", pdata->xpcs_regs);
res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
pdata->rxtx_regs = devm_ioremap_resource(dev, res);
if (IS_ERR(pdata->rxtx_regs)) {
dev_err(dev, "rxtx ioremap failed\n");
ret = PTR_ERR(pdata->rxtx_regs);
goto err_io;
}
if (netif_msg_probe(pdata))
dev_dbg(dev, "rxtx_regs = %p\n", pdata->rxtx_regs);
res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
pdata->sir0_regs = devm_ioremap_resource(dev, res);
if (IS_ERR(pdata->sir0_regs)) {
dev_err(dev, "sir0 ioremap failed\n");
ret = PTR_ERR(pdata->sir0_regs);
goto err_io;
}
if (netif_msg_probe(pdata))
dev_dbg(dev, "sir0_regs = %p\n", pdata->sir0_regs);
res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
pdata->sir1_regs = devm_ioremap_resource(dev, res);
if (IS_ERR(pdata->sir1_regs)) {
dev_err(dev, "sir1 ioremap failed\n");
ret = PTR_ERR(pdata->sir1_regs);
goto err_io;
}
if (netif_msg_probe(pdata))
dev_dbg(dev, "sir1_regs = %p\n", pdata->sir1_regs);
/* Retrieve the MAC address */
ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY,
pdata->mac_addr,
@@ -366,6 +510,115 @@ static int xgbe_probe(struct platform_device *pdev)
if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY))
pdata->per_channel_irq = 1;
/* Retrieve the PHY speedset */
ret = device_property_read_u32(phy_dev, XGBE_SPEEDSET_PROPERTY,
&pdata->speed_set);
if (ret) {
dev_err(dev, "invalid %s property\n", XGBE_SPEEDSET_PROPERTY);
goto err_io;
}
switch (pdata->speed_set) {
case XGBE_SPEEDSET_1000_10000:
case XGBE_SPEEDSET_2500_10000:
break;
default:
dev_err(dev, "invalid %s property\n", XGBE_SPEEDSET_PROPERTY);
ret = -EINVAL;
goto err_io;
}
/* Retrieve the PHY configuration properties */
if (device_property_present(phy_dev, XGBE_BLWC_PROPERTY)) {
ret = device_property_read_u32_array(phy_dev,
XGBE_BLWC_PROPERTY,
pdata->serdes_blwc,
XGBE_SPEEDS);
if (ret) {
dev_err(dev, "invalid %s property\n",
XGBE_BLWC_PROPERTY);
goto err_io;
}
} else {
memcpy(pdata->serdes_blwc, xgbe_serdes_blwc,
sizeof(pdata->serdes_blwc));
}
if (device_property_present(phy_dev, XGBE_CDR_RATE_PROPERTY)) {
ret = device_property_read_u32_array(phy_dev,
XGBE_CDR_RATE_PROPERTY,
pdata->serdes_cdr_rate,
XGBE_SPEEDS);
if (ret) {
dev_err(dev, "invalid %s property\n",
XGBE_CDR_RATE_PROPERTY);
goto err_io;
}
} else {
memcpy(pdata->serdes_cdr_rate, xgbe_serdes_cdr_rate,
sizeof(pdata->serdes_cdr_rate));
}
if (device_property_present(phy_dev, XGBE_PQ_SKEW_PROPERTY)) {
ret = device_property_read_u32_array(phy_dev,
XGBE_PQ_SKEW_PROPERTY,
pdata->serdes_pq_skew,
XGBE_SPEEDS);
if (ret) {
dev_err(dev, "invalid %s property\n",
XGBE_PQ_SKEW_PROPERTY);
goto err_io;
}
} else {
memcpy(pdata->serdes_pq_skew, xgbe_serdes_pq_skew,
sizeof(pdata->serdes_pq_skew));
}
if (device_property_present(phy_dev, XGBE_TX_AMP_PROPERTY)) {
ret = device_property_read_u32_array(phy_dev,
XGBE_TX_AMP_PROPERTY,
pdata->serdes_tx_amp,
XGBE_SPEEDS);
if (ret) {
dev_err(dev, "invalid %s property\n",
XGBE_TX_AMP_PROPERTY);
goto err_io;
}
} else {
memcpy(pdata->serdes_tx_amp, xgbe_serdes_tx_amp,
sizeof(pdata->serdes_tx_amp));
}
if (device_property_present(phy_dev, XGBE_DFE_CFG_PROPERTY)) {
ret = device_property_read_u32_array(phy_dev,
XGBE_DFE_CFG_PROPERTY,
pdata->serdes_dfe_tap_cfg,
XGBE_SPEEDS);
if (ret) {
dev_err(dev, "invalid %s property\n",
XGBE_DFE_CFG_PROPERTY);
goto err_io;
}
} else {
memcpy(pdata->serdes_dfe_tap_cfg, xgbe_serdes_dfe_tap_cfg,
sizeof(pdata->serdes_dfe_tap_cfg));
}
if (device_property_present(phy_dev, XGBE_DFE_ENA_PROPERTY)) {
ret = device_property_read_u32_array(phy_dev,
XGBE_DFE_ENA_PROPERTY,
pdata->serdes_dfe_tap_ena,
XGBE_SPEEDS);
if (ret) {
dev_err(dev, "invalid %s property\n",
XGBE_DFE_ENA_PROPERTY);
goto err_io;
}
} else {
memcpy(pdata->serdes_dfe_tap_ena, xgbe_serdes_dfe_tap_ena,
sizeof(pdata->serdes_dfe_tap_ena));
}
/* Obtain device settings unique to ACPI/OF */
if (pdata->use_acpi)
ret = xgbe_acpi_support(pdata);
@@ -393,17 +646,23 @@ static int xgbe_probe(struct platform_device *pdev)
}
pdata->dev_irq = ret;
/* Get the auto-negotiation interrupt */
ret = platform_get_irq(phy_pdev, phy_irqnum++);
if (ret < 0) {
dev_err(dev, "platform_get_irq phy 0 failed\n");
goto err_io;
}
pdata->an_irq = ret;
netdev->irq = pdata->dev_irq;
netdev->base_addr = (unsigned long)pdata->xgmac_regs;
memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len);
/* Set all the function pointers */
xgbe_init_all_fptrs(pdata);
hw_if = &pdata->hw_if;
desc_if = &pdata->desc_if;
/* Issue software reset to device */
hw_if->exit(pdata);
pdata->hw_if.exit(pdata);
/* Populate the hardware features */
xgbe_get_all_hw_features(pdata);
@@ -458,16 +717,8 @@ static int xgbe_probe(struct platform_device *pdev)
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
/* Prepare to regsiter with MDIO */
pdata->mii_bus_id = kasprintf(GFP_KERNEL, "%s", pdev->name);
if (!pdata->mii_bus_id) {
dev_err(dev, "failed to allocate mii bus id\n");
ret = -ENOMEM;
goto err_io;
}
ret = xgbe_mdio_register(pdata);
if (ret)
goto err_bus_id;
/* Call MDIO/PHY initialization routine */
pdata->phy_if.phy_init(pdata);
/* Set device operations */
netdev->netdev_ops = xgbe_get_netdev_ops();
@@ -512,26 +763,52 @@ static int xgbe_probe(struct platform_device *pdev)
ret = register_netdev(netdev);
if (ret) {
dev_err(dev, "net device registration failed\n");
goto err_reg_netdev;
goto err_io;
}
/* Create the PHY/ANEG name based on netdev name */
snprintf(pdata->an_name, sizeof(pdata->an_name) - 1, "%s-pcs",
netdev_name(netdev));
/* Create workqueues */
pdata->dev_workqueue =
create_singlethread_workqueue(netdev_name(netdev));
if (!pdata->dev_workqueue) {
netdev_err(netdev, "device workqueue creation failed\n");
ret = -ENOMEM;
goto err_netdev;
}
pdata->an_workqueue =
create_singlethread_workqueue(pdata->an_name);
if (!pdata->an_workqueue) {
netdev_err(netdev, "phy workqueue creation failed\n");
ret = -ENOMEM;
goto err_wq;
}
xgbe_ptp_register(pdata);
xgbe_debugfs_init(pdata);
platform_device_put(phy_pdev);
netdev_notice(netdev, "net device enabled\n");
DBGPR("<-- xgbe_probe\n");
return 0;
err_reg_netdev:
xgbe_mdio_unregister(pdata);
err_wq:
destroy_workqueue(pdata->dev_workqueue);
err_bus_id:
kfree(pdata->mii_bus_id);
err_netdev:
unregister_netdev(netdev);
err_io:
platform_device_put(phy_pdev);
err_phydev:
free_netdev(netdev);
err_alloc:
@@ -551,12 +828,14 @@ static int xgbe_remove(struct platform_device *pdev)
xgbe_ptp_unregister(pdata);
flush_workqueue(pdata->an_workqueue);
destroy_workqueue(pdata->an_workqueue);
flush_workqueue(pdata->dev_workqueue);
destroy_workqueue(pdata->dev_workqueue);
unregister_netdev(netdev);
xgbe_mdio_unregister(pdata);
kfree(pdata->mii_bus_id);
free_netdev(netdev);
DBGPR("<--xgbe_remove\n");
@@ -568,16 +847,17 @@ static int xgbe_remove(struct platform_device *pdev)
static int xgbe_suspend(struct device *dev)
{
struct net_device *netdev = dev_get_drvdata(dev);
int ret;
struct xgbe_prv_data *pdata = netdev_priv(netdev);
int ret = 0;
DBGPR("-->xgbe_suspend\n");
if (!netif_running(netdev)) {
DBGPR("<--xgbe_dev_suspend\n");
return -EINVAL;
}
if (netif_running(netdev))
ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER;
XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
DBGPR("<--xgbe_suspend\n");
@@ -587,16 +867,16 @@ static int xgbe_suspend(struct device *dev)
static int xgbe_resume(struct device *dev)
{
struct net_device *netdev = dev_get_drvdata(dev);
int ret;
struct xgbe_prv_data *pdata = netdev_priv(netdev);
int ret = 0;
DBGPR("-->xgbe_resume\n");
if (!netif_running(netdev)) {
DBGPR("<--xgbe_dev_resume\n");
return -EINVAL;
}
pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER;
XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
if (netif_running(netdev))
ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
DBGPR("<--xgbe_resume\n");

File diff suppressed because it is too large Load Diff

View File

@@ -129,7 +129,7 @@
#include <net/dcbnl.h>
#define XGBE_DRV_NAME "amd-xgbe"
#define XGBE_DRV_VERSION "1.0.0-a"
#define XGBE_DRV_VERSION "1.0.1"
#define XGBE_DRV_DESC "AMD 10 Gigabit Ethernet Driver"
/* Descriptor related defines */
@@ -178,14 +178,17 @@
#define XGMAC_JUMBO_PACKET_MTU 9000
#define XGMAC_MAX_JUMBO_PACKET 9018
/* MDIO bus phy name */
#define XGBE_PHY_NAME "amd_xgbe_phy"
#define XGBE_PRTAD 0
/* Common property names */
#define XGBE_MAC_ADDR_PROPERTY "mac-address"
#define XGBE_PHY_MODE_PROPERTY "phy-mode"
#define XGBE_DMA_IRQS_PROPERTY "amd,per-channel-interrupt"
#define XGBE_SPEEDSET_PROPERTY "amd,speed-set"
#define XGBE_BLWC_PROPERTY "amd,serdes-blwc"
#define XGBE_CDR_RATE_PROPERTY "amd,serdes-cdr-rate"
#define XGBE_PQ_SKEW_PROPERTY "amd,serdes-pq-skew"
#define XGBE_TX_AMP_PROPERTY "amd,serdes-tx-amp"
#define XGBE_DFE_CFG_PROPERTY "amd,serdes-dfe-tap-config"
#define XGBE_DFE_ENA_PROPERTY "amd,serdes-dfe-tap-enable"
/* Device-tree clock names */
#define XGBE_DMA_CLOCK "dma_clk"
@@ -241,6 +244,49 @@
#define XGBE_RSS_LOOKUP_TABLE_TYPE 0
#define XGBE_RSS_HASH_KEY_TYPE 1
/* Auto-negotiation */
#define XGBE_AN_MS_TIMEOUT 500
#define XGBE_LINK_TIMEOUT 10
#define XGBE_AN_INT_CMPLT 0x01
#define XGBE_AN_INC_LINK 0x02
#define XGBE_AN_PG_RCV 0x04
#define XGBE_AN_INT_MASK 0x07
/* Rate-change complete wait/retry count */
#define XGBE_RATECHANGE_COUNT 500
/* Default SerDes settings */
#define XGBE_SPEED_10000_BLWC 0
#define XGBE_SPEED_10000_CDR 0x7
#define XGBE_SPEED_10000_PLL 0x1
#define XGBE_SPEED_10000_PQ 0x12
#define XGBE_SPEED_10000_RATE 0x0
#define XGBE_SPEED_10000_TXAMP 0xa
#define XGBE_SPEED_10000_WORD 0x7
#define XGBE_SPEED_10000_DFE_TAP_CONFIG 0x1
#define XGBE_SPEED_10000_DFE_TAP_ENABLE 0x7f
#define XGBE_SPEED_2500_BLWC 1
#define XGBE_SPEED_2500_CDR 0x2
#define XGBE_SPEED_2500_PLL 0x0
#define XGBE_SPEED_2500_PQ 0xa
#define XGBE_SPEED_2500_RATE 0x1
#define XGBE_SPEED_2500_TXAMP 0xf
#define XGBE_SPEED_2500_WORD 0x1
#define XGBE_SPEED_2500_DFE_TAP_CONFIG 0x3
#define XGBE_SPEED_2500_DFE_TAP_ENABLE 0x0
#define XGBE_SPEED_1000_BLWC 1
#define XGBE_SPEED_1000_CDR 0x2
#define XGBE_SPEED_1000_PLL 0x0
#define XGBE_SPEED_1000_PQ 0xa
#define XGBE_SPEED_1000_RATE 0x3
#define XGBE_SPEED_1000_TXAMP 0xf
#define XGBE_SPEED_1000_WORD 0x1
#define XGBE_SPEED_1000_DFE_TAP_CONFIG 0x3
#define XGBE_SPEED_1000_DFE_TAP_ENABLE 0x0
struct xgbe_prv_data;
struct xgbe_packet_data {
@@ -412,6 +458,13 @@ struct xgbe_channel {
struct xgbe_ring *rx_ring;
} ____cacheline_aligned;
enum xgbe_state {
XGBE_DOWN,
XGBE_LINK,
XGBE_LINK_INIT,
XGBE_LINK_ERR,
};
enum xgbe_int {
XGMAC_INT_DMA_CH_SR_TI,
XGMAC_INT_DMA_CH_SR_TPS,
@@ -443,6 +496,55 @@ enum xgbe_mtl_fifo_size {
XGMAC_MTL_FIFO_SIZE_256K = 0x3ff,
};
enum xgbe_speed {
XGBE_SPEED_1000 = 0,
XGBE_SPEED_2500,
XGBE_SPEED_10000,
XGBE_SPEEDS,
};
enum xgbe_an {
XGBE_AN_READY = 0,
XGBE_AN_PAGE_RECEIVED,
XGBE_AN_INCOMPAT_LINK,
XGBE_AN_COMPLETE,
XGBE_AN_NO_LINK,
XGBE_AN_ERROR,
};
enum xgbe_rx {
XGBE_RX_BPA = 0,
XGBE_RX_XNP,
XGBE_RX_COMPLETE,
XGBE_RX_ERROR,
};
enum xgbe_mode {
XGBE_MODE_KR = 0,
XGBE_MODE_KX,
};
enum xgbe_speedset {
XGBE_SPEEDSET_1000_10000 = 0,
XGBE_SPEEDSET_2500_10000,
};
struct xgbe_phy {
u32 supported;
u32 advertising;
u32 lp_advertising;
int address;
int autoneg;
int speed;
int duplex;
int pause;
int asym_pause;
int link;
};
struct xgbe_mmc_stats {
/* Tx Stats */
u64 txoctetcount_gb;
@@ -594,6 +696,20 @@ struct xgbe_hw_if {
int (*set_rss_lookup_table)(struct xgbe_prv_data *, const u32 *);
};
struct xgbe_phy_if {
/* For initial PHY setup */
void (*phy_init)(struct xgbe_prv_data *);
/* For PHY support when setting device up/down */
int (*phy_reset)(struct xgbe_prv_data *);
int (*phy_start)(struct xgbe_prv_data *);
void (*phy_stop)(struct xgbe_prv_data *);
/* For PHY support while device is up */
void (*phy_status)(struct xgbe_prv_data *);
int (*phy_config_aneg)(struct xgbe_prv_data *);
};
struct xgbe_desc_if {
int (*alloc_ring_resources)(struct xgbe_prv_data *);
void (*free_ring_resources)(struct xgbe_prv_data *);
@@ -663,6 +779,9 @@ struct xgbe_prv_data {
/* XGMAC/XPCS related mmio registers */
void __iomem *xgmac_regs; /* XGMAC CSRs */
void __iomem *xpcs_regs; /* XPCS MMD registers */
void __iomem *rxtx_regs; /* SerDes Rx/Tx CSRs */
void __iomem *sir0_regs; /* SerDes integration registers (1/2) */
void __iomem *sir1_regs; /* SerDes integration registers (2/2) */
/* Overall device lock */
spinlock_t lock;
@@ -673,10 +792,14 @@ struct xgbe_prv_data {
/* RSS addressing mutex */
struct mutex rss_mutex;
/* Flags representing xgbe_state */
unsigned long dev_state;
int dev_irq;
unsigned int per_channel_irq;
struct xgbe_hw_if hw_if;
struct xgbe_phy_if phy_if;
struct xgbe_desc_if desc_if;
/* AXI DMA settings */
@@ -685,6 +808,11 @@ struct xgbe_prv_data {
unsigned int arcache;
unsigned int awcache;
/* Service routine support */
struct workqueue_struct *dev_workqueue;
struct work_struct service_work;
struct timer_list service_timer;
/* Rings for Tx/Rx on a DMA channel */
struct xgbe_channel *channel;
unsigned int channel_count;
@@ -732,22 +860,6 @@ struct xgbe_prv_data {
u32 rss_table[XGBE_RSS_MAX_TABLE_SIZE];
u32 rss_options;
/* MDIO settings */
struct module *phy_module;
char *mii_bus_id;
struct mii_bus *mii;
int mdio_mmd;
struct phy_device *phydev;
int default_autoneg;
int default_speed;
/* Current PHY settings */
phy_interface_t phy_mode;
int phy_link;
int phy_speed;
unsigned int phy_tx_pause;
unsigned int phy_rx_pause;
/* Netdev related settings */
unsigned char mac_addr[ETH_ALEN];
netdev_features_t netdev_features;
@@ -794,6 +906,53 @@ struct xgbe_prv_data {
/* Network interface message level setting */
u32 msg_enable;
/* Current PHY settings */
phy_interface_t phy_mode;
int phy_link;
int phy_speed;
unsigned int phy_tx_pause;
unsigned int phy_rx_pause;
/* MDIO/PHY related settings */
struct xgbe_phy phy;
int mdio_mmd;
unsigned long link_check;
char an_name[IFNAMSIZ + 32];
struct workqueue_struct *an_workqueue;
int an_irq;
struct work_struct an_irq_work;
unsigned int speed_set;
/* SerDes UEFI configurable settings.
* Switching between modes/speeds requires new values for some
* SerDes settings. The values can be supplied as device
* properties in array format. The first array entry is for
* 1GbE, second for 2.5GbE and third for 10GbE
*/
u32 serdes_blwc[XGBE_SPEEDS];
u32 serdes_cdr_rate[XGBE_SPEEDS];
u32 serdes_pq_skew[XGBE_SPEEDS];
u32 serdes_tx_amp[XGBE_SPEEDS];
u32 serdes_dfe_tap_cfg[XGBE_SPEEDS];
u32 serdes_dfe_tap_ena[XGBE_SPEEDS];
/* Auto-negotiation state machine support */
struct mutex an_mutex;
enum xgbe_an an_result;
enum xgbe_an an_state;
enum xgbe_rx kr_state;
enum xgbe_rx kx_state;
struct work_struct an_work;
unsigned int an_supported;
unsigned int parallel_detect;
unsigned int fec_ability;
unsigned long an_start;
unsigned int lpm_ctrl; /* CTRL1 for resume */
#ifdef CONFIG_DEBUG_FS
struct dentry *xgbe_debugfs;
@@ -807,6 +966,7 @@ struct xgbe_prv_data {
/* Function prototypes*/
void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *);
void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *);
void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *);
struct net_device_ops *xgbe_get_netdev_ops(void);
struct ethtool_ops *xgbe_get_ethtool_ops(void);
@@ -814,9 +974,6 @@ struct ethtool_ops *xgbe_get_ethtool_ops(void);
const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void);
#endif
int xgbe_mdio_register(struct xgbe_prv_data *);
void xgbe_mdio_unregister(struct xgbe_prv_data *);
void xgbe_dump_phy_registers(struct xgbe_prv_data *);
void xgbe_ptp_register(struct xgbe_prv_data *);
void xgbe_ptp_unregister(struct xgbe_prv_data *);
void xgbe_dump_tx_desc(struct xgbe_prv_data *, struct xgbe_ring *,