Skip to content

Commit

Permalink
net: sxgbe: add EEE(Energy Efficient Ethernet) for Samsung sxgbe
Browse files Browse the repository at this point in the history
Added support for the EEE(Energy Efficient Ethernet) in 10G ethernet driver.

Signed-off-by: Girish K S <ks.giri@samsung.com>
Neatening-by: Joe Perches <joe@perches.com>
Signed-off-by: Byungho An <bh74.an@samsung.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Girish K S authored and David S. Miller committed Mar 26, 2014
1 parent 1edb9ca commit acc18c1
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 2 deletions.
53 changes: 53 additions & 0 deletions drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,33 @@ struct sxgbe_mtl_ops;
#define RX_PTP_SIGNAL 0x0A
#define RX_PTP_RESV_MSG 0x0F

/* EEE-LPI mode flags*/
#define TX_ENTRY_LPI_MODE 0x10
#define TX_EXIT_LPI_MODE 0x20
#define RX_ENTRY_LPI_MODE 0x40
#define RX_EXIT_LPI_MODE 0x80

/* EEE-LPI Interrupt status flag */
#define LPI_INT_STATUS BIT(5)

/* EEE-LPI Default timer values */
#define LPI_LINK_STATUS_TIMER 0x3E8
#define LPI_MAC_WAIT_TIMER 0x00

/* EEE-LPI Control and status definitions */
#define LPI_CTRL_STATUS_TXA BIT(19)
#define LPI_CTRL_STATUS_PLSDIS BIT(18)
#define LPI_CTRL_STATUS_PLS BIT(17)
#define LPI_CTRL_STATUS_LPIEN BIT(16)
#define LPI_CTRL_STATUS_TXRSTP BIT(11)
#define LPI_CTRL_STATUS_RXRSTP BIT(10)
#define LPI_CTRL_STATUS_RLPIST BIT(9)
#define LPI_CTRL_STATUS_TLPIST BIT(8)
#define LPI_CTRL_STATUS_RLPIEX BIT(3)
#define LPI_CTRL_STATUS_RLPIEN BIT(2)
#define LPI_CTRL_STATUS_TLPIEX BIT(1)
#define LPI_CTRL_STATUS_TLPIEN BIT(0)

enum dma_irq_status {
tx_hard_error = BIT(0),
tx_bump_tc = BIT(1),
Expand Down Expand Up @@ -202,6 +229,13 @@ struct sxgbe_extra_stats {
unsigned long rx_buffer_access_err;
unsigned long rx_data_transfer_err;

/* EEE-LPI stats */
unsigned long tx_lpi_entry_n;
unsigned long tx_lpi_exit_n;
unsigned long rx_lpi_entry_n;
unsigned long rx_lpi_exit_n;
unsigned long eee_wakeup_error_n;

/* RX specific */
/* L2 error */
unsigned long rx_code_gmii_err;
Expand Down Expand Up @@ -299,6 +333,13 @@ struct sxgbe_core_ops {
unsigned char feature_index);
/* adjust SXGBE speed */
void (*set_speed)(void __iomem *ioaddr, unsigned char speed);

/* EEE-LPI specific operations */
void (*set_eee_mode)(void __iomem *ioaddr);
void (*reset_eee_mode)(void __iomem *ioaddr);
void (*set_eee_timer)(void __iomem *ioaddr, const int ls,
const int tw);
void (*set_eee_pls)(void __iomem *ioaddr, const int link);
};

const struct sxgbe_core_ops *sxgbe_get_core_ops(void);
Expand Down Expand Up @@ -354,6 +395,8 @@ struct sxgbe_hw_features {
/* IEEE 1588-2008 */
unsigned int atime_stamp;

unsigned int eee;

unsigned int tx_csum_offload;
unsigned int rx_csum_offload;
unsigned int multi_macaddr;
Expand Down Expand Up @@ -437,6 +480,13 @@ struct sxgbe_priv_data {
/* tc control */
int tx_tc;
int rx_tc;
/* EEE-LPI specific members */
struct timer_list eee_ctrl_timer;
bool tx_path_in_lpi_mode;
int lpi_irq;
int eee_enabled;
int eee_active;
int tx_lpi_timer;
};

/* Function prototypes */
Expand All @@ -459,4 +509,7 @@ int sxgbe_restore(struct net_device *ndev);

const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void);

void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv);
bool sxgbe_eee_init(struct sxgbe_priv_data * const priv);

#endif /* __SXGBE_COMMON_H__ */
86 changes: 85 additions & 1 deletion drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,38 @@ static void sxgbe_core_dump_regs(void __iomem *ioaddr)
{
}

static int sxgbe_get_lpi_status(void __iomem *ioaddr, const u32 irq_status)
{
int status = 0;
int lpi_status;

/* Reading this register shall clear all the LPI status bits */
lpi_status = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);

if (lpi_status & LPI_CTRL_STATUS_TLPIEN)
status |= TX_ENTRY_LPI_MODE;
if (lpi_status & LPI_CTRL_STATUS_TLPIEX)
status |= TX_EXIT_LPI_MODE;
if (lpi_status & LPI_CTRL_STATUS_RLPIEN)
status |= RX_ENTRY_LPI_MODE;
if (lpi_status & LPI_CTRL_STATUS_RLPIEX)
status |= RX_EXIT_LPI_MODE;

return status;
}

/* Handle extra events on specific interrupts hw dependent */
static int sxgbe_core_host_irq_status(void __iomem *ioaddr,
struct sxgbe_extra_stats *x)
{
return 0;
int irq_status, status = 0;

irq_status = readl(ioaddr + SXGBE_CORE_INT_STATUS_REG);

if (unlikely(irq_status & LPI_INT_STATUS))
status |= sxgbe_get_lpi_status(ioaddr, irq_status);

return status;
}

/* Set power management mode (e.g. magic frame) */
Expand Down Expand Up @@ -138,6 +165,59 @@ static void sxgbe_core_set_speed(void __iomem *ioaddr, unsigned char speed)
writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
}

static void sxgbe_set_eee_mode(void __iomem *ioaddr)
{
u32 ctrl;

/* Enable the LPI mode for transmit path with Tx automate bit set.
* When Tx Automate bit is set, MAC internally handles the entry
* to LPI mode after all outstanding and pending packets are
* transmitted.
*/
ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
ctrl |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA;
writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
}

static void sxgbe_reset_eee_mode(void __iomem *ioaddr)
{
u32 ctrl;

ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
ctrl &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA);
writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
}

static void sxgbe_set_eee_pls(void __iomem *ioaddr, const int link)
{
u32 ctrl;

ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);

/* If the PHY link status is UP then set PLS */
if (link)
ctrl |= LPI_CTRL_STATUS_PLS;
else
ctrl &= ~LPI_CTRL_STATUS_PLS;

writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
}

static void sxgbe_set_eee_timer(void __iomem *ioaddr,
const int ls, const int tw)
{
int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);

/* Program the timers in the LPI timer control register:
* LS: minimum time (ms) for which the link
* status from PHY should be ok before transmitting
* the LPI pattern.
* TW: minimum time (us) for which the core waits
* after it has stopped transmitting the LPI pattern.
*/
writel(value, ioaddr + SXGBE_CORE_LPI_TIMER_CTRL);
}

const struct sxgbe_core_ops core_ops = {
.core_init = sxgbe_core_init,
.dump_regs = sxgbe_core_dump_regs,
Expand All @@ -150,6 +230,10 @@ const struct sxgbe_core_ops core_ops = {
.get_controller_version = sxgbe_get_controller_version,
.get_hw_feature = sxgbe_get_hw_feature,
.set_speed = sxgbe_core_set_speed,
.set_eee_mode = sxgbe_set_eee_mode,
.reset_eee_mode = sxgbe_reset_eee_mode,
.set_eee_timer = sxgbe_set_eee_timer,
.set_eee_pls = sxgbe_set_eee_pls,
};

const struct sxgbe_core_ops *sxgbe_get_core_ops(void)
Expand Down
47 changes: 47 additions & 0 deletions drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,57 @@ struct sxgbe_stats {
}

static const struct sxgbe_stats sxgbe_gstrings_stats[] = {
SXGBE_STAT(tx_lpi_entry_n),
SXGBE_STAT(tx_lpi_exit_n),
SXGBE_STAT(rx_lpi_entry_n),
SXGBE_STAT(rx_lpi_exit_n),
SXGBE_STAT(eee_wakeup_error_n),
};
#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats)

static int sxgbe_get_eee(struct net_device *dev,
struct ethtool_eee *edata)
{
struct sxgbe_priv_data *priv = netdev_priv(dev);

if (!priv->hw_cap.eee)
return -EOPNOTSUPP;

edata->eee_enabled = priv->eee_enabled;
edata->eee_active = priv->eee_active;
edata->tx_lpi_timer = priv->tx_lpi_timer;

return phy_ethtool_get_eee(priv->phydev, edata);
}

static int sxgbe_set_eee(struct net_device *dev,
struct ethtool_eee *edata)
{
struct sxgbe_priv_data *priv = netdev_priv(dev);

priv->eee_enabled = edata->eee_enabled;

if (!priv->eee_enabled) {
sxgbe_disable_eee_mode(priv);
} else {
/* We are asking for enabling the EEE but it is safe
* to verify all by invoking the eee_init function.
* In case of failure it will return an error.
*/
priv->eee_enabled = sxgbe_eee_init(priv);
if (!priv->eee_enabled)
return -EOPNOTSUPP;

/* Do not change tx_lpi_timer in case of failure */
priv->tx_lpi_timer = edata->tx_lpi_timer;
}

return phy_ethtool_set_eee(priv->phydev, edata);
}

static const struct ethtool_ops sxgbe_ethtool_ops = {
.get_eee = sxgbe_get_eee,
.set_eee = sxgbe_set_eee,
};

void sxgbe_set_ethtool_ops(struct net_device *netdev)
Expand Down
Loading

0 comments on commit acc18c1

Please sign in to comment.