aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2014-09-24 20:05:22 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-28 17:14:09 -0400
commit450b05c15f9c776996f9627c7b4f1d38b6e6f4a0 (patch)
tree8e447cdbf775bb00d40e69b09cf89e77f333e07a
parent7905288f093ad924004609bb89a7ce1597892726 (diff)
net: dsa: bcm_sf2: add support for controlling EEE
When EEE is enabled, negotiate this feature with the PHY and make sure that the capability checking, local EEE advertisement, link partner EEE advertisement and auto-negotiation resolution returned by phy_init_eee() is positive, and enable EEE at the switch level. While querying the current EEE settings, verify the low-power indication and indicate its status. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/bcm_sf2.c73
-rw-r--r--drivers/net/dsa/bcm_sf2.h3
-rw-r--r--drivers/net/dsa/bcm_sf2_regs.h3
3 files changed, 79 insertions, 0 deletions
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 634e44ee8d0d..b9625968daac 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -220,6 +220,19 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
220 core_writel(priv, reg, CORE_STS_OVERRIDE_IMP); 220 core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
221} 221}
222 222
223static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
224{
225 struct bcm_sf2_priv *priv = ds_to_priv(ds);
226 u32 reg;
227
228 reg = core_readl(priv, CORE_EEE_EN_CTRL);
229 if (enable)
230 reg |= 1 << port;
231 else
232 reg &= ~(1 << port);
233 core_writel(priv, reg, CORE_EEE_EN_CTRL);
234}
235
223static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, 236static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
224 struct phy_device *phy) 237 struct phy_device *phy)
225{ 238{
@@ -247,6 +260,10 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
247 260
248 bcm_sf2_imp_vlan_setup(ds, cpu_port); 261 bcm_sf2_imp_vlan_setup(ds, cpu_port);
249 262
263 /* If EEE was enabled, restore it */
264 if (priv->port_sts[port].eee.eee_enabled)
265 bcm_sf2_eee_enable_set(ds, port, true);
266
250 return 0; 267 return 0;
251} 268}
252 269
@@ -279,6 +296,60 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
279 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL); 296 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
280} 297}
281 298
299/* Returns 0 if EEE was not enabled, or 1 otherwise
300 */
301static int bcm_sf2_eee_init(struct dsa_switch *ds, int port,
302 struct phy_device *phy)
303{
304 struct bcm_sf2_priv *priv = ds_to_priv(ds);
305 struct ethtool_eee *p = &priv->port_sts[port].eee;
306 int ret;
307
308 p->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full);
309
310 ret = phy_init_eee(phy, 0);
311 if (ret)
312 return 0;
313
314 bcm_sf2_eee_enable_set(ds, port, true);
315
316 return 1;
317}
318
319static int bcm_sf2_sw_get_eee(struct dsa_switch *ds, int port,
320 struct ethtool_eee *e)
321{
322 struct bcm_sf2_priv *priv = ds_to_priv(ds);
323 struct ethtool_eee *p = &priv->port_sts[port].eee;
324 u32 reg;
325
326 reg = core_readl(priv, CORE_EEE_LPI_INDICATE);
327 e->eee_enabled = p->eee_enabled;
328 e->eee_active = !!(reg & (1 << port));
329
330 return 0;
331}
332
333static int bcm_sf2_sw_set_eee(struct dsa_switch *ds, int port,
334 struct phy_device *phydev,
335 struct ethtool_eee *e)
336{
337 struct bcm_sf2_priv *priv = ds_to_priv(ds);
338 struct ethtool_eee *p = &priv->port_sts[port].eee;
339
340 p->eee_enabled = e->eee_enabled;
341
342 if (!p->eee_enabled) {
343 bcm_sf2_eee_enable_set(ds, port, false);
344 } else {
345 p->eee_enabled = bcm_sf2_eee_init(ds, port, phydev);
346 if (!p->eee_enabled)
347 return -EOPNOTSUPP;
348 }
349
350 return 0;
351}
352
282static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id) 353static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
283{ 354{
284 struct bcm_sf2_priv *priv = dev_id; 355 struct bcm_sf2_priv *priv = dev_id;
@@ -792,6 +863,8 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
792 .set_wol = bcm_sf2_sw_set_wol, 863 .set_wol = bcm_sf2_sw_set_wol,
793 .port_enable = bcm_sf2_port_setup, 864 .port_enable = bcm_sf2_port_setup,
794 .port_disable = bcm_sf2_port_disable, 865 .port_disable = bcm_sf2_port_disable,
866 .get_eee = bcm_sf2_sw_get_eee,
867 .set_eee = bcm_sf2_sw_set_eee,
795}; 868};
796 869
797static int __init bcm_sf2_init(void) 870static int __init bcm_sf2_init(void)
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
index 8fd6c1451a84..ee9f650d5026 100644
--- a/drivers/net/dsa/bcm_sf2.h
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -18,6 +18,7 @@
18#include <linux/spinlock.h> 18#include <linux/spinlock.h>
19#include <linux/mutex.h> 19#include <linux/mutex.h>
20#include <linux/mii.h> 20#include <linux/mii.h>
21#include <linux/ethtool.h>
21 22
22#include <net/dsa.h> 23#include <net/dsa.h>
23 24
@@ -43,6 +44,8 @@ struct bcm_sf2_hw_params {
43 44
44struct bcm_sf2_port_status { 45struct bcm_sf2_port_status {
45 unsigned int link; 46 unsigned int link;
47
48 struct ethtool_eee eee;
46}; 49};
47 50
48struct bcm_sf2_priv { 51struct bcm_sf2_priv {
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
index c65f138c777f..1bb49cb699ab 100644
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -225,4 +225,7 @@
225#define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8)) 225#define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8))
226#define PORT_VLAN_CTRL_MASK 0x1ff 226#define PORT_VLAN_CTRL_MASK 0x1ff
227 227
228#define CORE_EEE_EN_CTRL 0x24800
229#define CORE_EEE_LPI_INDICATE 0x24810
230
228#endif /* __BCM_SF2_REGS_H */ 231#endif /* __BCM_SF2_REGS_H */