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
135135 return "Broadcom Starfighter 2";
136136 }
137137
138−static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
138+static void bcm_sf2_imp_vlan_setup(struct dsa_switch *ds, int cpu_port)
139139 {
140140 struct bcm_sf2_priv *priv = ds_to_priv(ds);
141141 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+
158+static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
159+{
160+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
142161 u32 reg, val;
143162
144163 /* Enable the port memories */
@@ -199,24 +218,26 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) · 54 unmodified lines
199218 reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);
200219 reg |= (MII_SW_OR | LINK_STS);
201220 core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
221+}
202222
203− /* Enable the IMP Port to be in the same VLAN as the other ports
204− * on a per-port basis such that we only have Port i and IMP in
205− * the same VLAN.
206− */
207− for (i = 0; i < priv->hw_params.num_ports; i++) {
208− if (!((1 << i) & ds->phys_port_mask))
209− continue;
223+static 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;
210227
211− reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
212− reg |= (1 << port);
213− core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
214− }
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);
215234 }
216235
217−static void bcm_sf2_port_setup(struct dsa_switch *ds, int port)
236+static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
237+ struct phy_device *phy)
218238 {
219239 struct bcm_sf2_priv *priv = ds_to_priv(ds);
240+ s8 cpu_port = ds->dst[ds->index].cpu_port;
220241 u32 reg;
221242
222243 /* Clear the memory power down */
@@ -236,9 +257,18 @@ static void bcm_sf2_port_setup(struct dsa_switch *ds, int port) · 13 unmodified lines
236257 reg &= ~PORT_VLAN_CTRL_MASK;
237258 reg |= (1 << port);
238259 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;
239268 }
240269
241−static void bcm_sf2_port_disable(struct dsa_switch *ds, int port)
270+static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
271+ struct phy_device *phy)
242272 {
243273 struct bcm_sf2_priv *priv = ds_to_priv(ds);
244274 u32 off, reg;
@@ -246,6 +276,11 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port) · 1 unmodified line
246276 if (priv->wol_ports_mask & (1 << port))
247277 return;
248278
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+
249284 if (dsa_is_cpu_port(ds, port))
250285 off = CORE_IMP_CTL;
251286 else
@@ -261,6 +296,60 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port) · 9 unmodified lines
261296 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
262297 }
263298
299+/* Returns 0 if EEE was not enabled, or 1 otherwise
300+ */
301+static 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+
319+static 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+
333+static 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+
264353 static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
265354 {
266355 struct bcm_sf2_priv *priv = dev_id;
@@ -363,11 +452,11 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) · 96 unmodified lines
363452 for (port = 0; port < priv->hw_params.num_ports; port++) {
364453 /* IMP port receives special treatment */
365454 if ((1 << port) & ds->phys_port_mask)
366− bcm_sf2_port_setup(ds, port);
455+ bcm_sf2_port_setup(ds, port, NULL);
367456 else if (dsa_is_cpu_port(ds, port))
368457 bcm_sf2_imp_setup(ds, port);
369458 else
370− bcm_sf2_port_disable(ds, port);
459+ bcm_sf2_port_disable(ds, port, NULL);
371460 }
372461
373462 /* 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
506595 port_mode = EXT_REVMII;
507596 break;
508597 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));
509607 goto force_link;
510608 }
511609
@@ -629,7 +727,7 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds) · 117 unmodified lines
629727 for (port = 0; port < DSA_MAX_PORTS; port++) {
630728 if ((1 << port) & ds->phys_port_mask ||
631729 dsa_is_cpu_port(ds, port))
632− bcm_sf2_port_disable(ds, port);
730+ bcm_sf2_port_disable(ds, port, NULL);
633731 }
634732
635733 return 0;
@@ -685,7 +783,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) · 49 unmodified lines
685783
686784 for (port = 0; port < DSA_MAX_PORTS; port++) {
687785 if ((1 << port) & ds->phys_port_mask)
688− bcm_sf2_port_setup(ds, port);
786+ bcm_sf2_port_setup(ds, port, NULL);
689787 else if (dsa_is_cpu_port(ds, port))
690788 bcm_sf2_imp_setup(ds, port);
691789 }
@@ -763,6 +861,10 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = { · 71 unmodified lines
763861 .resume = bcm_sf2_sw_resume,
764862 .get_wol = bcm_sf2_sw_get_wol,
765863 .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,
766868 };
767869
768870 static int __init bcm_sf2_init(void)
drivers/net/dsa/bcm_sf2.h+3−0
@@ -18,6 +18,7 @@ · 17 unmodified lines
1818 #include <linux/spinlock.h>
1919 #include <linux/mutex.h>
2020 #include <linux/mii.h>
21+#include <linux/ethtool.h>
2122
2223 #include <net/dsa.h>
2324
@@ -43,6 +44,8 @@ struct bcm_sf2_hw_params { · 19 unmodified lines
4344
4445 struct bcm_sf2_port_status {
4546 unsigned int link;
47+
48+ struct ethtool_eee eee;
4649 };
4750
4851 struct bcm_sf2_priv {
drivers/net/dsa/bcm_sf2_regs.h+3−0
@@ -225,4 +225,7 @@ · 224 unmodified lines
225225 #define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8))
226226 #define PORT_VLAN_CTRL_MASK 0x1ff
227227
228+#define CORE_EEE_EN_CTRL 0x24800
229+#define CORE_EEE_LPI_INDICATE 0x24810
230+
228231 #endif /* __BCM_SF2_REGS_H */
include/net/dsa.h+17−0
@@ -224,6 +224,23 @@ struct dsa_switch_driver { · 223 unmodified lines
224224 */
225225 int (*suspend)(struct dsa_switch *ds);
226226 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);
227244 };
228245
229246 void 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
6262 {
6363 struct dsa_slave_priv *p = netdev_priv(dev);
6464 struct net_device *master = p->parent->dst->master_netdev;
65+ struct dsa_switch *ds = p->parent;
6566 int err;
6667
6768 if (!(master->flags & IFF_UP))
@@ -84,8 +85,20 @@ static int dsa_slave_open(struct net_device *dev) · 16 unmodified lines
8485 goto clear_allmulti;
8586 }
8687
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+
8797 return 0;
8898
99+clear_promisc:
100+ if (dev->flags & IFF_PROMISC)
101+ dev_set_promiscuity(master, 0);
89102 clear_allmulti:
90103 if (dev->flags & IFF_ALLMULTI)
91104 dev_set_allmulti(master, -1);
@@ -100,6 +113,10 @@ static int dsa_slave_close(struct net_device *dev) · 8 unmodified lines
100113 {
101114 struct dsa_slave_priv *p = netdev_priv(dev);
102115 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);
103120
104121 dev_mc_unsync(master, dev);
105122 dev_uc_unsync(master, dev);
@@ -111,6 +128,9 @@ static int dsa_slave_close(struct net_device *dev) · 5 unmodified lines
111128 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
112129 dev_uc_del(master, dev->dev_addr);
113130
131+ if (ds->drv->port_disable)
132+ ds->drv->port_disable(ds, p->port, p->phy);
133+
114134 return 0;
115135 }
116136
@@ -322,6 +342,44 @@ static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) · 205 unmodified lines
322342 return ret;
323343 }
324344
345+static 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+
364+static 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+
325383 static const struct ethtool_ops dsa_slave_ethtool_ops = {
326384 .get_settings = dsa_slave_get_settings,
327385 .set_settings = dsa_slave_set_settings,
@@ -333,6 +391,8 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { · 5 unmodified lines
333391 .get_sset_count = dsa_slave_get_sset_count,
334392 .set_wol = dsa_slave_set_wol,
335393 .get_wol = dsa_slave_get_wol,
394+ .set_eee = dsa_slave_set_eee,
395+ .get_eee = dsa_slave_get_eee,
336396 };
337397
338398 static const struct net_device_ops dsa_slave_netdev_ops = {