Skip to content

Commit acc18c1

Browse files
girishks2000davem330
authored andcommitted
net: sxgbe: add EEE(Energy Efficient Ethernet) for Samsung sxgbe
Added support for the EEE(Energy Efficient Ethernet) in 10G ethernet driver. Signed-off-by: Girish K S <[email protected]> Neatening-by: Joe Perches <[email protected]> Signed-off-by: Byungho An <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1edb9ca commit acc18c1

File tree

6 files changed

+360
-2
lines changed

6 files changed

+360
-2
lines changed

drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,33 @@ struct sxgbe_mtl_ops;
118118
#define RX_PTP_SIGNAL 0x0A
119119
#define RX_PTP_RESV_MSG 0x0F
120120

121+
/* EEE-LPI mode flags*/
122+
#define TX_ENTRY_LPI_MODE 0x10
123+
#define TX_EXIT_LPI_MODE 0x20
124+
#define RX_ENTRY_LPI_MODE 0x40
125+
#define RX_EXIT_LPI_MODE 0x80
126+
127+
/* EEE-LPI Interrupt status flag */
128+
#define LPI_INT_STATUS BIT(5)
129+
130+
/* EEE-LPI Default timer values */
131+
#define LPI_LINK_STATUS_TIMER 0x3E8
132+
#define LPI_MAC_WAIT_TIMER 0x00
133+
134+
/* EEE-LPI Control and status definitions */
135+
#define LPI_CTRL_STATUS_TXA BIT(19)
136+
#define LPI_CTRL_STATUS_PLSDIS BIT(18)
137+
#define LPI_CTRL_STATUS_PLS BIT(17)
138+
#define LPI_CTRL_STATUS_LPIEN BIT(16)
139+
#define LPI_CTRL_STATUS_TXRSTP BIT(11)
140+
#define LPI_CTRL_STATUS_RXRSTP BIT(10)
141+
#define LPI_CTRL_STATUS_RLPIST BIT(9)
142+
#define LPI_CTRL_STATUS_TLPIST BIT(8)
143+
#define LPI_CTRL_STATUS_RLPIEX BIT(3)
144+
#define LPI_CTRL_STATUS_RLPIEN BIT(2)
145+
#define LPI_CTRL_STATUS_TLPIEX BIT(1)
146+
#define LPI_CTRL_STATUS_TLPIEN BIT(0)
147+
121148
enum dma_irq_status {
122149
tx_hard_error = BIT(0),
123150
tx_bump_tc = BIT(1),
@@ -202,6 +229,13 @@ struct sxgbe_extra_stats {
202229
unsigned long rx_buffer_access_err;
203230
unsigned long rx_data_transfer_err;
204231

232+
/* EEE-LPI stats */
233+
unsigned long tx_lpi_entry_n;
234+
unsigned long tx_lpi_exit_n;
235+
unsigned long rx_lpi_entry_n;
236+
unsigned long rx_lpi_exit_n;
237+
unsigned long eee_wakeup_error_n;
238+
205239
/* RX specific */
206240
/* L2 error */
207241
unsigned long rx_code_gmii_err;
@@ -299,6 +333,13 @@ struct sxgbe_core_ops {
299333
unsigned char feature_index);
300334
/* adjust SXGBE speed */
301335
void (*set_speed)(void __iomem *ioaddr, unsigned char speed);
336+
337+
/* EEE-LPI specific operations */
338+
void (*set_eee_mode)(void __iomem *ioaddr);
339+
void (*reset_eee_mode)(void __iomem *ioaddr);
340+
void (*set_eee_timer)(void __iomem *ioaddr, const int ls,
341+
const int tw);
342+
void (*set_eee_pls)(void __iomem *ioaddr, const int link);
302343
};
303344

304345
const struct sxgbe_core_ops *sxgbe_get_core_ops(void);
@@ -354,6 +395,8 @@ struct sxgbe_hw_features {
354395
/* IEEE 1588-2008 */
355396
unsigned int atime_stamp;
356397

398+
unsigned int eee;
399+
357400
unsigned int tx_csum_offload;
358401
unsigned int rx_csum_offload;
359402
unsigned int multi_macaddr;
@@ -437,6 +480,13 @@ struct sxgbe_priv_data {
437480
/* tc control */
438481
int tx_tc;
439482
int rx_tc;
483+
/* EEE-LPI specific members */
484+
struct timer_list eee_ctrl_timer;
485+
bool tx_path_in_lpi_mode;
486+
int lpi_irq;
487+
int eee_enabled;
488+
int eee_active;
489+
int tx_lpi_timer;
440490
};
441491

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

460510
const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void);
461511

512+
void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv);
513+
bool sxgbe_eee_init(struct sxgbe_priv_data * const priv);
514+
462515
#endif /* __SXGBE_COMMON_H__ */

drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,38 @@ static void sxgbe_core_dump_regs(void __iomem *ioaddr)
4848
{
4949
}
5050

51+
static int sxgbe_get_lpi_status(void __iomem *ioaddr, const u32 irq_status)
52+
{
53+
int status = 0;
54+
int lpi_status;
55+
56+
/* Reading this register shall clear all the LPI status bits */
57+
lpi_status = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
58+
59+
if (lpi_status & LPI_CTRL_STATUS_TLPIEN)
60+
status |= TX_ENTRY_LPI_MODE;
61+
if (lpi_status & LPI_CTRL_STATUS_TLPIEX)
62+
status |= TX_EXIT_LPI_MODE;
63+
if (lpi_status & LPI_CTRL_STATUS_RLPIEN)
64+
status |= RX_ENTRY_LPI_MODE;
65+
if (lpi_status & LPI_CTRL_STATUS_RLPIEX)
66+
status |= RX_EXIT_LPI_MODE;
67+
68+
return status;
69+
}
70+
5171
/* Handle extra events on specific interrupts hw dependent */
5272
static int sxgbe_core_host_irq_status(void __iomem *ioaddr,
5373
struct sxgbe_extra_stats *x)
5474
{
55-
return 0;
75+
int irq_status, status = 0;
76+
77+
irq_status = readl(ioaddr + SXGBE_CORE_INT_STATUS_REG);
78+
79+
if (unlikely(irq_status & LPI_INT_STATUS))
80+
status |= sxgbe_get_lpi_status(ioaddr, irq_status);
81+
82+
return status;
5683
}
5784

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

168+
static void sxgbe_set_eee_mode(void __iomem *ioaddr)
169+
{
170+
u32 ctrl;
171+
172+
/* Enable the LPI mode for transmit path with Tx automate bit set.
173+
* When Tx Automate bit is set, MAC internally handles the entry
174+
* to LPI mode after all outstanding and pending packets are
175+
* transmitted.
176+
*/
177+
ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
178+
ctrl |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA;
179+
writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
180+
}
181+
182+
static void sxgbe_reset_eee_mode(void __iomem *ioaddr)
183+
{
184+
u32 ctrl;
185+
186+
ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
187+
ctrl &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA);
188+
writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
189+
}
190+
191+
static void sxgbe_set_eee_pls(void __iomem *ioaddr, const int link)
192+
{
193+
u32 ctrl;
194+
195+
ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
196+
197+
/* If the PHY link status is UP then set PLS */
198+
if (link)
199+
ctrl |= LPI_CTRL_STATUS_PLS;
200+
else
201+
ctrl &= ~LPI_CTRL_STATUS_PLS;
202+
203+
writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
204+
}
205+
206+
static void sxgbe_set_eee_timer(void __iomem *ioaddr,
207+
const int ls, const int tw)
208+
{
209+
int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
210+
211+
/* Program the timers in the LPI timer control register:
212+
* LS: minimum time (ms) for which the link
213+
* status from PHY should be ok before transmitting
214+
* the LPI pattern.
215+
* TW: minimum time (us) for which the core waits
216+
* after it has stopped transmitting the LPI pattern.
217+
*/
218+
writel(value, ioaddr + SXGBE_CORE_LPI_TIMER_CTRL);
219+
}
220+
141221
const struct sxgbe_core_ops core_ops = {
142222
.core_init = sxgbe_core_init,
143223
.dump_regs = sxgbe_core_dump_regs,
@@ -150,6 +230,10 @@ const struct sxgbe_core_ops core_ops = {
150230
.get_controller_version = sxgbe_get_controller_version,
151231
.get_hw_feature = sxgbe_get_hw_feature,
152232
.set_speed = sxgbe_core_set_speed,
233+
.set_eee_mode = sxgbe_set_eee_mode,
234+
.reset_eee_mode = sxgbe_reset_eee_mode,
235+
.set_eee_timer = sxgbe_set_eee_timer,
236+
.set_eee_pls = sxgbe_set_eee_pls,
153237
};
154238

155239
const struct sxgbe_core_ops *sxgbe_get_core_ops(void)

drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,57 @@ struct sxgbe_stats {
3232
}
3333

3434
static const struct sxgbe_stats sxgbe_gstrings_stats[] = {
35+
SXGBE_STAT(tx_lpi_entry_n),
36+
SXGBE_STAT(tx_lpi_exit_n),
37+
SXGBE_STAT(rx_lpi_entry_n),
38+
SXGBE_STAT(rx_lpi_exit_n),
39+
SXGBE_STAT(eee_wakeup_error_n),
3540
};
3641
#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats)
3742

43+
static int sxgbe_get_eee(struct net_device *dev,
44+
struct ethtool_eee *edata)
45+
{
46+
struct sxgbe_priv_data *priv = netdev_priv(dev);
47+
48+
if (!priv->hw_cap.eee)
49+
return -EOPNOTSUPP;
50+
51+
edata->eee_enabled = priv->eee_enabled;
52+
edata->eee_active = priv->eee_active;
53+
edata->tx_lpi_timer = priv->tx_lpi_timer;
54+
55+
return phy_ethtool_get_eee(priv->phydev, edata);
56+
}
57+
58+
static int sxgbe_set_eee(struct net_device *dev,
59+
struct ethtool_eee *edata)
60+
{
61+
struct sxgbe_priv_data *priv = netdev_priv(dev);
62+
63+
priv->eee_enabled = edata->eee_enabled;
64+
65+
if (!priv->eee_enabled) {
66+
sxgbe_disable_eee_mode(priv);
67+
} else {
68+
/* We are asking for enabling the EEE but it is safe
69+
* to verify all by invoking the eee_init function.
70+
* In case of failure it will return an error.
71+
*/
72+
priv->eee_enabled = sxgbe_eee_init(priv);
73+
if (!priv->eee_enabled)
74+
return -EOPNOTSUPP;
75+
76+
/* Do not change tx_lpi_timer in case of failure */
77+
priv->tx_lpi_timer = edata->tx_lpi_timer;
78+
}
79+
80+
return phy_ethtool_set_eee(priv->phydev, edata);
81+
}
82+
3883
static const struct ethtool_ops sxgbe_ethtool_ops = {
84+
.get_eee = sxgbe_get_eee,
85+
.set_eee = sxgbe_set_eee,
3986
};
4087

4188
void sxgbe_set_ethtool_ops(struct net_device *netdev)

0 commit comments

Comments
 (0)