aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGirish K S <ks.giri@samsung.com>2014-03-25 15:10:57 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-26 16:49:31 -0400
commitacc18c147b2281ff85f93862eb8c768df1bfb7df (patch)
tree6af088d7b1f44301d8e865074d0c99c622e04e85
parent1edb9ca69e8a7988900fc0283e10550b5592164d (diff)
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 <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>
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h53
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c86
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c47
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c165
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c6
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h5
6 files changed, 360 insertions, 2 deletions
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
index c7803f199967..fd367cb6bcad 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
@@ -118,6 +118,33 @@ struct sxgbe_mtl_ops;
118#define RX_PTP_SIGNAL 0x0A 118#define RX_PTP_SIGNAL 0x0A
119#define RX_PTP_RESV_MSG 0x0F 119#define RX_PTP_RESV_MSG 0x0F
120 120
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
121enum dma_irq_status { 148enum dma_irq_status {
122 tx_hard_error = BIT(0), 149 tx_hard_error = BIT(0),
123 tx_bump_tc = BIT(1), 150 tx_bump_tc = BIT(1),
@@ -202,6 +229,13 @@ struct sxgbe_extra_stats {
202 unsigned long rx_buffer_access_err; 229 unsigned long rx_buffer_access_err;
203 unsigned long rx_data_transfer_err; 230 unsigned long rx_data_transfer_err;
204 231
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
205 /* RX specific */ 239 /* RX specific */
206 /* L2 error */ 240 /* L2 error */
207 unsigned long rx_code_gmii_err; 241 unsigned long rx_code_gmii_err;
@@ -299,6 +333,13 @@ struct sxgbe_core_ops {
299 unsigned char feature_index); 333 unsigned char feature_index);
300 /* adjust SXGBE speed */ 334 /* adjust SXGBE speed */
301 void (*set_speed)(void __iomem *ioaddr, unsigned char speed); 335 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);
302}; 343};
303 344
304const struct sxgbe_core_ops *sxgbe_get_core_ops(void); 345const struct sxgbe_core_ops *sxgbe_get_core_ops(void);
@@ -354,6 +395,8 @@ struct sxgbe_hw_features {
354 /* IEEE 1588-2008 */ 395 /* IEEE 1588-2008 */
355 unsigned int atime_stamp; 396 unsigned int atime_stamp;
356 397
398 unsigned int eee;
399
357 unsigned int tx_csum_offload; 400 unsigned int tx_csum_offload;
358 unsigned int rx_csum_offload; 401 unsigned int rx_csum_offload;
359 unsigned int multi_macaddr; 402 unsigned int multi_macaddr;
@@ -437,6 +480,13 @@ struct sxgbe_priv_data {
437 /* tc control */ 480 /* tc control */
438 int tx_tc; 481 int tx_tc;
439 int rx_tc; 482 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;
440}; 490};
441 491
442/* Function prototypes */ 492/* Function prototypes */
@@ -459,4 +509,7 @@ int sxgbe_restore(struct net_device *ndev);
459 509
460const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void); 510const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void);
461 511
512void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv);
513bool sxgbe_eee_init(struct sxgbe_priv_data * const priv);
514
462#endif /* __SXGBE_COMMON_H__ */ 515#endif /* __SXGBE_COMMON_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
index 4ad31bbc42c9..01647901f55f 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
@@ -48,11 +48,38 @@ static void sxgbe_core_dump_regs(void __iomem *ioaddr)
48{ 48{
49} 49}
50 50
51static 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
51/* Handle extra events on specific interrupts hw dependent */ 71/* Handle extra events on specific interrupts hw dependent */
52static int sxgbe_core_host_irq_status(void __iomem *ioaddr, 72static int sxgbe_core_host_irq_status(void __iomem *ioaddr,
53 struct sxgbe_extra_stats *x) 73 struct sxgbe_extra_stats *x)
54{ 74{
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;
56} 83}
57 84
58/* Set power management mode (e.g. magic frame) */ 85/* Set power management mode (e.g. magic frame) */
@@ -138,6 +165,59 @@ static void sxgbe_core_set_speed(void __iomem *ioaddr, unsigned char speed)
138 writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG); 165 writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
139} 166}
140 167
168static 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
182static 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
191static 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
206static 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
141const struct sxgbe_core_ops core_ops = { 221const struct sxgbe_core_ops core_ops = {
142 .core_init = sxgbe_core_init, 222 .core_init = sxgbe_core_init,
143 .dump_regs = sxgbe_core_dump_regs, 223 .dump_regs = sxgbe_core_dump_regs,
@@ -150,6 +230,10 @@ const struct sxgbe_core_ops core_ops = {
150 .get_controller_version = sxgbe_get_controller_version, 230 .get_controller_version = sxgbe_get_controller_version,
151 .get_hw_feature = sxgbe_get_hw_feature, 231 .get_hw_feature = sxgbe_get_hw_feature,
152 .set_speed = sxgbe_core_set_speed, 232 .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,
153}; 237};
154 238
155const struct sxgbe_core_ops *sxgbe_get_core_ops(void) 239const struct sxgbe_core_ops *sxgbe_get_core_ops(void)
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
index 1dce2b2e045b..ca95f1daefd8 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
@@ -32,10 +32,57 @@ struct sxgbe_stats {
32} 32}
33 33
34static const struct sxgbe_stats sxgbe_gstrings_stats[] = { 34static 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),
35}; 40};
36#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats) 41#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats)
37 42
43static 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
58static 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
38static const struct ethtool_ops sxgbe_ethtool_ops = { 83static const struct ethtool_ops sxgbe_ethtool_ops = {
84 .get_eee = sxgbe_get_eee,
85 .set_eee = sxgbe_set_eee,
39}; 86};
40 87
41void sxgbe_set_ethtool_ops(struct net_device *netdev) 88void sxgbe_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
index 75ba57cfe7c0..fbee3da4c592 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -55,6 +55,9 @@
55#define SXGBE_DEFAULT_LPI_TIMER 1000 55#define SXGBE_DEFAULT_LPI_TIMER 1000
56 56
57static int debug = -1; 57static int debug = -1;
58static int eee_timer = SXGBE_DEFAULT_LPI_TIMER;
59
60module_param(eee_timer, int, S_IRUGO | S_IWUSR);
58 61
59module_param(debug, int, S_IRUGO | S_IWUSR); 62module_param(debug, int, S_IRUGO | S_IWUSR);
60static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | 63static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
@@ -67,6 +70,97 @@ static irqreturn_t sxgbe_rx_interrupt(int irq, void *dev_id);
67 70
68#define SXGBE_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) 71#define SXGBE_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
69 72
73#define SXGBE_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
74
75/**
76 * sxgbe_verify_args - verify the driver parameters.
77 * Description: it verifies if some wrong parameter is passed to the driver.
78 * Note that wrong parameters are replaced with the default values.
79 */
80static void sxgbe_verify_args(void)
81{
82 if (unlikely(eee_timer < 0))
83 eee_timer = SXGBE_DEFAULT_LPI_TIMER;
84}
85
86static void sxgbe_enable_eee_mode(const struct sxgbe_priv_data *priv)
87{
88 /* Check and enter in LPI mode */
89 if (!priv->tx_path_in_lpi_mode)
90 priv->hw->mac->set_eee_mode(priv->ioaddr);
91}
92
93void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv)
94{
95 /* Exit and disable EEE in case of we are are in LPI state. */
96 priv->hw->mac->reset_eee_mode(priv->ioaddr);
97 del_timer_sync(&priv->eee_ctrl_timer);
98 priv->tx_path_in_lpi_mode = false;
99}
100
101/**
102 * sxgbe_eee_ctrl_timer
103 * @arg : data hook
104 * Description:
105 * If there is no data transfer and if we are not in LPI state,
106 * then MAC Transmitter can be moved to LPI state.
107 */
108static void sxgbe_eee_ctrl_timer(unsigned long arg)
109{
110 struct sxgbe_priv_data *priv = (struct sxgbe_priv_data *)arg;
111
112 sxgbe_enable_eee_mode(priv);
113 mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer));
114}
115
116/**
117 * sxgbe_eee_init
118 * @priv: private device pointer
119 * Description:
120 * If the EEE support has been enabled while configuring the driver,
121 * if the GMAC actually supports the EEE (from the HW cap reg) and the
122 * phy can also manage EEE, so enable the LPI state and start the timer
123 * to verify if the tx path can enter in LPI state.
124 */
125bool sxgbe_eee_init(struct sxgbe_priv_data * const priv)
126{
127 bool ret = false;
128
129 /* MAC core supports the EEE feature. */
130 if (priv->hw_cap.eee) {
131 /* Check if the PHY supports EEE */
132 if (phy_init_eee(priv->phydev, 1))
133 return false;
134
135 priv->eee_active = 1;
136 init_timer(&priv->eee_ctrl_timer);
137 priv->eee_ctrl_timer.function = sxgbe_eee_ctrl_timer;
138 priv->eee_ctrl_timer.data = (unsigned long)priv;
139 priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer);
140 add_timer(&priv->eee_ctrl_timer);
141
142 priv->hw->mac->set_eee_timer(priv->ioaddr,
143 SXGBE_DEFAULT_LPI_TIMER,
144 priv->tx_lpi_timer);
145
146 pr_info("Energy-Efficient Ethernet initialized\n");
147
148 ret = true;
149 }
150
151 return ret;
152}
153
154static void sxgbe_eee_adjust(const struct sxgbe_priv_data *priv)
155{
156 /* When the EEE has been already initialised we have to
157 * modify the PLS bit in the LPI ctrl & status reg according
158 * to the PHY link status. For this reason.
159 */
160 if (priv->eee_enabled)
161 priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
162}
163
70/** 164/**
71 * sxgbe_clk_csr_set - dynamically set the MDC clock 165 * sxgbe_clk_csr_set - dynamically set the MDC clock
72 * @priv: driver private structure 166 * @priv: driver private structure
@@ -156,6 +250,9 @@ static void sxgbe_adjust_link(struct net_device *dev)
156 250
157 if (new_state & netif_msg_link(priv)) 251 if (new_state & netif_msg_link(priv))
158 phy_print_status(phydev); 252 phy_print_status(phydev);
253
254 /* Alter the MAC settings for EEE */
255 sxgbe_eee_adjust(priv);
159} 256}
160 257
161/** 258/**
@@ -676,7 +773,7 @@ static void sxgbe_tx_queue_clean(struct sxgbe_tx_queue *tqueue)
676 * @priv: driver private structure 773 * @priv: driver private structure
677 * Description: it reclaims resources after transmission completes. 774 * Description: it reclaims resources after transmission completes.
678 */ 775 */
679static void sxgbe_tx_all_clean(struct sxgbe_priv_data *priv) 776static void sxgbe_tx_all_clean(struct sxgbe_priv_data * const priv)
680{ 777{
681 u8 queue_num; 778 u8 queue_num;
682 779
@@ -685,6 +782,11 @@ static void sxgbe_tx_all_clean(struct sxgbe_priv_data *priv)
685 782
686 sxgbe_tx_queue_clean(tqueue); 783 sxgbe_tx_queue_clean(tqueue);
687 } 784 }
785
786 if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
787 sxgbe_enable_eee_mode(priv);
788 mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer));
789 }
688} 790}
689 791
690/** 792/**
@@ -766,6 +868,7 @@ static int sxgbe_get_hw_features(struct sxgbe_priv_data * const priv)
766 features->multi_macaddr = SXGBE_HW_FEAT_MACADDR_COUNT(rval); 868 features->multi_macaddr = SXGBE_HW_FEAT_MACADDR_COUNT(rval);
767 features->tstamp_srcselect = SXGBE_HW_FEAT_TSTMAP_SRC(rval); 869 features->tstamp_srcselect = SXGBE_HW_FEAT_TSTMAP_SRC(rval);
768 features->sa_vlan_insert = SXGBE_HW_FEAT_SRCADDR_VLAN(rval); 870 features->sa_vlan_insert = SXGBE_HW_FEAT_SRCADDR_VLAN(rval);
871 features->eee = SXGBE_HW_FEAT_EEE(rval);
769 } 872 }
770 873
771 /* Read First Capability Register CAP[1] */ 874 /* Read First Capability Register CAP[1] */
@@ -983,6 +1086,20 @@ static int sxgbe_open(struct net_device *dev)
983 goto init_error; 1086 goto init_error;
984 } 1087 }
985 1088
1089 /* If the LPI irq is different from the mac irq
1090 * register a dedicated handler
1091 */
1092 if (priv->lpi_irq != dev->irq) {
1093 ret = devm_request_irq(priv->device, priv->lpi_irq,
1094 sxgbe_common_interrupt,
1095 IRQF_SHARED, dev->name, dev);
1096 if (unlikely(ret < 0)) {
1097 netdev_err(dev, "%s: ERROR: allocating the LPI IRQ %d (%d)\n",
1098 __func__, priv->lpi_irq, ret);
1099 goto init_error;
1100 }
1101 }
1102
986 /* Request TX DMA irq lines */ 1103 /* Request TX DMA irq lines */
987 SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 1104 SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
988 ret = devm_request_irq(priv->device, 1105 ret = devm_request_irq(priv->device,
@@ -1038,6 +1155,9 @@ static int sxgbe_open(struct net_device *dev)
1038 priv->hw->dma->rx_watchdog(priv->ioaddr, SXGBE_MAX_DMA_RIWT); 1155 priv->hw->dma->rx_watchdog(priv->ioaddr, SXGBE_MAX_DMA_RIWT);
1039 } 1156 }
1040 1157
1158 priv->tx_lpi_timer = SXGBE_DEFAULT_LPI_TIMER;
1159 priv->eee_enabled = sxgbe_eee_init(priv);
1160
1041 napi_enable(&priv->napi); 1161 napi_enable(&priv->napi);
1042 netif_start_queue(dev); 1162 netif_start_queue(dev);
1043 1163
@@ -1063,6 +1183,9 @@ static int sxgbe_release(struct net_device *dev)
1063{ 1183{
1064 struct sxgbe_priv_data *priv = netdev_priv(dev); 1184 struct sxgbe_priv_data *priv = netdev_priv(dev);
1065 1185
1186 if (priv->eee_enabled)
1187 del_timer_sync(&priv->eee_ctrl_timer);
1188
1066 /* Stop and disconnect the PHY */ 1189 /* Stop and disconnect the PHY */
1067 if (priv->phydev) { 1190 if (priv->phydev) {
1068 phy_stop(priv->phydev); 1191 phy_stop(priv->phydev);
@@ -1123,6 +1246,9 @@ static netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev)
1123 /* get the spinlock */ 1246 /* get the spinlock */
1124 spin_lock(&tqueue->tx_lock); 1247 spin_lock(&tqueue->tx_lock);
1125 1248
1249 if (priv->tx_path_in_lpi_mode)
1250 sxgbe_disable_eee_mode(priv);
1251
1126 if (unlikely(sxgbe_tx_avail(tqueue, tx_rsize) < nr_frags + 1)) { 1252 if (unlikely(sxgbe_tx_avail(tqueue, tx_rsize) < nr_frags + 1)) {
1127 if (!netif_tx_queue_stopped(dev_txq)) { 1253 if (!netif_tx_queue_stopped(dev_txq)) {
1128 netif_tx_stop_queue(dev_txq); 1254 netif_tx_stop_queue(dev_txq);
@@ -1380,6 +1506,25 @@ static void sxgbe_tx_timeout(struct net_device *dev)
1380 */ 1506 */
1381static irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id) 1507static irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id)
1382{ 1508{
1509 struct net_device *netdev = (struct net_device *)dev_id;
1510 struct sxgbe_priv_data *priv = netdev_priv(netdev);
1511 int status;
1512
1513 status = priv->hw->mac->host_irq_status(priv->ioaddr, &priv->xstats);
1514 /* For LPI we need to save the tx status */
1515 if (status & TX_ENTRY_LPI_MODE) {
1516 priv->xstats.tx_lpi_entry_n++;
1517 priv->tx_path_in_lpi_mode = true;
1518 }
1519 if (status & TX_EXIT_LPI_MODE) {
1520 priv->xstats.tx_lpi_exit_n++;
1521 priv->tx_path_in_lpi_mode = false;
1522 }
1523 if (status & RX_ENTRY_LPI_MODE)
1524 priv->xstats.rx_lpi_entry_n++;
1525 if (status & RX_EXIT_LPI_MODE)
1526 priv->xstats.rx_lpi_exit_n++;
1527
1383 return IRQ_HANDLED; 1528 return IRQ_HANDLED;
1384} 1529}
1385 1530
@@ -1876,6 +2021,9 @@ struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
1876 priv->plat = plat_dat; 2021 priv->plat = plat_dat;
1877 priv->ioaddr = addr; 2022 priv->ioaddr = addr;
1878 2023
2024 /* Verify driver arguments */
2025 sxgbe_verify_args();
2026
1879 /* Init MAC and get the capabilities */ 2027 /* Init MAC and get the capabilities */
1880 sxgbe_hw_init(priv); 2028 sxgbe_hw_init(priv);
1881 2029
@@ -2032,7 +2180,21 @@ module_exit(sxgbe_exit);
2032#ifndef MODULE 2180#ifndef MODULE
2033static int __init sxgbe_cmdline_opt(char *str) 2181static int __init sxgbe_cmdline_opt(char *str)
2034{ 2182{
2183 char *opt;
2184
2185 if (!str || !*str)
2186 return -EINVAL;
2187 while ((opt = strsep(&str, ",")) != NULL) {
2188 if (!strncmp(opt, "eee_timer:", 6)) {
2189 if (kstrtoint(opt + 10, 0, &eee_timer))
2190 goto err;
2191 }
2192 }
2035 return 0; 2193 return 0;
2194
2195err:
2196 pr_err("%s: ERROR broken module parameter conversion\n", __func__);
2197 return -EINVAL;
2036} 2198}
2037 2199
2038__setup("sxgbeeth=", sxgbe_cmdline_opt); 2200__setup("sxgbeeth=", sxgbe_cmdline_opt);
@@ -2043,6 +2205,7 @@ __setup("sxgbeeth=", sxgbe_cmdline_opt);
2043MODULE_DESCRIPTION("SAMSUNG 10G/2.5G/1G Ethernet PLATFORM driver"); 2205MODULE_DESCRIPTION("SAMSUNG 10G/2.5G/1G Ethernet PLATFORM driver");
2044 2206
2045MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); 2207MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)");
2208MODULE_PARM_DESC(eee_timer, "EEE-LPI Default LS timer value");
2046 2209
2047MODULE_AUTHOR("Siva Reddy Kallam <siva.kallam@samsung.com>"); 2210MODULE_AUTHOR("Siva Reddy Kallam <siva.kallam@samsung.com>");
2048MODULE_AUTHOR("ByungHo An <bh74.an@samsung.com>"); 2211MODULE_AUTHOR("ByungHo An <bh74.an@samsung.com>");
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
index f5a9de710052..94c2cd73d4a9 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
@@ -145,6 +145,12 @@ static int sxgbe_platform_probe(struct platform_device *pdev)
145 } 145 }
146 } 146 }
147 147
148 priv->lpi_irq = irq_of_parse_and_map(node, chan);
149 if (priv->lpi_irq <= 0) {
150 dev_err(dev, "sxgbe lpi irq parsing failed\n");
151 goto err_rx_irq_unmap;
152 }
153
148 platform_set_drvdata(pdev, priv->dev); 154 platform_set_drvdata(pdev, priv->dev);
149 155
150 pr_debug("platform driver registration completed\n"); 156 pr_debug("platform driver registration completed\n");
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
index d1cd9ac1b062..85a7b3104a1a 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
@@ -25,6 +25,11 @@
25#define SXGBE_CORE_HASH_TABLE_REG5 0x0024 25#define SXGBE_CORE_HASH_TABLE_REG5 0x0024
26#define SXGBE_CORE_HASH_TABLE_REG6 0x0028 26#define SXGBE_CORE_HASH_TABLE_REG6 0x0028
27#define SXGBE_CORE_HASH_TABLE_REG7 0x002C 27#define SXGBE_CORE_HASH_TABLE_REG7 0x002C
28
29/* EEE-LPI Registers */
30#define SXGBE_CORE_LPI_CTRL_STATUS 0x00D0
31#define SXGBE_CORE_LPI_TIMER_CTRL 0x00D4
32
28/* VLAN Specific Registers */ 33/* VLAN Specific Registers */
29#define SXGBE_CORE_VLAN_TAG_REG 0x0050 34#define SXGBE_CORE_VLAN_TAG_REG 0x0050
30#define SXGBE_CORE_VLAN_HASHTAB_REG 0x0058 35#define SXGBE_CORE_VLAN_HASHTAB_REG 0x0058