aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2014-08-27 20:04:51 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-28 01:59:40 -0400
commit0d8bcdd383b8865e752a7e8edb4712c2e3902052 (patch)
treeb4a91fb89f31582da17c727278039c4df4c0f049 /net/dsa
parentbd47497a0171b96264927e3377254db13b9fe3e3 (diff)
net: dsa: allow for more complex PHY setups
Modify the DSA slave interface to be bound to an arbitray PHY, not just the ones that are available as child PHY devices of the switch MDIO bus. This allows us for instance to have external PHYs connected to a separate MDIO bus, but yet also connected to a given switch port. Under certain configurations, the physical port mask might not be a 1:1 mapping to the MII PHYs mask. This is the case, if e.g: Port 1 of the switch is used and connects to a PHY at a MDIO address different than 1. Introduce a phys_mii_mask variable which allows driver to implement and divert their own MDIO read/writes operations for a subset of the MDIO PHY addresses. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/dsa.c5
-rw-r--r--net/dsa/dsa_priv.h4
-rw-r--r--net/dsa/slave.c76
3 files changed, 82 insertions, 3 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 6a5bae673037..4dc2a16b72cf 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -144,6 +144,11 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
144 goto out; 144 goto out;
145 } 145 }
146 146
147 /* Make the built-in MII bus mask match the number of ports,
148 * switch drivers can override this later
149 */
150 ds->phys_mii_mask = ds->phys_port_mask;
151
147 /* 152 /*
148 * If the CPU connects to this switch, set the switch tree 153 * If the CPU connects to this switch, set the switch tree
149 * tagging protocol to the preferred tagging format of this 154 * tagging protocol to the preferred tagging format of this
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 218d75d16f6f..d20364ac1574 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -33,6 +33,10 @@ struct dsa_slave_priv {
33 * to this port. 33 * to this port.
34 */ 34 */
35 struct phy_device *phy; 35 struct phy_device *phy;
36 phy_interface_t phy_interface;
37 int old_link;
38 int old_pause;
39 int old_duplex;
36}; 40};
37 41
38/* dsa.c */ 42/* dsa.c */
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 5688c34253e5..03d2894a0f8a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -12,6 +12,8 @@
12#include <linux/netdevice.h> 12#include <linux/netdevice.h>
13#include <linux/etherdevice.h> 13#include <linux/etherdevice.h>
14#include <linux/phy.h> 14#include <linux/phy.h>
15#include <linux/of_net.h>
16#include <linux/of_mdio.h>
15#include "dsa_priv.h" 17#include "dsa_priv.h"
16 18
17/* slave mii_bus handling ***************************************************/ 19/* slave mii_bus handling ***************************************************/
@@ -19,7 +21,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
19{ 21{
20 struct dsa_switch *ds = bus->priv; 22 struct dsa_switch *ds = bus->priv;
21 23
22 if (ds->phys_port_mask & (1 << addr)) 24 if (ds->phys_mii_mask & (1 << addr))
23 return ds->drv->phy_read(ds, addr, reg); 25 return ds->drv->phy_read(ds, addr, reg);
24 26
25 return 0xffff; 27 return 0xffff;
@@ -29,7 +31,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
29{ 31{
30 struct dsa_switch *ds = bus->priv; 32 struct dsa_switch *ds = bus->priv;
31 33
32 if (ds->phys_port_mask & (1 << addr)) 34 if (ds->phys_mii_mask & (1 << addr))
33 return ds->drv->phy_write(ds, addr, reg, val); 35 return ds->drv->phy_write(ds, addr, reg, val);
34 36
35 return 0; 37 return 0;
@@ -312,7 +314,70 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
312 .ndo_do_ioctl = dsa_slave_ioctl, 314 .ndo_do_ioctl = dsa_slave_ioctl,
313}; 315};
314 316
317static void dsa_slave_adjust_link(struct net_device *dev)
318{
319 struct dsa_slave_priv *p = netdev_priv(dev);
320 unsigned int status_changed = 0;
321
322 if (p->old_link != p->phy->link) {
323 status_changed = 1;
324 p->old_link = p->phy->link;
325 }
326
327 if (p->old_duplex != p->phy->duplex) {
328 status_changed = 1;
329 p->old_duplex = p->phy->duplex;
330 }
331
332 if (p->old_pause != p->phy->pause) {
333 status_changed = 1;
334 p->old_pause = p->phy->pause;
335 }
336
337 if (status_changed)
338 phy_print_status(p->phy);
339}
340
315/* slave device setup *******************************************************/ 341/* slave device setup *******************************************************/
342static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
343 struct net_device *slave_dev)
344{
345 struct dsa_switch *ds = p->parent;
346 struct dsa_chip_data *cd = ds->pd;
347 struct device_node *phy_dn, *port_dn;
348 int ret;
349
350 port_dn = cd->port_dn[p->port];
351 p->phy_interface = of_get_phy_mode(port_dn);
352
353 phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
354 if (of_phy_is_fixed_link(port_dn)) {
355 /* In the case of a fixed PHY, the DT node associated
356 * to the fixed PHY is the Port DT node
357 */
358 ret = of_phy_register_fixed_link(port_dn);
359 if (ret) {
360 pr_err("failed to register fixed PHY\n");
361 return;
362 }
363 phy_dn = port_dn;
364 }
365
366 if (phy_dn)
367 p->phy = of_phy_connect(slave_dev, phy_dn,
368 dsa_slave_adjust_link, 0,
369 p->phy_interface);
370
371 /* We could not connect to a designated PHY, so use the switch internal
372 * MDIO bus instead
373 */
374 if (!p->phy)
375 p->phy = ds->slave_mii_bus->phy_map[p->port];
376 else
377 pr_info("attached PHY at address %d [%s]\n",
378 p->phy->addr, p->phy->drv->name);
379}
380
316struct net_device * 381struct net_device *
317dsa_slave_create(struct dsa_switch *ds, struct device *parent, 382dsa_slave_create(struct dsa_switch *ds, struct device *parent,
318 int port, char *name) 383 int port, char *name)
@@ -361,7 +426,12 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
361 p->dev = slave_dev; 426 p->dev = slave_dev;
362 p->parent = ds; 427 p->parent = ds;
363 p->port = port; 428 p->port = port;
364 p->phy = ds->slave_mii_bus->phy_map[port]; 429
430 p->old_pause = -1;
431 p->old_link = -1;
432 p->old_duplex = -1;
433
434 dsa_slave_phy_setup(p, slave_dev);
365 435
366 ret = register_netdev(slave_dev); 436 ret = register_netdev(slave_dev);
367 if (ret) { 437 if (ret) {