diff options
author | Girish K S <ks.giri@samsung.com> | 2014-03-25 15:10:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-26 16:49:31 -0400 |
commit | acc18c147b2281ff85f93862eb8c768df1bfb7df (patch) | |
tree | 6af088d7b1f44301d8e865074d0c99c622e04e85 | |
parent | 1edb9ca69e8a7988900fc0283e10550b5592164d (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.h | 53 | ||||
-rw-r--r-- | drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c | 86 | ||||
-rw-r--r-- | drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c | 47 | ||||
-rw-r--r-- | drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 165 | ||||
-rw-r--r-- | drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h | 5 |
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 | |||
121 | enum dma_irq_status { | 148 | enum 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 | ||
304 | const struct sxgbe_core_ops *sxgbe_get_core_ops(void); | 345 | const 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 | ||
460 | const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void); | 510 | const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void); |
461 | 511 | ||
512 | void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv); | ||
513 | bool 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 | ||
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 | |||
51 | /* Handle extra events on specific interrupts hw dependent */ | 71 | /* Handle extra events on specific interrupts hw dependent */ |
52 | static int sxgbe_core_host_irq_status(void __iomem *ioaddr, | 72 | static 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 | ||
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 | |||
141 | const struct sxgbe_core_ops core_ops = { | 221 | const 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 | ||
155 | const struct sxgbe_core_ops *sxgbe_get_core_ops(void) | 239 | const 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 | ||
34 | static const struct sxgbe_stats sxgbe_gstrings_stats[] = { | 34 | 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), | ||
35 | }; | 40 | }; |
36 | #define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats) | 41 | #define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats) |
37 | 42 | ||
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 | |||
38 | static const struct ethtool_ops sxgbe_ethtool_ops = { | 83 | static const struct ethtool_ops sxgbe_ethtool_ops = { |
84 | .get_eee = sxgbe_get_eee, | ||
85 | .set_eee = sxgbe_set_eee, | ||
39 | }; | 86 | }; |
40 | 87 | ||
41 | void sxgbe_set_ethtool_ops(struct net_device *netdev) | 88 | void 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 | ||
57 | static int debug = -1; | 57 | static int debug = -1; |
58 | static int eee_timer = SXGBE_DEFAULT_LPI_TIMER; | ||
59 | |||
60 | module_param(eee_timer, int, S_IRUGO | S_IWUSR); | ||
58 | 61 | ||
59 | module_param(debug, int, S_IRUGO | S_IWUSR); | 62 | module_param(debug, int, S_IRUGO | S_IWUSR); |
60 | static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | | 63 | static 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 | */ | ||
80 | static void sxgbe_verify_args(void) | ||
81 | { | ||
82 | if (unlikely(eee_timer < 0)) | ||
83 | eee_timer = SXGBE_DEFAULT_LPI_TIMER; | ||
84 | } | ||
85 | |||
86 | static 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 | |||
93 | void 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 | */ | ||
108 | static 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 | */ | ||
125 | bool 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 | |||
154 | static 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 | */ |
679 | static void sxgbe_tx_all_clean(struct sxgbe_priv_data *priv) | 776 | static 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 | */ |
1381 | static irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id) | 1507 | static 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 |
2033 | static int __init sxgbe_cmdline_opt(char *str) | 2181 | static 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 | |||
2195 | err: | ||
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); | |||
2043 | MODULE_DESCRIPTION("SAMSUNG 10G/2.5G/1G Ethernet PLATFORM driver"); | 2205 | MODULE_DESCRIPTION("SAMSUNG 10G/2.5G/1G Ethernet PLATFORM driver"); |
2044 | 2206 | ||
2045 | MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); | 2207 | MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); |
2208 | MODULE_PARM_DESC(eee_timer, "EEE-LPI Default LS timer value"); | ||
2046 | 2209 | ||
2047 | MODULE_AUTHOR("Siva Reddy Kallam <siva.kallam@samsung.com>"); | 2210 | MODULE_AUTHOR("Siva Reddy Kallam <siva.kallam@samsung.com>"); |
2048 | MODULE_AUTHOR("ByungHo An <bh74.an@samsung.com>"); | 2211 | MODULE_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 |