History

Merge branch 'dsa_eee'

Florian Fainelli says: ==================== net: dsa: EEE and other PM features This patch set allows DSA switch drivers to enable/disable/query EEE on a per-port level, as well as control precisely which switch ports are enable/disabled. ====================

David S. Miller committed 12 years ago

Commit fe2c5fb2 parents 155c6e1 450b05c5 files · +203 −18Browse files

Unified · Split

5 files
  1. drivers/net/dsa/bcm_sf2.c +120 −18
  2. drivers/net/dsa/bcm_sf2.h +3 −0
  3. drivers/net/dsa/bcm_sf2_regs.h +3 −0
  4. include/net/dsa.h +17 −0
  5. net/dsa/slave.c +60 −0
drivers/net/dsa/bcm_sf2.c+120−18
@@ -135,10 +135,29 @@ static char *bcm_sf2_sw_probe(struct device *host_dev, int sw_addr) · 134 unmodified lines
135 return "Broadcom Starfighter 2";135 return "Broadcom Starfighter 2";
136}136}
137 137
138static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)138static void bcm_sf2_imp_vlan_setup(struct dsa_switch *ds, int cpu_port)
139{139{
140 struct bcm_sf2_priv *priv = ds_to_priv(ds);140 struct bcm_sf2_priv *priv = ds_to_priv(ds);
141 unsigned int i;141 unsigned int i;
142 u32 reg;
143
144 /* Enable the IMP Port to be in the same VLAN as the other ports
145 * on a per-port basis such that we only have Port i and IMP in
146 * the same VLAN.
147 */
148 for (i = 0; i < priv->hw_params.num_ports; i++) {
149 if (!((1 << i) & ds->phys_port_mask))
150 continue;
151
152 reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
153 reg |= (1 << cpu_port);
154 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
155 }
156}
157
158static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
159{
160 struct bcm_sf2_priv *priv = ds_to_priv(ds);
142 u32 reg, val;161 u32 reg, val;
143 162
144 /* Enable the port memories */163 /* Enable the port memories */
@@ -199,24 +218,26 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) · 54 unmodified lines
199 reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);218 reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);
200 reg |= (MII_SW_OR | LINK_STS);219 reg |= (MII_SW_OR | LINK_STS);
201 core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);220 core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
221}
202 222
203 /* Enable the IMP Port to be in the same VLAN as the other ports223static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
204 * on a per-port basis such that we only have Port i and IMP in224{
205 * the same VLAN.225 struct bcm_sf2_priv *priv = ds_to_priv(ds);
206 */226 u32 reg;
207 for (i = 0; i < priv->hw_params.num_ports; i++) {
208 if (!((1 << i) & ds->phys_port_mask))
209 continue;
210 227
211 reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));228 reg = core_readl(priv, CORE_EEE_EN_CTRL);
212 reg |= (1 << port);229 if (enable)
213 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));230 reg |= 1 << port;
214 }231 else
232 reg &= ~(1 << port);
233 core_writel(priv, reg, CORE_EEE_EN_CTRL);
215}234}
216 235
217static void bcm_sf2_port_setup(struct dsa_switch *ds, int port)236static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
237 struct phy_device *phy)
218{238{
219 struct bcm_sf2_priv *priv = ds_to_priv(ds);239 struct bcm_sf2_priv *priv = ds_to_priv(ds);
240 s8 cpu_port = ds->dst[ds->index].cpu_port;
220 u32 reg;241 u32 reg;
221 242
222 /* Clear the memory power down */243 /* Clear the memory power down */
@@ -236,9 +257,18 @@ static void bcm_sf2_port_setup(struct dsa_switch *ds, int port) · 13 unmodified lines
236 reg &= ~PORT_VLAN_CTRL_MASK;257 reg &= ~PORT_VLAN_CTRL_MASK;
237 reg |= (1 << port);258 reg |= (1 << port);
238 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port));259 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port));
260
261 bcm_sf2_imp_vlan_setup(ds, cpu_port);
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
267 return 0;
239}268}
240 269
241static void bcm_sf2_port_disable(struct dsa_switch *ds, int port)270static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
271 struct phy_device *phy)
242{272{
243 struct bcm_sf2_priv *priv = ds_to_priv(ds);273 struct bcm_sf2_priv *priv = ds_to_priv(ds);
244 u32 off, reg;274 u32 off, reg;
@@ -246,6 +276,11 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port) · 1 unmodified line
246 if (priv->wol_ports_mask & (1 << port))276 if (priv->wol_ports_mask & (1 << port))
247 return;277 return;
248 278
279 if (port == 7) {
280 intrl2_1_mask_set(priv, P_IRQ_MASK(P7_IRQ_OFF));
281 intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR);
282 }
283
249 if (dsa_is_cpu_port(ds, port))284 if (dsa_is_cpu_port(ds, port))
250 off = CORE_IMP_CTL;285 off = CORE_IMP_CTL;
251 else286 else
@@ -261,6 +296,60 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port) · 9 unmodified lines
261 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);296 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
262}297}
263 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
264static 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)
265{354{
266 struct bcm_sf2_priv *priv = dev_id;355 struct bcm_sf2_priv *priv = dev_id;
@@ -363,11 +452,11 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) · 96 unmodified lines
363 for (port = 0; port < priv->hw_params.num_ports; port++) {452 for (port = 0; port < priv->hw_params.num_ports; port++) {
364 /* IMP port receives special treatment */453 /* IMP port receives special treatment */
365 if ((1 << port) & ds->phys_port_mask)454 if ((1 << port) & ds->phys_port_mask)
366 bcm_sf2_port_setup(ds, port);455 bcm_sf2_port_setup(ds, port, NULL);
367 else if (dsa_is_cpu_port(ds, port))456 else if (dsa_is_cpu_port(ds, port))
368 bcm_sf2_imp_setup(ds, port);457 bcm_sf2_imp_setup(ds, port);
369 else458 else
370 bcm_sf2_port_disable(ds, port);459 bcm_sf2_port_disable(ds, port, NULL);
371 }460 }
372 461
373 /* Include the pseudo-PHY address and the broadcast PHY address to462 /* Include the pseudo-PHY address and the broadcast PHY address to
@@ -506,6 +595,15 @@ static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port, · 132 unmodified lines
506 port_mode = EXT_REVMII;595 port_mode = EXT_REVMII;
507 break;596 break;
508 default:597 default:
598 /* All other PHYs: internal and MoCA */
599 goto force_link;
600 }
601
602 /* If the link is down, just disable the interface to conserve power */
603 if (!phydev->link) {
604 reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
605 reg &= ~RGMII_MODE_EN;
606 reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
509 goto force_link;607 goto force_link;
510 }608 }
511 609
@@ -629,7 +727,7 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds) · 117 unmodified lines
629 for (port = 0; port < DSA_MAX_PORTS; port++) {727 for (port = 0; port < DSA_MAX_PORTS; port++) {
630 if ((1 << port) & ds->phys_port_mask ||728 if ((1 << port) & ds->phys_port_mask ||
631 dsa_is_cpu_port(ds, port))729 dsa_is_cpu_port(ds, port))
632 bcm_sf2_port_disable(ds, port);730 bcm_sf2_port_disable(ds, port, NULL);
633 }731 }
634 732
635 return 0;733 return 0;
@@ -685,7 +783,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) · 49 unmodified lines
685 783
686 for (port = 0; port < DSA_MAX_PORTS; port++) {784 for (port = 0; port < DSA_MAX_PORTS; port++) {
687 if ((1 << port) & ds->phys_port_mask)785 if ((1 << port) & ds->phys_port_mask)
688 bcm_sf2_port_setup(ds, port);786 bcm_sf2_port_setup(ds, port, NULL);
689 else if (dsa_is_cpu_port(ds, port))787 else if (dsa_is_cpu_port(ds, port))
690 bcm_sf2_imp_setup(ds, port);788 bcm_sf2_imp_setup(ds, port);
691 }789 }
@@ -763,6 +861,10 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = { · 71 unmodified lines
763 .resume = bcm_sf2_sw_resume,861 .resume = bcm_sf2_sw_resume,
764 .get_wol = bcm_sf2_sw_get_wol,862 .get_wol = bcm_sf2_sw_get_wol,
765 .set_wol = bcm_sf2_sw_set_wol,863 .set_wol = bcm_sf2_sw_set_wol,
864 .port_enable = bcm_sf2_port_setup,
865 .port_disable = bcm_sf2_port_disable,
866 .get_eee = bcm_sf2_sw_get_eee,
867 .set_eee = bcm_sf2_sw_set_eee,
766};868};
767 869
768static int __init bcm_sf2_init(void)870static int __init bcm_sf2_init(void)
drivers/net/dsa/bcm_sf2.h+3−0
@@ -18,6 +18,7 @@ · 17 unmodified lines
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 { · 19 unmodified lines
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 {
drivers/net/dsa/bcm_sf2_regs.h+3−0
@@ -225,4 +225,7 @@ · 224 unmodified lines
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 0x1ff226#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 */
include/net/dsa.h+17−0
@@ -224,6 +224,23 @@ struct dsa_switch_driver { · 223 unmodified lines
224 */224 */
225 int (*suspend)(struct dsa_switch *ds);225 int (*suspend)(struct dsa_switch *ds);
226 int (*resume)(struct dsa_switch *ds);226 int (*resume)(struct dsa_switch *ds);
227
228 /*
229 * Port enable/disable
230 */
231 int (*port_enable)(struct dsa_switch *ds, int port,
232 struct phy_device *phy);
233 void (*port_disable)(struct dsa_switch *ds, int port,
234 struct phy_device *phy);
235
236 /*
237 * EEE setttings
238 */
239 int (*set_eee)(struct dsa_switch *ds, int port,
240 struct phy_device *phydev,
241 struct ethtool_eee *e);
242 int (*get_eee)(struct dsa_switch *ds, int port,
243 struct ethtool_eee *e);
227};244};
228 245
229void register_switch_driver(struct dsa_switch_driver *type);246void register_switch_driver(struct dsa_switch_driver *type);
net/dsa/slave.c+60−0
@@ -62,6 +62,7 @@ static int dsa_slave_open(struct net_device *dev) · 61 unmodified lines
62{62{
63 struct dsa_slave_priv *p = netdev_priv(dev);63 struct dsa_slave_priv *p = netdev_priv(dev);
64 struct net_device *master = p->parent->dst->master_netdev;64 struct net_device *master = p->parent->dst->master_netdev;
65 struct dsa_switch *ds = p->parent;
65 int err;66 int err;
66 67
67 if (!(master->flags & IFF_UP))68 if (!(master->flags & IFF_UP))
@@ -84,8 +85,20 @@ static int dsa_slave_open(struct net_device *dev) · 16 unmodified lines
84 goto clear_allmulti;85 goto clear_allmulti;
85 }86 }
86 87
88 if (ds->drv->port_enable) {
89 err = ds->drv->port_enable(ds, p->port, p->phy);
90 if (err)
91 goto clear_promisc;
92 }
93
94 if (p->phy)
95 phy_start(p->phy);
96
87 return 0;97 return 0;
88 98
99clear_promisc:
100 if (dev->flags & IFF_PROMISC)
101 dev_set_promiscuity(master, 0);
89clear_allmulti:102clear_allmulti:
90 if (dev->flags & IFF_ALLMULTI)103 if (dev->flags & IFF_ALLMULTI)
91 dev_set_allmulti(master, -1);104 dev_set_allmulti(master, -1);
@@ -100,6 +113,10 @@ static int dsa_slave_close(struct net_device *dev) · 8 unmodified lines
100{113{
101 struct dsa_slave_priv *p = netdev_priv(dev);114 struct dsa_slave_priv *p = netdev_priv(dev);
102 struct net_device *master = p->parent->dst->master_netdev;115 struct net_device *master = p->parent->dst->master_netdev;
116 struct dsa_switch *ds = p->parent;
117
118 if (p->phy)
119 phy_stop(p->phy);
103 120
104 dev_mc_unsync(master, dev);121 dev_mc_unsync(master, dev);
105 dev_uc_unsync(master, dev);122 dev_uc_unsync(master, dev);
@@ -111,6 +128,9 @@ static int dsa_slave_close(struct net_device *dev) · 5 unmodified lines
111 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))128 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
112 dev_uc_del(master, dev->dev_addr);129 dev_uc_del(master, dev->dev_addr);
113 130
131 if (ds->drv->port_disable)
132 ds->drv->port_disable(ds, p->port, p->phy);
133
114 return 0;134 return 0;
115}135}
116 136
@@ -322,6 +342,44 @@ static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) · 205 unmodified lines
322 return ret;342 return ret;
323}343}
324 344
345static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
346{
347 struct dsa_slave_priv *p = netdev_priv(dev);
348 struct dsa_switch *ds = p->parent;
349 int ret;
350
351 if (!ds->drv->set_eee)
352 return -EOPNOTSUPP;
353
354 ret = ds->drv->set_eee(ds, p->port, p->phy, e);
355 if (ret)
356 return ret;
357
358 if (p->phy)
359 ret = phy_ethtool_set_eee(p->phy, e);
360
361 return ret;
362}
363
364static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
365{
366 struct dsa_slave_priv *p = netdev_priv(dev);
367 struct dsa_switch *ds = p->parent;
368 int ret;
369
370 if (!ds->drv->get_eee)
371 return -EOPNOTSUPP;
372
373 ret = ds->drv->get_eee(ds, p->port, e);
374 if (ret)
375 return ret;
376
377 if (p->phy)
378 ret = phy_ethtool_get_eee(p->phy, e);
379
380 return ret;
381}
382
325static const struct ethtool_ops dsa_slave_ethtool_ops = {383static const struct ethtool_ops dsa_slave_ethtool_ops = {
326 .get_settings = dsa_slave_get_settings,384 .get_settings = dsa_slave_get_settings,
327 .set_settings = dsa_slave_set_settings,385 .set_settings = dsa_slave_set_settings,
@@ -333,6 +391,8 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { · 5 unmodified lines
333 .get_sset_count = dsa_slave_get_sset_count,391 .get_sset_count = dsa_slave_get_sset_count,
334 .set_wol = dsa_slave_set_wol,392 .set_wol = dsa_slave_set_wol,
335 .get_wol = dsa_slave_get_wol,393 .get_wol = dsa_slave_get_wol,
394 .set_eee = dsa_slave_set_eee,
395 .get_eee = dsa_slave_get_eee,
336};396};
337 397
338static const struct net_device_ops dsa_slave_netdev_ops = {398static const struct net_device_ops dsa_slave_netdev_ops = {