Commit 169fbdc6 authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-new-binding'

Andrew Lunn says:

====================
New DSA bind, switches as devices

The interesting patches here are the last three. They implement a new
binding for DSA, which removes a few limitations of the current DSA
binding. In particular, it allows switches to be true Linux devices.
These devices can be on any type of bus, unlike the old DSA binding
which assumes MDIO. See the commit log for more details. The second to
last patch modifies an existing boards device tree to use the new
binding, giving a good example of how switches can be true MDIO
devices. The last patch documents the new binding.

Thanks go to Florian and Vivien for reviewing, testing and bug fixing
these patches.
Tested-by: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Tested-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>

Since V1:

* Add lots of reviewed-by's
* Fix rtable comment
* dsa2: Clear cpu port mask in dsa_cpu_port_unapply()
* dsa2: Only set dsa_port_mask when port successfully configured
* dsa: clear {dsa|cpu}_port_mask on destroy

Since RFC:

* Split the mv88e6xxx MDIO refactor into a rename patch and a refactor
  patch.
* Extend commit message with comment about wrong of_node_put()
* Fix destroy of cpu and dsa ports.
* Rename _DSA_TAG_LAST to DSA_TAG_LAST and add a comment.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 76f21b99 8c5ad1d6
Marvell Distributed Switch Architecture Device Tree Bindings
------------------------------------------------------------
Distributed Switch Architecture Device Tree Bindings
----------------------------------------------------
Two bindings exist, one of which has been deprecated due to
limitations.
Current Binding
---------------
Switches are true Linux devices and can be probes by any means. Once
probed, they register to the DSA framework, passing a node
pointer. This node is expected to fulfil the following binding, and
may contain additional properties as required by the device it is
embedded within.
Required properties:
- ports : A container for child nodes representing switch ports.
Optional properties:
- dsa,member : A two element list indicates which DSA cluster, and position
within the cluster a switch takes. <0 0> is cluster 0,
switch 0. <0 1> is cluster 0, switch 1. <1 0> is cluster 1,
switch 0. A switch not part of any cluster (single device
hanging off a CPU port) must not specify this property
The ports container has the following properties
Required properties:
- #address-cells : Must be 1
- #size-cells : Must be 0
Each port children node must have the following mandatory properties:
- reg : Describes the port address in the switch
- label : Describes the label associated with this port, which
will become the netdev name. Special labels are
"cpu" to indicate a CPU port and "dsa" to
indicate an uplink/downlink port between switches in
the cluster.
A port labelled "dsa" has the following mandatory property:
- link : Should be a list of phandles to other switch's DSA
port. This port is used as the outgoing port
towards the phandle ports. The full routing
information must be given, not just the one hop
routes to neighbouring switches.
A port labelled "cpu" has the following mandatory property:
- ethernet : Should be a phandle to a valid Ethernet device node.
This host device is what the switch port is
connected to.
Port child nodes may also contain the following optional standardised
properties, described in binding documents:
- phy-handle : Phandle to a PHY on an MDIO bus. See
Documentation/devicetree/bindings/net/ethernet.txt
for details.
- phy-mode : See
Documentation/devicetree/bindings/net/ethernet.txt
for details.
- fixed-link : Fixed-link subnode describing a link to a non-MDIO
managed entity. See
Documentation/devicetree/bindings/net/fixed-link.txt
for details.
Example
The following example shows three switches on three MDIO busses,
linked into one DSA cluster.
&mdio1 {
#address-cells = <1>;
#size-cells = <0>;
switch0: switch0@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan0";
};
port@1 {
reg = <1>;
label = "lan1";
};
port@2 {
reg = <2>;
label = "lan2";
};
switch0port5: port@5 {
reg = <5>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port6
&switch2port9>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&fec1>;
fixed-link {
speed = <100>;
full-duplex;
};
};
};
};
};
&mdio2 {
#address-cells = <1>;
#size-cells = <0>;
switch1: switch1@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan3";
phy-handle = <&switch1phy0>;
};
port@1 {
reg = <1>;
label = "lan4";
phy-handle = <&switch1phy1>;
};
port@2 {
reg = <2>;
label = "lan5";
phy-handle = <&switch1phy2>;
};
switch1port5: port@5 {
reg = <5>;
label = "dsa";
link = <&switch2port9>;
phy-mode = "rgmii-txid";
fixed-link {
speed = <1000>;
full-duplex;
};
};
switch1port6: port@6 {
reg = <6>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
switch1phy0: switch1phy0@0 {
reg = <0>;
};
switch1phy1: switch1phy0@1 {
reg = <1>;
};
switch1phy2: switch1phy0@2 {
reg = <2>;
};
};
};
};
&mdio4 {
#address-cells = <1>;
#size-cells = <0>;
switch2: switch2@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 2>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan6";
};
port@1 {
reg = <1>;
label = "lan7";
};
port@2 {
reg = <2>;
label = "lan8";
};
port@3 {
reg = <3>;
label = "optical3";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 2
GPIO_ACTIVE_HIGH>;
};
};
port@4 {
reg = <4>;
label = "optical4";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 3
GPIO_ACTIVE_HIGH>;
};
};
switch2port9: port@9 {
reg = <9>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port5
&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};
Deprecated Binding
------------------
The deprecated binding makes use of a platform device to represent the
switches. The switches themselves are not Linux devices, and make use
of an MDIO bus for management.
Required properties:
- compatible : Should be "marvell,dsa"
......
......@@ -85,187 +85,199 @@ mdio_mux_1: mdio@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
switch0: switch0@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan0";
};
port@1 {
reg = <1>;
label = "lan1";
};
port@2 {
reg = <2>;
label = "lan2";
};
switch0port5: port@5 {
reg = <5>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port6
&switch2port9>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&fec1>;
fixed-link {
speed = <100>;
full-duplex;
};
};
};
};
};
mdio_mux_2: mdio@2 {
reg = <2>;
#address-cells = <1>;
#size-cells = <0>;
};
mdio_mux_4: mdio@4 {
reg = <4>;
#address-cells = <1>;
#size-cells = <0>;
};
mdio_mux_8: mdio@8 {
reg = <8>;
#address-cells = <1>;
#size-cells = <0>;
};
};
dsa {
compatible = "marvell,dsa";
#address-cells = <2>;
#size-cells = <0>;
dsa,ethernet = <&fec1>;
dsa,mii-bus = <&mdio_mux_1>;
/* 6352 - Primary - 7 ports */
switch0: switch@0-0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x00 0>;
eeprom-length = <512>;
port@0 {
switch1: switch1@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
label = "lan0";
};
port@1 {
reg = <1>;
label = "lan1";
};
port@2 {
reg = <2>;
label = "lan2";
};
switch0port5: port@5 {
reg = <5>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port6
&switch2port9>;
fixed-link {
speed = <1000>;
full-duplex;
dsa,member = <0 1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan3";
phy-handle = <&switch1phy0>;
};
port@1 {
reg = <1>;
label = "lan4";
phy-handle = <&switch1phy1>;
};
port@2 {
reg = <2>;
label = "lan5";
phy-handle = <&switch1phy2>;
};
switch1port5: port@5 {
reg = <5>;
label = "dsa";
link = <&switch2port9>;
phy-mode = "rgmii-txid";
fixed-link {
speed = <1000>;
full-duplex;
};
};
switch1port6: port@6 {
reg = <6>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
port@6 {
reg = <6>;
label = "cpu";
fixed-link {
speed = <100>;
full-duplex;
mdio {
#address-cells = <1>;
#size-cells = <0>;
switch1phy0: switch1phy0@0 {
reg = <0>;
};
switch1phy1: switch1phy0@1 {
reg = <1>;
};
switch1phy2: switch1phy0@2 {
reg = <2>;
};
};
};
};
/* 6352 - Secondary - 7 ports */
switch1: switch@0-1 {
mdio_mux_4: mdio@4 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x00 1>;
eeprom-length = <512>;
mii-bus = <&mdio_mux_2>;
reg = <4>;
port@0 {
switch2: switch2@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
label = "lan3";
};
port@1 {
reg = <1>;
label = "lan4";
};
port@2 {
reg = <2>;
label = "lan5";
};
switch1port5: port@5 {
reg = <5>;
label = "dsa";
link = <&switch2port9>;
phy-mode = "rgmii-txid";
fixed-link {
speed = <1000>;
full-duplex;
};
};
switch1port6: port@6 {
reg = <6>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
dsa,member = <0 2>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan6";
};
port@1 {
reg = <1>;
label = "lan7";
};
port@2 {
reg = <2>;
label = "lan8";
};
port@3 {
reg = <3>;
label = "optical3";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 2
GPIO_ACTIVE_HIGH>;
};
};
port@4 {
reg = <4>;
label = "optical4";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 3
GPIO_ACTIVE_HIGH>;
};
};
switch2port9: port@9 {
reg = <9>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port5
&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};
/* 6185 - 10 ports */
switch2: switch@0-2 {
mdio_mux_8: mdio@8 {
reg = <8>;
#address-cells = <1>;
#size-cells = <0>;
reg = <0x00 2>;
mii-bus = <&mdio_mux_4>;
port@0 {
reg = <0>;
label = "lan6";
};
port@1 {
reg = <1>;
label = "lan7";
};
port@2 {
reg = <2>;
label = "lan8";
};
port@3 {
reg = <3>;
label = "optical3";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 2
GPIO_ACTIVE_HIGH>;
};
};
port@4 {
reg = <4>;
label = "optical4";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 3
GPIO_ACTIVE_HIGH>;
};
};
switch2port9: port@9 {
reg = <9>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port5
&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
......
......@@ -804,7 +804,7 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
int (*cb)(struct switchdev_obj *obj))
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
struct net_device *dev = ds->ports[port];
struct net_device *dev = ds->ports[port].netdev;
struct bcm_sf2_arl_entry results[2];
unsigned int count = 0;
int ret;
......@@ -1248,7 +1248,7 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
* state machine and make it go in PHY_FORCING state instead.
*/
if (!status->link)
netif_carrier_off(ds->ports[port]);
netif_carrier_off(ds->ports[port].netdev);
status->duplex = 1;
} else {
status->link = 1;
......
This diff is collapsed.
......@@ -600,6 +600,12 @@ struct mv88e6xxx_priv_state {
/* set to size of eeprom if supported by the switch */
int eeprom_len;
/* Device node for the MDIO bus */
struct device_node *mdio_np;
/* And the MDIO bus itself */
struct mii_bus *mdio_bus;
};
enum stat_type {
......
......@@ -26,6 +26,7 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_TRAILER,
DSA_TAG_PROTO_EDSA,
DSA_TAG_PROTO_BRCM,
DSA_TAG_LAST, /* MUST BE LAST */
};
#define DSA_MAX_SWITCHES 4
......@@ -58,12 +59,11 @@ struct dsa_chip_data {
struct device_node *port_dn[DSA_MAX_PORTS];
/*
* An array (with nr_chips elements) of which element [a]
* indicates which port on this switch should be used to
* send packets to that are destined for switch a. Can be
* NULL if there is only one switch chip.
* An array of which element [a] indicates which port on this
* switch should be used to send packets to that are destined
* for switch a. Can be NULL if there is only one switch chip.
*/
s8 *rtable;
s8 rtable[DSA_MAX_SWITCHES];
};
struct dsa_platform_data {
......@@ -85,6 +85,17 @@ struct dsa_platform_data {
struct packet_type;
struct dsa_switch_tree {
struct list_head list;
/* Tree identifier */
u32 tree;
/* Number of switches attached to this tree */
struct kref refcount;
/* Has this tree been applied to the hardware? */
bool applied;
/*
* Configuration data for the platform device that owns
* this dsa switch tree instance.
......@@ -100,7 +111,6 @@ struct dsa_switch_tree {
struct net_device *dev,
struct packet_type *pt,
struct net_device *orig_dev);
enum dsa_tag_protocol tag_protocol;
/*
* Original copy of the master netdev ethtool_ops
......@@ -117,6 +127,17 @@ struct dsa_switch_tree {
* Data for the individual switch chips.
*/
struct dsa_switch *ds[DSA_MAX_SWITCHES];
/*
* Tagging protocol operations for adding and removing an
* encapsulation tag.
*/
const struct dsa_device_ops *tag_ops;
};
struct dsa_port {
struct net_device *netdev;
struct device_node *dn;
};
struct dsa_switch {
......@@ -144,6 +165,13 @@ struct dsa_switch {
*/
struct dsa_switch_driver *drv;
/*
* An array of which element [a] indicates which port on this
* switch should be used to send packets to that are destined
* for switch a. Can be NULL if there is only one switch chip.
*/
s8 rtable[DSA_MAX_SWITCHES];
#ifdef CONFIG_NET_DSA_HWMON
/*
* Hardware monitoring information
......@@ -152,14 +180,20 @@ struct dsa_switch {
struct device *hwmon_dev;
#endif
/*
* The lower device this switch uses to talk to the host
*/
struct net_device *master_netdev;
/*
* Slave mii_bus and devices for the individual ports.
*/
u32 dsa_port_mask;
u32 cpu_port_mask;
u32 enabled_port_mask;
u32 phys_mii_mask;
struct dsa_port ports[DSA_MAX_PORTS];
struct mii_bus *slave_mii_bus;
struct net_device *ports[DSA_MAX_PORTS];
};
static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
......@@ -174,7 +208,7 @@ static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p)
static inline bool dsa_is_port_initialized(struct dsa_switch *ds, int p)
{
return ds->enabled_port_mask & (1 << p) && ds->ports[p];
return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev;
}
static inline u8 dsa_upstream_port(struct dsa_switch *ds)
......@@ -190,7 +224,7 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds)
if (dst->cpu_switch == ds->index)
return dst->cpu_port;
else
return ds->cd->rtable[dst->cpu_switch];
return ds->rtable[dst->cpu_switch];
}
struct switchdev_trans;
......@@ -344,4 +378,7 @@ static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
{
return dst->rcv != NULL;
}
void dsa_unregister_switch(struct dsa_switch *ds);
int dsa_register_switch(struct dsa_switch *ds, struct device_node *np);
#endif
# the core
obj-$(CONFIG_NET_DSA) += dsa_core.o
dsa_core-y += dsa.o slave.o
dsa_core-y += dsa.o slave.o dsa2.o
# tagging formats
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
......
......@@ -29,6 +29,33 @@
char dsa_driver_version[] = "0.1";
static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
struct net_device *dev)
{
/* Just return the original SKB */
return skb;
}
static const struct dsa_device_ops none_ops = {
.xmit = dsa_slave_notag_xmit,
.rcv = NULL,
};
const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
#ifdef CONFIG_NET_DSA_TAG_DSA
[DSA_TAG_PROTO_DSA] = &dsa_netdev_ops,
#endif
#ifdef CONFIG_NET_DSA_TAG_EDSA
[DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops,
#endif
#ifdef CONFIG_NET_DSA_TAG_TRAILER
[DSA_TAG_PROTO_TRAILER] = &trailer_netdev_ops,
#endif
#ifdef CONFIG_NET_DSA_TAG_BRCM
[DSA_TAG_PROTO_BRCM] = &brcm_netdev_ops,
#endif
[DSA_TAG_PROTO_NONE] = &none_ops,
};
/* switch driver registration ***********************************************/
static DEFINE_MUTEX(dsa_switch_drivers_mutex);
......@@ -180,41 +207,65 @@ __ATTRIBUTE_GROUPS(dsa_hwmon);
#endif /* CONFIG_NET_DSA_HWMON */
/* basic switch operations **************************************************/
static int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct net_device *master)
int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev,
struct device_node *port_dn, int port)
{
struct dsa_chip_data *cd = ds->cd;
struct device_node *port_dn;
struct phy_device *phydev;
int ret, port, mode;
int ret, mode;
if (of_phy_is_fixed_link(port_dn)) {
ret = of_phy_register_fixed_link(port_dn);
if (ret) {
dev_err(dev, "failed to register fixed PHY\n");
return ret;
}
phydev = of_phy_find_device(port_dn);
mode = of_get_phy_mode(port_dn);
if (mode < 0)
mode = PHY_INTERFACE_MODE_NA;
phydev->interface = mode;
genphy_config_init(phydev);
genphy_read_status(phydev);
if (ds->drv->adjust_link)
ds->drv->adjust_link(ds, port, phydev);
}
return 0;
}
static int dsa_cpu_dsa_setups(struct dsa_switch *ds, struct device *dev)
{
struct device_node *port_dn;
int ret, port;
for (port = 0; port < DSA_MAX_PORTS; port++) {
if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)))
continue;
port_dn = cd->port_dn[port];
if (of_phy_is_fixed_link(port_dn)) {
ret = of_phy_register_fixed_link(port_dn);
if (ret) {
netdev_err(master,
"failed to register fixed PHY\n");
return ret;
}
phydev = of_phy_find_device(port_dn);
mode = of_get_phy_mode(port_dn);
if (mode < 0)
mode = PHY_INTERFACE_MODE_NA;
phydev->interface = mode;
genphy_config_init(phydev);
genphy_read_status(phydev);
if (ds->drv->adjust_link)
ds->drv->adjust_link(ds, port, phydev);
}
port_dn = ds->ports[port].dn;
ret = dsa_cpu_dsa_setup(ds, dev, port_dn, port);
if (ret)
return ret;
}
return 0;
}
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol)
{
const struct dsa_device_ops *ops;
if (tag_protocol >= DSA_TAG_LAST)
return ERR_PTR(-EINVAL);
ops = dsa_device_ops[tag_protocol];
if (!ops)
return ERR_PTR(-ENOPROTOOPT);
return ops;
}
static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
{
struct dsa_switch_driver *drv = ds->drv;
......@@ -243,6 +294,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
}
dst->cpu_switch = index;
dst->cpu_port = i;
ds->cpu_port_mask |= 1 << i;
} else if (!strcmp(name, "dsa")) {
ds->dsa_port_mask |= 1 << i;
} else {
......@@ -267,37 +319,17 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
* switch.
*/
if (dst->cpu_switch == index) {
switch (drv->tag_protocol) {
#ifdef CONFIG_NET_DSA_TAG_DSA
case DSA_TAG_PROTO_DSA:
dst->rcv = dsa_netdev_ops.rcv;
break;
#endif
#ifdef CONFIG_NET_DSA_TAG_EDSA
case DSA_TAG_PROTO_EDSA:
dst->rcv = edsa_netdev_ops.rcv;
break;
#endif
#ifdef CONFIG_NET_DSA_TAG_TRAILER
case DSA_TAG_PROTO_TRAILER:
dst->rcv = trailer_netdev_ops.rcv;
break;
#endif
#ifdef CONFIG_NET_DSA_TAG_BRCM
case DSA_TAG_PROTO_BRCM:
dst->rcv = brcm_netdev_ops.rcv;
break;
#endif
case DSA_TAG_PROTO_NONE:
break;
default:
ret = -ENOPROTOOPT;
dst->tag_ops = dsa_resolve_tag_protocol(drv->tag_protocol);
if (IS_ERR(dst->tag_ops)) {
ret = PTR_ERR(dst->tag_ops);
goto out;
}
dst->tag_protocol = drv->tag_protocol;
dst->rcv = dst->tag_ops->rcv;
}
memcpy(ds->rtable, cd->rtable, sizeof(ds->rtable));
/*
* Do basic register setup.
*/
......@@ -309,22 +341,25 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
if (ret < 0)
goto out;
ds->slave_mii_bus = devm_mdiobus_alloc(parent);
if (ds->slave_mii_bus == NULL) {
ret = -ENOMEM;
goto out;
}
dsa_slave_mii_bus_init(ds);
ret = mdiobus_register(ds->slave_mii_bus);
if (ret < 0)
goto out;
if (!ds->slave_mii_bus && drv->phy_read) {
ds->slave_mii_bus = devm_mdiobus_alloc(parent);
if (!ds->slave_mii_bus) {
ret = -ENOMEM;
goto out;
}
dsa_slave_mii_bus_init(ds);
ret = mdiobus_register(ds->slave_mii_bus);
if (ret < 0)
goto out;
}
/*
* Create network devices for physical switch ports.
*/
for (i = 0; i < DSA_MAX_PORTS; i++) {
ds->ports[i].dn = cd->port_dn[i];
if (!(ds->enabled_port_mask & (1 << i)))
continue;
......@@ -337,7 +372,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
}
/* Perform configuration of the CPU and DSA ports */
ret = dsa_cpu_dsa_setup(ds, dst->master_netdev);
ret = dsa_cpu_dsa_setups(ds, parent);
if (ret < 0) {
netdev_err(dst->master_netdev, "[%d] : can't configure CPU and DSA ports\n",
index);
......@@ -420,11 +455,21 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
return ds;
}
static void dsa_switch_destroy(struct dsa_switch *ds)
void dsa_cpu_dsa_destroy(struct device_node *port_dn)
{
struct device_node *port_dn;
struct phy_device *phydev;
struct dsa_chip_data *cd = ds->cd;
if (of_phy_is_fixed_link(port_dn)) {
phydev = of_phy_find_device(port_dn);
if (phydev) {
phy_device_free(phydev);
fixed_phy_unregister(phydev);
}
}
}
static void dsa_switch_destroy(struct dsa_switch *ds)
{
int port;
#ifdef CONFIG_NET_DSA_HWMON
......@@ -437,26 +482,25 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
if (!(ds->enabled_port_mask & (1 << port)))
continue;
if (!ds->ports[port])
if (!ds->ports[port].netdev)
continue;
dsa_slave_destroy(ds->ports[port]);
dsa_slave_destroy(ds->ports[port].netdev);
}
/* Remove any fixed link PHYs */
/* Disable configuration of the CPU and DSA ports */
for (port = 0; port < DSA_MAX_PORTS; port++) {
port_dn = cd->port_dn[port];
if (of_phy_is_fixed_link(port_dn)) {
phydev = of_phy_find_device(port_dn);
if (phydev) {
phy_device_free(phydev);
of_node_put(port_dn);
fixed_phy_unregister(phydev);
}
}
if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)))
continue;
dsa_cpu_dsa_destroy(ds->ports[port].dn);
/* Clearing a bit which is not set does no harm */
ds->cpu_port_mask |= ~(1 << port);
ds->dsa_port_mask |= ~(1 << port);
}
mdiobus_unregister(ds->slave_mii_bus);
if (ds->slave_mii_bus && ds->drv->phy_read)
mdiobus_unregister(ds->slave_mii_bus);
}
#ifdef CONFIG_PM_SLEEP
......@@ -469,7 +513,7 @@ static int dsa_switch_suspend(struct dsa_switch *ds)
if (!dsa_is_port_initialized(ds, i))
continue;
ret = dsa_slave_suspend(ds->ports[i]);
ret = dsa_slave_suspend(ds->ports[i].netdev);
if (ret)
return ret;
}
......@@ -495,7 +539,7 @@ static int dsa_switch_resume(struct dsa_switch *ds)
if (!dsa_is_port_initialized(ds, i))
continue;
ret = dsa_slave_resume(ds->ports[i]);
ret = dsa_slave_resume(ds->ports[i].netdev);
if (ret)
return ret;
}
......@@ -587,17 +631,6 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
if (link_sw_addr >= pd->nr_chips)
return -EINVAL;
/* First time routing table allocation */
if (!cd->rtable) {
cd->rtable = kmalloc_array(pd->nr_chips, sizeof(s8),
GFP_KERNEL);
if (!cd->rtable)
return -ENOMEM;
/* default to no valid uplink/downlink */
memset(cd->rtable, -1, pd->nr_chips * sizeof(s8));
}
cd->rtable[link_sw_addr] = port_index;
return 0;
......@@ -639,7 +672,6 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
kfree(pd->chip[i].port_names[port_index]);
port_index++;
}
kfree(pd->chip[i].rtable);
/* Drop our reference to the MDIO bus device */
if (pd->chip[i].host_dev)
......
This diff is collapsed.
......@@ -50,12 +50,16 @@ struct dsa_slave_priv {
/* dsa.c */
extern char dsa_driver_version[];
int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct device *dev,
struct device_node *port_dn, int port);
void dsa_cpu_dsa_destroy(struct device_node *port_dn);
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol);
/* slave.c */
extern const struct dsa_device_ops notag_netdev_ops;
void dsa_slave_mii_bus_init(struct dsa_switch *ds);
int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
int port, char *name);
int port, const char *name);
void dsa_slave_destroy(struct net_device *slave_dev);
int dsa_slave_suspend(struct net_device *slave_dev);
int dsa_slave_resume(struct net_device *slave_dev);
......
......@@ -49,8 +49,7 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds)
ds->slave_mii_bus->name = "dsa slave smi";
ds->slave_mii_bus->read = dsa_slave_phy_read;
ds->slave_mii_bus->write = dsa_slave_phy_write;
snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d:%.2x",
ds->index, ds->cd->sw_addr);
snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d", ds->index);
ds->slave_mii_bus->parent = ds->dev;
ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
}
......@@ -522,14 +521,6 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
struct net_device *dev)
{
/* Just return the original SKB */
return skb;
}
/* ethtool operations *******************************************************/
static int
dsa_slave_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
......@@ -615,7 +606,7 @@ static int dsa_slave_get_eeprom_len(struct net_device *dev)
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
if (ds->cd->eeprom_len)
if (ds->cd && ds->cd->eeprom_len)
return ds->cd->eeprom_len;
if (ds->drv->get_eeprom_len)
......@@ -999,13 +990,12 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
struct net_device *slave_dev)
{
struct dsa_switch *ds = p->parent;
struct dsa_chip_data *cd = ds->cd;
struct device_node *phy_dn, *port_dn;
bool phy_is_fixed = false;
u32 phy_flags = 0;
int mode, ret;
port_dn = cd->port_dn[p->port];
port_dn = ds->ports[p->port].dn;
mode = of_get_phy_mode(port_dn);
if (mode < 0)
mode = PHY_INTERFACE_MODE_NA;
......@@ -1109,14 +1099,18 @@ int dsa_slave_resume(struct net_device *slave_dev)
}
int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
int port, char *name)
int port, const char *name)
{
struct net_device *master = ds->dst->master_netdev;
struct dsa_switch_tree *dst = ds->dst;
struct net_device *master;
struct net_device *slave_dev;
struct dsa_slave_priv *p;
int ret;
master = ds->dst->master_netdev;
if (ds->master_netdev)
master = ds->master_netdev;
slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name,
NET_NAME_UNKNOWN, ether_setup);
if (slave_dev == NULL)
......@@ -1147,49 +1141,24 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
NULL);
SET_NETDEV_DEV(slave_dev, parent);
slave_dev->dev.of_node = ds->cd->port_dn[port];
slave_dev->dev.of_node = ds->ports[port].dn;
slave_dev->vlan_features = master->vlan_features;
p = netdev_priv(slave_dev);
p->parent = ds;
p->port = port;
switch (ds->dst->tag_protocol) {
#ifdef CONFIG_NET_DSA_TAG_DSA
case DSA_TAG_PROTO_DSA:
p->xmit = dsa_netdev_ops.xmit;
break;
#endif
#ifdef CONFIG_NET_DSA_TAG_EDSA
case DSA_TAG_PROTO_EDSA:
p->xmit = edsa_netdev_ops.xmit;
break;
#endif
#ifdef CONFIG_NET_DSA_TAG_TRAILER
case DSA_TAG_PROTO_TRAILER:
p->xmit = trailer_netdev_ops.xmit;
break;
#endif
#ifdef CONFIG_NET_DSA_TAG_BRCM
case DSA_TAG_PROTO_BRCM:
p->xmit = brcm_netdev_ops.xmit;
break;
#endif
default:
p->xmit = dsa_slave_notag_xmit;
break;
}
p->xmit = dst->tag_ops->xmit;
p->old_pause = -1;
p->old_link = -1;
p->old_duplex = -1;
ds->ports[port] = slave_dev;
ds->ports[port].netdev = slave_dev;
ret = register_netdev(slave_dev);
if (ret) {
netdev_err(master, "error %d registering interface %s\n",
ret, slave_dev->name);
ds->ports[port] = NULL;
ds->ports[port].netdev = NULL;
free_netdev(slave_dev);
return ret;
}
......
......@@ -127,7 +127,7 @@ static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
/* Validate port against switch setup, either the port is totally */
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
if (source_port >= DSA_MAX_PORTS || !ds->ports[source_port].netdev)
goto out_drop;
/* Remove Broadcom tag and update checksum */
......@@ -140,7 +140,7 @@ static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
skb_push(skb, ETH_HLEN);
skb->pkt_type = PACKET_HOST;
skb->dev = ds->ports[source_port];
skb->dev = ds->ports[source_port].netdev;
skb->protocol = eth_type_trans(skb, skb->dev);
skb->dev->stats.rx_packets++;
......
......@@ -107,10 +107,14 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
* Check that the source device exists and that the source
* port is a registered DSA port.
*/
if (source_device >= dst->pd->nr_chips)
if (source_device >= DSA_MAX_SWITCHES)
goto out_drop;
ds = dst->ds[source_device];
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
if (!ds)
goto out_drop;
if (source_port >= DSA_MAX_PORTS || !ds->ports[source_port].netdev)
goto out_drop;
/*
......@@ -159,7 +163,7 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
2 * ETH_ALEN);
}
skb->dev = ds->ports[source_port];
skb->dev = ds->ports[source_port].netdev;
skb_push(skb, ETH_HLEN);
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, skb->dev);
......
......@@ -120,10 +120,14 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
* Check that the source device exists and that the source
* port is a registered DSA port.
*/
if (source_device >= dst->pd->nr_chips)
if (source_device >= DSA_MAX_SWITCHES)
goto out_drop;
ds = dst->ds[source_device];
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
if (!ds)
goto out_drop;
if (source_port >= DSA_MAX_PORTS || !ds->ports[source_port].netdev)
goto out_drop;
/*
......@@ -178,7 +182,7 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
2 * ETH_ALEN);
}
skb->dev = ds->ports[source_port];
skb->dev = ds->ports[source_port].netdev;
skb_push(skb, ETH_HLEN);
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, skb->dev);
......
......@@ -82,12 +82,12 @@ static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
goto out_drop;
source_port = trailer[1] & 7;
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
if (source_port >= DSA_MAX_PORTS || !ds->ports[source_port].netdev)
goto out_drop;
pskb_trim_rcsum(skb, skb->len - 4);
skb->dev = ds->ports[source_port];
skb->dev = ds->ports[source_port].netdev;
skb_push(skb, ETH_HLEN);
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, skb->dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment