netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support
@ 2014-08-26  4:49 Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks Florian Fainelli
                   ` (12 more replies)
  0 siblings, 13 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

Hi all,

This patch series adds support for the Broadcom Starfighter 2 (Roboswitch
successor) using the existing DSA infrastructure. This integrated switch
is heavily used in Set Top Box, Cable gateways and DSL gateways products
from Broadcom, and to a larger extent the new ARM-based Wi-Fi routers although
slightly differently.

Changes in v4 are the introducing of an indirection level for DSA switch tag
protocols receive and transmit functions.

I intentionnaly did not address one comment from Alexander who suggested to
move port_names and port_dn in a separate structure since that involves
touching arch/arm/ and arch/blackfin/ code which I am not yet comfortable
doing.

Notable changes in v3 is the preliminary patch that reworks the skb->protocol
override helpers for non-Ethertype switch tags, based on feedback from
Alexander Duyck.

The biggest changes from v1 of this patch series are:

- use the new fixed PHY helpers
- improved the switch driver with more complete features (interrupts,
  (RG)MII configuration, memory arrays power down/up, port disabling/enable
  VLAN separation

Future work will focus on bringing the upstream driver in feature parity with
the current downstream driver, including:

- adding Wake-on-LAN support to the switch
- adding suspend/resume callbacks for S2/S3 Power Management modes
- extending the switch register interface to cover BCM5310X SoCs

Florian Fainelli (13):
  net: dsa: reduce number of protocol hooks
  net: phy: add generic UniMAC MDIO bus driver
  net: phy: provide stub for fixed_phy_set_link_update
  net: dsa: provide a switch device device tree node pointer
  net: dsa: retain a per-port device_node pointer
  net: dsa: allow for more complex PHY setups
  net: dsa: allow switches to work without tagging
  net: dsa: allow drivers to do link adjustment
  net: dsa: allow updating fixed PHY link information
  net: dsa: add Broadcom tag RX/TX handler
  net: dsa: add Broadcom SF2 switch driver
  Documentation: devicetree: update dsa binding with optional properties
  Documentation: devicetree: add Broadcom Starfighter 2 binding

 .../bindings/net/broadcom-mdio-unimac.txt          |  39 ++
 .../devicetree/bindings/net/broadcom-sf2.txt       |  78 +++
 Documentation/devicetree/bindings/net/dsa/dsa.txt  |  17 +
 drivers/net/dsa/Kconfig                            |  11 +
 drivers/net/dsa/Makefile                           |   1 +
 drivers/net/dsa/bcm_sf2.c                          | 626 +++++++++++++++++++++
 drivers/net/dsa/bcm_sf2.h                          | 140 +++++
 drivers/net/dsa/bcm_sf2_regs.h                     | 227 ++++++++
 drivers/net/phy/Kconfig                            |   8 +
 drivers/net/phy/Makefile                           |   1 +
 drivers/net/phy/mdio-bcm-unimac.c                  | 212 +++++++
 include/linux/netdevice.h                          |  26 +-
 include/linux/phy_fixed.h                          |  17 +-
 include/net/dsa.h                                  |  38 +-
 include/uapi/linux/if_ether.h                      |   1 +
 net/dsa/Kconfig                                    |   3 +
 net/dsa/Makefile                                   |   1 +
 net/dsa/dsa.c                                      |  48 +-
 net/dsa/dsa_priv.h                                 |  16 +-
 net/dsa/slave.c                                    | 165 ++++--
 net/dsa/tag_brcm.c                                 | 173 ++++++
 net/dsa/tag_dsa.c                                  |   8 +-
 net/dsa/tag_edsa.c                                 |   8 +-
 net/dsa/tag_trailer.c                              |   8 +-
 net/ethernet/eth.c                                 |   5 +-
 25 files changed, 1766 insertions(+), 111 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
 create mode 100644 Documentation/devicetree/bindings/net/broadcom-sf2.txt
 create mode 100644 drivers/net/dsa/bcm_sf2.c
 create mode 100644 drivers/net/dsa/bcm_sf2.h
 create mode 100644 drivers/net/dsa/bcm_sf2_regs.h
 create mode 100644 drivers/net/phy/mdio-bcm-unimac.c
 create mode 100644 net/dsa/tag_brcm.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-27 15:25   ` Alexander Duyck
  2014-08-26  4:49 ` [PATCH net-next v4 02/13] net: phy: add generic UniMAC MDIO bus driver Florian Fainelli
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

DSA is currently registering one packet_type function per EtherType it
needs to intercept in the receive path of a DSA-enabled Ethernet device.
Right now we have three of them: trailer, DSA and eDSA, and there might
be more in the future, this will not scale to the addition of new
protocols.

This patch proceeds with adding a new layer of abstraction and two new
functions:

dsa_switch_rcv() which will dispatch into the tag-protocol specific
receive function implemented by net/dsa/tag_*.c

dsa_slave_xmit() which will dispatch into the tag-protocol specific
transmit function implemented by net/dsa/tag_*.c

When we do create the per-port slave network devices, we iterate over
the switch protocol to assign the DSA-specific receive and transmit
operations.

This allows us to greatly simplify the check in eth_type_trans() and
always override the skb->protocol with ETH_P_DSA for Ethernet switches
tagged protocol, while also reducing the number repetitive slave
netdevice_ops assignments.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v4:
- introduce a level of indirection and dsa_device_ops to limit the
  number of packet_type functions to just one and do the dispatching
  in the core dsa code.

New patch in v3

 include/linux/netdevice.h | 28 ++++++++++++----------------
 include/net/dsa.h         | 20 +++-----------------
 net/dsa/dsa.c             | 39 +++++++++++++++++++++------------------
 net/dsa/dsa_priv.h        |  9 +++------
 net/dsa/slave.c           | 45 ++++++++++++++-------------------------------
 net/dsa/tag_dsa.c         |  8 ++++----
 net/dsa/tag_edsa.c        |  8 ++++----
 net/dsa/tag_trailer.c     |  8 ++++----
 net/ethernet/eth.c        |  5 +----
 9 files changed, 66 insertions(+), 104 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 039b23786c22..1875dc71422a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1781,24 +1781,13 @@ void dev_net_set(struct net_device *dev, struct net *net)
 #endif
 }
 
-static inline bool netdev_uses_dsa_tags(struct net_device *dev)
+static inline bool netdev_uses_dsa(struct net_device *dev)
 {
-#ifdef CONFIG_NET_DSA_TAG_DSA
-	if (dev->dsa_ptr != NULL)
-		return dsa_uses_dsa_tags(dev->dsa_ptr);
-#endif
-
-	return 0;
-}
-
-static inline bool netdev_uses_trailer_tags(struct net_device *dev)
-{
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-	if (dev->dsa_ptr != NULL)
-		return dsa_uses_trailer_tags(dev->dsa_ptr);
+#ifdef CONFIG_NET_DSA
+	return dev->dsa_ptr != NULL;
+#else
+	return false;
 #endif
-
-	return 0;
 }
 
 /**
@@ -1933,6 +1922,13 @@ struct udp_offload {
 	struct offload_callbacks callbacks;
 };
 
+struct dsa_device_ops {
+	netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev);
+	int (*rcv)(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *pt, struct net_device *orig_dev);
+};
+
+
 /* often modified stats are per cpu, other are shared (netdev->stats) */
 struct pcpu_sw_netstats {
 	u64     rx_packets;
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6efce384451e..6e26f1e4d8ce 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -59,6 +59,8 @@ struct dsa_platform_data {
 	struct dsa_chip_data	*chip;
 };
 
+struct dsa_device_ops;
+
 struct dsa_switch_tree {
 	/*
 	 * Configuration data for the platform device that owns
@@ -71,6 +73,7 @@ struct dsa_switch_tree {
 	 * protocol to use.
 	 */
 	struct net_device	*master_netdev;
+	const struct dsa_device_ops	*ops;
 	__be16			tag_protocol;
 
 	/*
@@ -186,21 +189,4 @@ static inline void *ds_to_priv(struct dsa_switch *ds)
 	return (void *)(ds + 1);
 }
 
-/*
- * The original DSA tag format and some other tag formats have no
- * ethertype, which means that we need to add a little hack to the
- * networking receive path to make sure that received frames get
- * the right ->protocol assigned to them when one of those tag
- * formats is in use.
- */
-static inline bool dsa_uses_dsa_tags(struct dsa_switch_tree *dst)
-{
-	return !!(dst->tag_protocol == htons(ETH_P_DSA));
-}
-
-static inline bool dsa_uses_trailer_tags(struct dsa_switch_tree *dst)
-{
-	return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
-}
-
 #endif
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 0a49632fac47..62a8c91bba48 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -608,6 +608,24 @@ static void dsa_shutdown(struct platform_device *pdev)
 {
 }
 
+static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
+			  struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct dsa_switch_tree *dst = dev->dsa_ptr;
+
+	if (unlikely(dst == NULL)) {
+		kfree_skb(skb);
+		return 0;
+	}
+
+	return dst->ops->rcv(skb, dev, pt, orig_dev);
+}
+
+struct packet_type dsa_pack_type __read_mostly = {
+	.type	= cpu_to_be16(ETH_P_DSA),
+	.func	= dsa_switch_rcv,
+};
+
 static const struct of_device_id dsa_of_match_table[] = {
 	{ .compatible = "marvell,dsa", },
 	{}
@@ -633,30 +651,15 @@ static int __init dsa_init_module(void)
 	if (rc)
 		return rc;
 
-#ifdef CONFIG_NET_DSA_TAG_DSA
-	dev_add_pack(&dsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-	dev_add_pack(&edsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-	dev_add_pack(&trailer_packet_type);
-#endif
+	dev_add_pack(&dsa_pack_type);
+
 	return 0;
 }
 module_init(dsa_init_module);
 
 static void __exit dsa_cleanup_module(void)
 {
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-	dev_remove_pack(&trailer_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-	dev_remove_pack(&edsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_DSA
-	dev_remove_pack(&dsa_packet_type);
-#endif
+	dev_remove_pack(&dsa_pack_type);
 	platform_driver_unregister(&dsa_driver);
 }
 module_exit(dsa_cleanup_module);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index d4cf5cc747e3..218d75d16f6f 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -45,16 +45,13 @@ struct net_device *dsa_slave_create(struct dsa_switch *ds,
 				    int port, char *name);
 
 /* tag_dsa.c */
-netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type dsa_packet_type;
+extern const struct dsa_device_ops dsa_netdev_ops;
 
 /* tag_edsa.c */
-netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type edsa_packet_type;
+extern const struct dsa_device_ops edsa_netdev_ops;
 
 /* tag_trailer.c */
-netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type trailer_packet_type;
+extern const struct dsa_device_ops trailer_netdev_ops;
 
 
 #endif
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 45a1e34c89e0..ad1a913533aa 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -171,6 +171,14 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	return -EOPNOTSUPP;
 }
 
+static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch_tree *dst = p->parent->dst;
+
+	return dst->ops->xmit(skb, dev);
+}
+
 
 /* ethtool operations *******************************************************/
 static int
@@ -293,42 +301,16 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
 	.get_sset_count		= dsa_slave_get_sset_count,
 };
 
-#ifdef CONFIG_NET_DSA_TAG_DSA
-static const struct net_device_ops dsa_netdev_ops = {
+static const struct net_device_ops dsa_slave_netdev_ops = {
 	.ndo_init		= dsa_slave_init,
 	.ndo_open	 	= dsa_slave_open,
 	.ndo_stop		= dsa_slave_close,
-	.ndo_start_xmit		= dsa_xmit,
+	.ndo_start_xmit		= dsa_slave_xmit,
 	.ndo_change_rx_flags	= dsa_slave_change_rx_flags,
 	.ndo_set_rx_mode	= dsa_slave_set_rx_mode,
 	.ndo_set_mac_address	= dsa_slave_set_mac_address,
 	.ndo_do_ioctl		= dsa_slave_ioctl,
 };
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-static const struct net_device_ops edsa_netdev_ops = {
-	.ndo_init		= dsa_slave_init,
-	.ndo_open	 	= dsa_slave_open,
-	.ndo_stop		= dsa_slave_close,
-	.ndo_start_xmit		= edsa_xmit,
-	.ndo_change_rx_flags	= dsa_slave_change_rx_flags,
-	.ndo_set_rx_mode	= dsa_slave_set_rx_mode,
-	.ndo_set_mac_address	= dsa_slave_set_mac_address,
-	.ndo_do_ioctl		= dsa_slave_ioctl,
-};
-#endif
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-static const struct net_device_ops trailer_netdev_ops = {
-	.ndo_init		= dsa_slave_init,
-	.ndo_open	 	= dsa_slave_open,
-	.ndo_stop		= dsa_slave_close,
-	.ndo_start_xmit		= trailer_xmit,
-	.ndo_change_rx_flags	= dsa_slave_change_rx_flags,
-	.ndo_set_rx_mode	= dsa_slave_set_rx_mode,
-	.ndo_set_mac_address	= dsa_slave_set_mac_address,
-	.ndo_do_ioctl		= dsa_slave_ioctl,
-};
-#endif
 
 /* slave device setup *******************************************************/
 struct net_device *
@@ -349,21 +331,22 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 	slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
 	eth_hw_addr_inherit(slave_dev, master);
 	slave_dev->tx_queue_len = 0;
+	slave_dev->netdev_ops = &dsa_slave_netdev_ops;
 
 	switch (ds->dst->tag_protocol) {
 #ifdef CONFIG_NET_DSA_TAG_DSA
 	case htons(ETH_P_DSA):
-		slave_dev->netdev_ops = &dsa_netdev_ops;
+		ds->dst->ops = &dsa_netdev_ops;
 		break;
 #endif
 #ifdef CONFIG_NET_DSA_TAG_EDSA
 	case htons(ETH_P_EDSA):
-		slave_dev->netdev_ops = &edsa_netdev_ops;
+		ds->dst->ops = &edsa_netdev_ops;
 		break;
 #endif
 #ifdef CONFIG_NET_DSA_TAG_TRAILER
 	case htons(ETH_P_TRAILER):
-		slave_dev->netdev_ops = &trailer_netdev_ops;
+		ds->dst->ops = &trailer_netdev_ops;
 		break;
 #endif
 	default:
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index cacce1e22f9c..d7dbc5bda5c0 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -16,7 +16,7 @@
 
 #define DSA_HLEN	4
 
-netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
 	u8 *dsa_header;
@@ -186,7 +186,7 @@ out:
 	return 0;
 }
 
-struct packet_type dsa_packet_type __read_mostly = {
-	.type	= cpu_to_be16(ETH_P_DSA),
-	.func	= dsa_rcv,
+const struct dsa_device_ops dsa_netdev_ops = {
+	.xmit	= dsa_xmit,
+	.rcv	= dsa_rcv,
 };
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index e70c43c25e64..6b30abe89183 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -17,7 +17,7 @@
 #define DSA_HLEN	4
 #define EDSA_HLEN	8
 
-netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
 	u8 *edsa_header;
@@ -205,7 +205,7 @@ out:
 	return 0;
 }
 
-struct packet_type edsa_packet_type __read_mostly = {
-	.type	= cpu_to_be16(ETH_P_EDSA),
-	.func	= edsa_rcv,
+const struct dsa_device_ops edsa_netdev_ops = {
+	.xmit	= edsa_xmit,
+	.rcv	= edsa_rcv,
 };
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index 94bc260d015d..5fe9444842c5 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -14,7 +14,7 @@
 #include <linux/slab.h>
 #include "dsa_priv.h"
 
-netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
 	struct sk_buff *nskb;
@@ -114,7 +114,7 @@ out:
 	return 0;
 }
 
-struct packet_type trailer_packet_type __read_mostly = {
-	.type	= cpu_to_be16(ETH_P_TRAILER),
-	.func	= trailer_rcv,
+const struct dsa_device_ops trailer_netdev_ops = {
+	.xmit	= trailer_xmit,
+	.rcv	= trailer_rcv,
 };
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index f405e0592407..636721f15b57 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -181,12 +181,9 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
 	 * variants has been configured on the receiving interface,
 	 * and if so, set skb->protocol without looking at the packet.
 	 */
-	if (unlikely(netdev_uses_dsa_tags(dev)))
+	if (unlikely(netdev_uses_dsa(dev)))
 		return htons(ETH_P_DSA);
 
-	if (unlikely(netdev_uses_trailer_tags(dev)))
-		return htons(ETH_P_TRAILER);
-
 	if (likely(ntohs(eth->h_proto) >= ETH_P_802_3_MIN))
 		return eth->h_proto;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 02/13] net: phy: add generic UniMAC MDIO bus driver
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 03/13] net: phy: provide stub for fixed_phy_set_link_update Florian Fainelli
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

Add a generic UniMAC MDIO bus driver and its Device Tree binding, which
can be used by the BCMGENET driver as-is, and the upcoming Starfighter 2
Ethernet switch MDIO bus controller.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v4:
- added a slightly longer paragraph in Kconfig about where this hardware can
  be found

Changes in v3:
- renamed from mdio-unimac to mdio-bcm-unimac

Changes in v2:
- improved binding documentation with respect to the HW setups available
  influencing interrupts
 .../bindings/net/broadcom-mdio-unimac.txt          |  39 ++++
 drivers/net/phy/Kconfig                            |   8 +
 drivers/net/phy/Makefile                           |   1 +
 drivers/net/phy/mdio-bcm-unimac.c                  | 212 +++++++++++++++++++++
 4 files changed, 260 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
 create mode 100644 drivers/net/phy/mdio-bcm-unimac.c

diff --git a/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt b/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
new file mode 100644
index 000000000000..ab0bb4247d14
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
@@ -0,0 +1,39 @@
+* Broadcom UniMAC MDIO bus controller
+
+Required properties:
+- compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2",
+  "brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio"
+- reg: address and length of the regsiter set for the device, first one is the
+  base register, and the second one is optional and for indirect accesses to
+  larger than 16-bits MDIO transactions
+- reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw"
+- #size-cells: must be 1
+- #address-cells: must be 0
+
+Optional properties:
+- interrupts: must be one if the interrupt is shared with the Ethernet MAC or
+  Ethernet switch this MDIO block is integrated from, or must be two, if there
+  are two separate interrupts, first one must be "mdio done" and second must be
+  for "mdio error"
+- interrupt-names: must be "mdio_done_error" when there is a share interrupt fed
+  to this hardware block, or must be "mdio_done" for the first interrupt and
+  "mdio_error" for the second when there are separate interrupts
+
+Child nodes of this MDIO bus controller node are standard Ethernet PHY device
+nodes as described in Documentation/devicetree/bindings/net/phy.txt
+
+Example:
+
+mdio@403c0 {
+	compatible = "brcm,unimac-mdio";
+	reg = <0x403c0 0x8 0x40300 0x18>;
+	reg-names = "mdio", "mdio_indir_rw";
+	#size-cells = <1>;
+	#address-cells = <0>;
+
+	...
+	phy@0 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0>;
+	};
+};
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 65de0cab8d07..28437ab9c7bd 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -205,6 +205,14 @@ config MDIO_BUS_MUX_MMIOREG
 
 	  Currently, only 8-bit registers are supported.
 
+config MDIO_BCM_UNIMAC
+	tristate "Broadcom UniMAC MDIO bus controller"
+	help
+	  This module provides a driver for the Broadcom UniMAC MDIO busses.
+	  This hardware can be found in the Broadcom GENET Ethernet MAC
+	  controllers as well as some Broadcom Ethernet switches such as the
+	  Starfighter 2 switches.
+
 endif # PHYLIB
 
 config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 7dc3d5b304cf..eb3b18b5978b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
 obj-$(CONFIG_MDIO_SUN4I)	+= mdio-sun4i.o
 obj-$(CONFIG_MDIO_MOXART)	+= mdio-moxart.o
 obj-$(CONFIG_AMD_XGBE_PHY)	+= amd-xgbe-phy.o
+obj-$(CONFIG_MDIO_BCM_UNIMAC)	+= mdio-bcm-unimac.o
diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
new file mode 100644
index 000000000000..e6b08ceb9c37
--- /dev/null
+++ b/drivers/net/phy/mdio-bcm-unimac.c
@@ -0,0 +1,212 @@
+/*
+ * Broadcom UniMAC MDIO bus controller driver
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+
+#define MDIO_CMD		0x00
+#define  MDIO_START_BUSY	(1 << 29)
+#define  MDIO_READ_FAIL		(1 << 28)
+#define  MDIO_RD		(2 << 26)
+#define  MDIO_WR		(1 << 26)
+#define  MDIO_PMD_SHIFT		21
+#define  MDIO_PMD_MASK		0x1F
+#define  MDIO_REG_SHIFT		16
+#define  MDIO_REG_MASK		0x1F
+
+#define MDIO_CFG		0x04
+#define  MDIO_C22		(1 << 0)
+#define  MDIO_C45		0
+#define  MDIO_CLK_DIV_SHIFT	4
+#define  MDIO_CLK_DIV_MASK	0x3F
+#define  MDIO_SUPP_PREAMBLE	(1 << 12)
+
+struct unimac_mdio_priv {
+	struct mii_bus		*mii_bus;
+	void __iomem		*base;
+};
+
+static inline void unimac_mdio_start(struct unimac_mdio_priv *priv)
+{
+	u32 reg;
+
+	reg = __raw_readl(priv->base + MDIO_CMD);
+	reg |= MDIO_START_BUSY;
+	__raw_writel(reg, priv->base + MDIO_CMD);
+}
+
+static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv)
+{
+	return __raw_readl(priv->base + MDIO_CMD) & MDIO_START_BUSY;
+}
+
+static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+	struct unimac_mdio_priv *priv = bus->priv;
+	unsigned int timeout = 1000;
+	u32 cmd;
+
+	/* Prepare the read operation */
+	cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT);
+	__raw_writel(cmd, priv->base + MDIO_CMD);
+
+	/* Start MDIO transaction */
+	unimac_mdio_start(priv);
+
+	do {
+		if (!unimac_mdio_busy(priv))
+			break;
+
+		usleep_range(1000, 2000);
+	} while (timeout--);
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	cmd = __raw_readl(priv->base + MDIO_CMD);
+	if (cmd & MDIO_READ_FAIL)
+		return -EIO;
+
+	return cmd & 0xffff;
+}
+
+static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
+			     int reg, u16 val)
+{
+	struct unimac_mdio_priv *priv = bus->priv;
+	unsigned int timeout = 1000;
+	u32 cmd;
+
+	/* Prepare the write operation */
+	cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
+		(reg << MDIO_REG_SHIFT) | (0xffff & val);
+	__raw_writel(cmd, priv->base + MDIO_CMD);
+
+	unimac_mdio_start(priv);
+
+	do {
+		if (!unimac_mdio_busy(priv))
+			break;
+
+		usleep_range(1000, 2000);
+	} while (timeout--);
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int unimac_mdio_probe(struct platform_device *pdev)
+{
+	struct unimac_mdio_priv *priv;
+	struct device_node *np;
+	struct mii_bus *bus;
+	struct resource *r;
+	int ret;
+
+	np = pdev->dev.of_node;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	/* Just ioremap, as this MDIO block is usually integrated into an
+	 * Ethernet MAC controller register range
+	 */
+	priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!priv->base) {
+		dev_err(&pdev->dev, "failed to remap register\n");
+		return -ENOMEM;
+	}
+
+	priv->mii_bus = mdiobus_alloc();
+	if (!priv->mii_bus)
+		return -ENOMEM;
+
+	bus = priv->mii_bus;
+	bus->priv = priv;
+	bus->name = "unimac MII bus";
+	bus->parent = &pdev->dev;
+	bus->read = unimac_mdio_read;
+	bus->write = unimac_mdio_write;
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+
+	bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+	if (!bus->irq) {
+		ret = -ENOMEM;
+		goto out_mdio_free;
+	}
+
+	ret = of_mdiobus_register(bus, np);
+	if (ret) {
+		dev_err(&pdev->dev, "MDIO bus registration failed\n");
+		goto out_mdio_irq;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	dev_info(&pdev->dev, "Broadcom UniMAC MDIO bus at 0x%p\n", priv->base);
+
+	return 0;
+
+out_mdio_irq:
+	kfree(bus->irq);
+out_mdio_free:
+	mdiobus_free(bus);
+	return ret;
+}
+
+static int unimac_mdio_remove(struct platform_device *pdev)
+{
+	struct unimac_mdio_priv *priv = platform_get_drvdata(pdev);
+
+	mdiobus_unregister(priv->mii_bus);
+	kfree(priv->mii_bus->irq);
+	mdiobus_free(priv->mii_bus);
+
+	return 0;
+}
+
+static struct of_device_id unimac_mdio_ids[] = {
+	{ .compatible = "brcm,genet-mdio-v4", },
+	{ .compatible = "brcm,genet-mdio-v3", },
+	{ .compatible = "brcm,genet-mdio-v2", },
+	{ .compatible = "brcm,genet-mdio-v1", },
+	{ .compatible = "brcm,unimac-mdio", },
+};
+
+static struct platform_driver unimac_mdio_driver = {
+	.driver = {
+		.name = "unimac-mdio",
+		.owner = THIS_MODULE,
+		.of_match_table = unimac_mdio_ids,
+	},
+	.probe	= unimac_mdio_probe,
+	.remove	= unimac_mdio_remove,
+};
+module_platform_driver(unimac_mdio_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:unimac-mdio");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 03/13] net: phy: provide stub for fixed_phy_set_link_update
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 02/13] net: phy: add generic UniMAC MDIO bus driver Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 04/13] net: dsa: provide a switch device device tree node pointer Florian Fainelli
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

In preparation for updating the DSA code and avoid using ifdefs there,
provide an empty stub for fixed_phy_set_link_update when
CONFIG_FIXED_PHY is not selected.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
New patch in v4 that resulted in more build testing

 include/linux/phy_fixed.h | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h
index ae612acebb53..941138664c1d 100644
--- a/include/linux/phy_fixed.h
+++ b/include/linux/phy_fixed.h
@@ -18,6 +18,9 @@ extern int fixed_phy_register(unsigned int irq,
 			      struct fixed_phy_status *status,
 			      struct device_node *np);
 extern void fixed_phy_del(int phy_addr);
+extern int fixed_phy_set_link_update(struct phy_device *phydev,
+			int (*link_update)(struct net_device *,
+					   struct fixed_phy_status *));
 #else
 static inline int fixed_phy_add(unsigned int irq, int phy_id,
 				struct fixed_phy_status *status)
@@ -34,14 +37,12 @@ static inline int fixed_phy_del(int phy_addr)
 {
 	return -ENODEV;
 }
-#endif /* CONFIG_FIXED_PHY */
-
-/*
- * This function issued only by fixed_phy-aware drivers, no need
- * protect it with #ifdef
- */
-extern int fixed_phy_set_link_update(struct phy_device *phydev,
+static inline int fixed_phy_set_link_update(struct phy_device *phydev,
 			int (*link_update)(struct net_device *,
-					   struct fixed_phy_status *));
+					   struct fixed_phy_status *))
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_FIXED_PHY */
 
 #endif /* __PHY_FIXED_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 04/13] net: dsa: provide a switch device device tree node pointer
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (2 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 03/13] net: phy: provide stub for fixed_phy_set_link_update Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 05/13] net: dsa: retain a per-port device_node pointer Florian Fainelli
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

We might need to fetch additional resources from the device tree node
pointer, such as register ranges or other properties. Keep a device_node
pointer around for this.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 include/net/dsa.h | 7 +++++++
 net/dsa/dsa.c     | 1 +
 2 files changed, 8 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6e26f1e4d8ce..decc62709acd 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
 
 #define DSA_MAX_SWITCHES	4
 #define DSA_MAX_PORTS		12
@@ -26,6 +27,12 @@ struct dsa_chip_data {
 	struct device	*mii_bus;
 	int		sw_addr;
 
+	/* Device tree node pointer for this specific switch chip
+	 * used during switch setup in case additional properties
+	 * and resources needs to be used
+	 */
+	struct device_node *of_node;
+
 	/*
 	 * The names of the switch's ports.  Use "cpu" to
 	 * designate the switch port that the cpu is connected to,
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 62a8c91bba48..1ad18cfd1a3e 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -410,6 +410,7 @@ static int dsa_of_probe(struct platform_device *pdev)
 		chip_index++;
 		cd = &pd->chip[chip_index];
 
+		cd->of_node = child;
 		cd->mii_bus = &mdio_bus->dev;
 
 		sw_addr = of_get_property(child, "reg", NULL);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 05/13] net: dsa: retain a per-port device_node pointer
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (3 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 04/13] net: dsa: provide a switch device device tree node pointer Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 06/13] net: dsa: allow for more complex PHY setups Florian Fainelli
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

We will later use the per-port device_node pointer to fetch a bunch of
port-specific properties.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v2, v3, v4:
- respin

 include/net/dsa.h | 1 +
 net/dsa/dsa.c     | 2 ++
 net/dsa/slave.c   | 1 +
 3 files changed, 4 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index decc62709acd..597875d3f69e 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -41,6 +41,7 @@ struct dsa_chip_data {
 	 * or any other string to indicate this is a physical port.
 	 */
 	char		*port_names[DSA_MAX_PORTS];
+	struct device_node *port_dn[DSA_MAX_PORTS];
 
 	/*
 	 * An array (with nr_chips elements) of which element [a]
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 1ad18cfd1a3e..e3a1ec109a01 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -432,6 +432,8 @@ static int dsa_of_probe(struct platform_device *pdev)
 			if (!port_name)
 				continue;
 
+			cd->port_dn[port_index] = port;
+
 			cd->port_names[port_index] = kstrdup(port_name,
 					GFP_KERNEL);
 			if (!cd->port_names[port_index]) {
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index ad1a913533aa..5688c34253e5 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -354,6 +354,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 	}
 
 	SET_NETDEV_DEV(slave_dev, parent);
+	slave_dev->dev.of_node = ds->pd->port_dn[port];
 	slave_dev->vlan_features = master->vlan_features;
 
 	p = netdev_priv(slave_dev);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 06/13] net: dsa: allow for more complex PHY setups
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (4 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 05/13] net: dsa: retain a per-port device_node pointer Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 07/13] net: dsa: allow switches to work without tagging Florian Fainelli
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

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>
---
Changes in v4:
- make more build testing
- changed phy_is_fixed from 'unsigned int' to 'bool' type

Changes in v2:
- introduce phys_mii_mask to allow switch drivers to divert MDIO operations
  for some PHY addresses

- use the latest fixed PHY API
- iron out non-OF setups

 include/net/dsa.h  |  1 +
 net/dsa/dsa.c      |  5 ++++
 net/dsa/dsa_priv.h |  4 +++
 net/dsa/slave.c    | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 597875d3f69e..dc357454ae3b 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -130,6 +130,7 @@ struct dsa_switch {
 	 */
 	u32			dsa_port_mask;
 	u32			phys_port_mask;
+	u32			phys_mii_mask;
 	struct mii_bus		*slave_mii_bus;
 	struct net_device	*ports[DSA_MAX_PORTS];
 };
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index e3a1ec109a01..03b0d9221d35 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,
 		goto out;
 	}
 
+	/* Make the built-in MII bus mask match the number of ports,
+	 * switch drivers can override this later
+	 */
+	ds->phys_mii_mask = ds->phys_port_mask;
+
 	/*
 	 * If the CPU connects to this switch, set the switch tree
 	 * 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 {
 	 * to this port.
 	 */
 	struct phy_device	*phy;
+	phy_interface_t		phy_interface;
+	int			old_link;
+	int			old_pause;
+	int			old_duplex;
 };
 
 /* 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 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
 #include "dsa_priv.h"
 
 /* slave mii_bus handling ***************************************************/
@@ -19,7 +21,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
 {
 	struct dsa_switch *ds = bus->priv;
 
-	if (ds->phys_port_mask & (1 << addr))
+	if (ds->phys_mii_mask & (1 << addr))
 		return ds->drv->phy_read(ds, addr, reg);
 
 	return 0xffff;
@@ -29,7 +31,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
 {
 	struct dsa_switch *ds = bus->priv;
 
-	if (ds->phys_port_mask & (1 << addr))
+	if (ds->phys_mii_mask & (1 << addr))
 		return ds->drv->phy_write(ds, addr, reg, val);
 
 	return 0;
@@ -312,7 +314,70 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
 	.ndo_do_ioctl		= dsa_slave_ioctl,
 };
 
+static void dsa_slave_adjust_link(struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	unsigned int status_changed = 0;
+
+	if (p->old_link != p->phy->link) {
+		status_changed = 1;
+		p->old_link = p->phy->link;
+	}
+
+	if (p->old_duplex != p->phy->duplex) {
+		status_changed = 1;
+		p->old_duplex = p->phy->duplex;
+	}
+
+	if (p->old_pause != p->phy->pause) {
+		status_changed = 1;
+		p->old_pause = p->phy->pause;
+	}
+
+	if (status_changed)
+		phy_print_status(p->phy);
+}
+
 /* slave device setup *******************************************************/
+static void 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->pd;
+	struct device_node *phy_dn, *port_dn;
+	int ret;
+
+	port_dn = cd->port_dn[p->port];
+	p->phy_interface = of_get_phy_mode(port_dn);
+
+	phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
+	if (of_phy_is_fixed_link(port_dn)) {
+		/* In the case of a fixed PHY, the DT node associated
+		 * to the fixed PHY is the Port DT node
+		 */
+		ret = of_phy_register_fixed_link(port_dn);
+		if (ret) {
+			pr_err("failed to register fixed PHY\n");
+			return;
+		}
+		phy_dn = port_dn;
+	}
+
+	if (phy_dn)
+		p->phy = of_phy_connect(slave_dev, phy_dn,
+					dsa_slave_adjust_link, 0,
+					p->phy_interface);
+
+	/* We could not connect to a designated PHY, so use the switch internal
+	 * MDIO bus instead
+	 */
+	if (!p->phy)
+		p->phy = ds->slave_mii_bus->phy_map[p->port];
+	else
+		pr_info("attached PHY at address %d [%s]\n",
+			p->phy->addr, p->phy->drv->name);
+}
+
 struct net_device *
 dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 		 int port, char *name)
@@ -361,7 +426,12 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 	p->dev = slave_dev;
 	p->parent = ds;
 	p->port = port;
-	p->phy = ds->slave_mii_bus->phy_map[port];
+
+	p->old_pause = -1;
+	p->old_link = -1;
+	p->old_duplex = -1;
+
+	dsa_slave_phy_setup(p, slave_dev);
 
 	ret = register_netdev(slave_dev);
 	if (ret) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 07/13] net: dsa: allow switches to work without tagging
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (5 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 06/13] net: dsa: allow for more complex PHY setups Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 08/13] net: dsa: allow drivers to do link adjustment Florian Fainelli
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

In case switch port tagging is disabled (voluntarily, or the switch just
does not support it), allow us to continue using the defined set of
dsa_device_ops in net/dsa/slave.c.

We introduce dsa_protocol_is_tagged() to check whether we need to
override skb->protocol and go through the DSA-specifif packet_type
function, or if we just go on and receive the SKB through the normal
path.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v4:
- reworked logic to use dsa_device_ops introduced in patch 1
- added a helper to check for the switch protocol tag

Changes in v3:
- update logic with the helpers introduced in the firs patch set
- renamed dummy to notag

 include/linux/netdevice.h |  6 +++---
 include/net/dsa.h         |  5 +++++
 net/dsa/slave.c           | 19 ++++++++++++++++++-
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1875dc71422a..429801370d0c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1784,10 +1784,10 @@ void dev_net_set(struct net_device *dev, struct net *net)
 static inline bool netdev_uses_dsa(struct net_device *dev)
 {
 #ifdef CONFIG_NET_DSA
-	return dev->dsa_ptr != NULL;
-#else
-	return false;
+	if (dev->dsa_ptr != NULL)
+		return dsa_uses_tagged_protocol(dev->dsa_ptr);
 #endif
+	return false;
 }
 
 /**
diff --git a/include/net/dsa.h b/include/net/dsa.h
index dc357454ae3b..1035f6452d79 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -198,4 +198,9 @@ static inline void *ds_to_priv(struct dsa_switch *ds)
 	return (void *)(ds + 1);
 }
 
+static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
+{
+	return dst->tag_protocol != 0;
+}
+
 #endif
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 03d2894a0f8a..241c2a1684cb 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -181,6 +181,17 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
 	return dst->ops->xmit(skb, dev);
 }
 
+static netdev_tx_t dsa_slave_notag_xmit(struct sk_buff *skb,
+					struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+
+	skb->dev = p->parent->dst->master_netdev;
+	dev_queue_xmit(skb);
+
+	return NETDEV_TX_OK;
+}
+
 
 /* ethtool operations *******************************************************/
 static int
@@ -314,6 +325,11 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
 	.ndo_do_ioctl		= dsa_slave_ioctl,
 };
 
+static const struct dsa_device_ops notag_netdev_ops = {
+	.xmit	= dsa_slave_notag_xmit,
+	.rcv	= NULL,
+};
+
 static void dsa_slave_adjust_link(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
@@ -415,7 +431,8 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 		break;
 #endif
 	default:
-		BUG();
+		ds->dst->ops = &notag_netdev_ops;
+		break;
 	}
 
 	SET_NETDEV_DEV(slave_dev, parent);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 08/13] net: dsa: allow drivers to do link adjustment
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (6 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 07/13] net: dsa: allow switches to work without tagging Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 09/13] net: dsa: allow updating fixed PHY link information Florian Fainelli
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

Whenever libphy determines that the link status of a given PHY/port has
changed, allow to call into the switch driver link adjustment callback
so proper actions can be taken care of by the switch driver upon link
notification.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 include/net/dsa.h | 7 +++++++
 net/dsa/slave.c   | 4 ++++
 2 files changed, 11 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 1035f6452d79..2d3835924dd2 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -16,6 +16,7 @@
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/of.h>
+#include <linux/phy.h>
 
 #define DSA_MAX_SWITCHES	4
 #define DSA_MAX_PORTS		12
@@ -182,6 +183,12 @@ struct dsa_switch_driver {
 	void	(*poll_link)(struct dsa_switch *ds);
 
 	/*
+	 * Link state adjustment (called from libphy)
+	 */
+	void	(*adjust_link)(struct dsa_switch *ds, int port,
+				struct phy_device *phydev);
+
+	/*
 	 * ethtool hardware statistics.
 	 */
 	void	(*get_strings)(struct dsa_switch *ds, int port, uint8_t *data);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 241c2a1684cb..398d0663d3dd 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -333,6 +333,7 @@ static const struct dsa_device_ops notag_netdev_ops = {
 static void dsa_slave_adjust_link(struct net_device *dev)
 {
 	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
 	unsigned int status_changed = 0;
 
 	if (p->old_link != p->phy->link) {
@@ -350,6 +351,9 @@ static void dsa_slave_adjust_link(struct net_device *dev)
 		p->old_pause = p->phy->pause;
 	}
 
+	if (ds->drv->adjust_link && status_changed)
+		ds->drv->adjust_link(ds, p->port, p->phy);
+
 	if (status_changed)
 		phy_print_status(p->phy);
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 09/13] net: dsa: allow updating fixed PHY link information
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (7 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 08/13] net: dsa: allow drivers to do link adjustment Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 10/13] net: dsa: add Broadcom tag RX/TX handler Florian Fainelli
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

Allow switch drivers to hook a PHY link update callback to perform
port-specific link work.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v4:
- changed phy_is_fixed from 'unsigned int' to 'bool'

 include/net/dsa.h |  3 +++
 net/dsa/slave.c   | 17 +++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 2d3835924dd2..2c9563f0b2f4 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -17,6 +17,7 @@
 #include <linux/workqueue.h>
 #include <linux/of.h>
 #include <linux/phy.h>
+#include <linux/phy_fixed.h>
 
 #define DSA_MAX_SWITCHES	4
 #define DSA_MAX_PORTS		12
@@ -187,6 +188,8 @@ struct dsa_switch_driver {
 	 */
 	void	(*adjust_link)(struct dsa_switch *ds, int port,
 				struct phy_device *phydev);
+	void	(*fixed_link_update)(struct dsa_switch *ds, int port,
+				struct fixed_phy_status *st);
 
 	/*
 	 * ethtool hardware statistics.
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 398d0663d3dd..18ff53836fe3 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -358,6 +358,18 @@ static void dsa_slave_adjust_link(struct net_device *dev)
 		phy_print_status(p->phy);
 }
 
+static int dsa_slave_fixed_link_update(struct net_device *dev,
+				       struct fixed_phy_status *status)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
+
+	if (ds->drv->fixed_link_update)
+		ds->drv->fixed_link_update(ds, p->port, status);
+
+	return 0;
+}
+
 /* slave device setup *******************************************************/
 static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
 				struct net_device *slave_dev)
@@ -365,6 +377,7 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
 	struct dsa_switch *ds = p->parent;
 	struct dsa_chip_data *cd = ds->pd;
 	struct device_node *phy_dn, *port_dn;
+	bool phy_is_fixed = false;
 	int ret;
 
 	port_dn = cd->port_dn[p->port];
@@ -380,6 +393,7 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
 			pr_err("failed to register fixed PHY\n");
 			return;
 		}
+		phy_is_fixed = true;
 		phy_dn = port_dn;
 	}
 
@@ -388,6 +402,9 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
 					dsa_slave_adjust_link, 0,
 					p->phy_interface);
 
+	if (p->phy && phy_is_fixed)
+		fixed_phy_set_link_update(p->phy, dsa_slave_fixed_link_update);
+
 	/* We could not connect to a designated PHY, so use the switch internal
 	 * MDIO bus instead
 	 */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 10/13] net: dsa: add Broadcom tag RX/TX handler
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (8 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 09/13] net: dsa: allow updating fixed PHY link information Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 11/13] net: dsa: add Broadcom SF2 switch driver Florian Fainelli
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

Add support for the 4-bytes Broadcom tag that built-in switches such as
the Starfighter 2 might insert when receiving packets, or that we need
to insert while targetting specific switch ports. We use a fake
EtherType field for this 4-bytes switch tag: ETH_P_BRCMTAG to make sure
we can assign DSA-specific network operations.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v4:
- reworked changes to match the new dsa_device_ops introduced in patch 1

Changes in v3:
- add ETH_P_BRCMTAG as part of this changeset and not in a previous patch
- fixed an early de-reference in the receive hook

 include/uapi/linux/if_ether.h |   1 +
 net/dsa/Kconfig               |   3 +
 net/dsa/Makefile              |   1 +
 net/dsa/dsa_priv.h            |   3 +
 net/dsa/slave.c               |   5 ++
 net/dsa/tag_brcm.c            | 173 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 186 insertions(+)
 create mode 100644 net/dsa/tag_brcm.c

diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 0f8210b8e0bc..2e9f13768abd 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -128,6 +128,7 @@
 #define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
 #define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
 #define ETH_P_CAIF	0x00F7		/* ST-Ericsson CAIF protocol	*/
+#define ETH_P_BRCMTAG	0x00F8		/* Broadcom tag (4 bytes *)	*/
 
 /*
  *	This is an Ethernet frame header.
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index f5eede1d6cb8..a585fd6352eb 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -12,6 +12,9 @@ config NET_DSA
 if NET_DSA
 
 # tagging formats
+config NET_DSA_TAG_BRCM
+	bool
+
 config NET_DSA_TAG_DSA
 	bool
 
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 7b9fcbbeda5d..da06ed1df620 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA) += dsa_core.o
 dsa_core-y += dsa.o slave.o
 
 # tagging formats
+dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
 dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
 dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
 dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index d20364ac1574..98afed4d92ba 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -57,5 +57,8 @@ extern const struct dsa_device_ops edsa_netdev_ops;
 /* tag_trailer.c */
 extern const struct dsa_device_ops trailer_netdev_ops;
 
+/* tag_brcm.c */
+extern const struct dsa_device_ops brcm_netdev_ops;
+
 
 #endif
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 18ff53836fe3..7333a4aebb7d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -451,6 +451,11 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 		ds->dst->ops = &trailer_netdev_ops;
 		break;
 #endif
+#ifdef CONFIG_NET_DSA_TAG_BRCM
+	case htons(ETH_P_BRCMTAG):
+		ds->dst->ops = &brcm_netdev_ops;
+		break;
+#endif
 	default:
 		ds->dst->ops = &notag_netdev_ops;
 		break;
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
new file mode 100644
index 000000000000..e0b759ec209e
--- /dev/null
+++ b/net/dsa/tag_brcm.c
@@ -0,0 +1,173 @@
+/*
+ * Broadcom tag support
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include "dsa_priv.h"
+
+/* This tag length is 4 bytes, older ones were 6 bytes, we do not
+ * handle them
+ */
+#define BRCM_TAG_LEN	4
+
+/* Tag is constructed and desconstructed using byte by byte access
+ * because the tag is placed after the MAC Source Address, which does
+ * not make it 4-bytes aligned, so this might cause unaligned accesses
+ * on most systems where this is used.
+ */
+
+/* Ingress and egress opcodes */
+#define BRCM_OPCODE_SHIFT	5
+#define BRCM_OPCODE_MASK	0x7
+
+/* Ingress fields */
+/* 1st byte in the tag */
+#define BRCM_IG_TC_SHIFT	2
+#define BRCM_IG_TC_MASK		0x7
+/* 2nd byte in the tag */
+#define BRCM_IG_TE_MASK		0x3
+#define BRCM_IG_TS_SHIFT	7
+/* 3rd byte in the tag */
+#define BRCM_IG_DSTMAP2_MASK	1
+#define BRCM_IG_DSTMAP1_MASK	0xff
+
+/* Egress fields */
+
+/* 2nd byte in the tag */
+#define BRCM_EG_CID_MASK	0xff
+
+/* 3rd byte in the tag */
+#define BRCM_EG_RC_MASK		0xff
+#define  BRCM_EG_RC_RSVD	(3 << 6)
+#define  BRCM_EG_RC_EXCEPTION	(1 << 5)
+#define  BRCM_EG_RC_PROT_SNOOP	(1 << 4)
+#define  BRCM_EG_RC_PROT_TERM	(1 << 3)
+#define  BRCM_EG_RC_SWITCH	(1 << 2)
+#define  BRCM_EG_RC_MAC_LEARN	(1 << 1)
+#define  BRCM_EG_RC_MIRROR	(1 << 0)
+#define BRCM_EG_TC_SHIFT	5
+#define BRCM_EG_TC_MASK		0x7
+#define BRCM_EG_PID_MASK	0x1f
+
+static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	u8 *brcm_tag;
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
+		goto out_free;
+
+	skb_push(skb, BRCM_TAG_LEN);
+
+	memmove(skb->data, skb->data + BRCM_TAG_LEN, 2 * ETH_ALEN);
+
+	/* Build the tag after the MAC Source Address */
+	brcm_tag = skb->data + 2 * ETH_ALEN;
+
+	/* Set the ingress opcode, traffic class, tag enforcment is
+	 * deprecated
+	 */
+	brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
+			((skb->priority << BRCM_IG_TC_SHIFT) & BRCM_IG_TC_MASK);
+	brcm_tag[1] = 0;
+	brcm_tag[2] = 0;
+	if (p->port == 8)
+		brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
+	brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK;
+
+	/* Queue the SKB for transmission on the parent interface, but
+	 * do not modify its EtherType
+	 */
+	skb->protocol = htons(ETH_P_BRCMTAG);
+	skb->dev = p->parent->dst->master_netdev;
+	dev_queue_xmit(skb);
+
+	return NETDEV_TX_OK;
+
+out_free:
+	kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
+			struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct dsa_switch_tree *dst = dev->dsa_ptr;
+	struct dsa_switch *ds;
+	int source_port;
+	u8 *brcm_tag;
+
+	if (unlikely(dst == NULL))
+		goto out_drop;
+
+	ds = dst->ds[0];
+
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (skb == NULL)
+		goto out;
+
+	if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
+		goto out_drop;
+
+	/* skb->data points to the EtherType, the tag is right before it */
+	brcm_tag = skb->data - 2;
+
+	/* The opcode should never be different than 0b000 */
+	if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
+		goto out_drop;
+
+	/* We should never see a reserved reason code without knowing how to
+	 * handle it
+	 */
+	WARN_ON(brcm_tag[2] & BRCM_EG_RC_RSVD);
+
+	/* Locate which port this is coming from */
+	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)
+		goto out_drop;
+
+	/* Remove Broadcom tag and update checksum */
+	skb_pull_rcsum(skb, BRCM_TAG_LEN);
+
+	/* Move the Ethernet DA and SA */
+	memmove(skb->data - ETH_HLEN,
+		skb->data - ETH_HLEN - BRCM_TAG_LEN,
+		2 * ETH_ALEN);
+
+	skb_push(skb, ETH_HLEN);
+	skb->pkt_type = PACKET_HOST;
+	skb->dev = ds->ports[source_port];
+	skb->protocol = eth_type_trans(skb, skb->dev);
+
+	skb->dev->stats.rx_packets++;
+	skb->dev->stats.rx_bytes += skb->len;
+
+	netif_receive_skb(skb);
+
+	return 0;
+
+out_drop:
+	kfree_skb(skb);
+out:
+	return 0;
+}
+
+const struct dsa_device_ops brcm_netdev_ops = {
+	.xmit	= brcm_tag_xmit,
+	.rcv	= brcm_tag_rcv,
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 11/13] net: dsa: add Broadcom SF2 switch driver
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (9 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 10/13] net: dsa: add Broadcom tag RX/TX handler Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 12/13] Documentation: devicetree: update dsa binding with optional properties Florian Fainelli
  2014-08-26  4:49 ` [PATCH net-next v4 13/13] Documentation: devicetree: add Broadcom Starfighter 2 binding Florian Fainelli
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

Add support for the Broadcom Starfigther 2 switch chip using a DSA
driver. This switch driver supports the following features:

- configuration of the external switch port interface: MII, RevMII,
  RGMII and RGMII_NO_ID are supported
- support for the per-port MIB counters
- support for link interrupts for special ports (e.g: MoCA)
- powering up/down of switch memories to conserve power when ports are
  unused

Finally, update the compatible property for the DSA core code to match
our switch top-level compatible node.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v4:
- fixed typo on the word Starfighter
- fixed a few checkpatch.pl warnings

No changes in v3

Changes in v2:
- add support for reading to special MDIO phys (0 and 30)
- added more power down optimization
- added VLAN separation
 drivers/net/dsa/Kconfig        |  11 +
 drivers/net/dsa/Makefile       |   1 +
 drivers/net/dsa/bcm_sf2.c      | 626 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/bcm_sf2.h      | 140 +++++++++
 drivers/net/dsa/bcm_sf2_regs.h | 227 +++++++++++++++
 net/dsa/dsa.c                  |   1 +
 6 files changed, 1006 insertions(+)
 create mode 100644 drivers/net/dsa/bcm_sf2.c
 create mode 100644 drivers/net/dsa/bcm_sf2.h
 create mode 100644 drivers/net/dsa/bcm_sf2_regs.h

diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index b8fe808b7957..c6ee07c6a1b5 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -36,4 +36,15 @@ config NET_DSA_MV88E6123_61_65
 	  This enables support for the Marvell 88E6123/6161/6165
 	  ethernet switch chips.
 
+config NET_DSA_BCM_SF2
+	tristate "Broadcom Starfighter 2 Ethernet switch support"
+	select NET_DSA
+	select NET_DSA_TAG_BRCM
+	select FIXED_PHY if NET_DSA_BCM_SF2=y
+	select BCM7XXX_PHY
+	select MDIO_BCM_UNIMAC
+	---help---
+	  This enables support for the Broadcom Starfighter 2 Ethernet
+	  switch chips.
+
 endmenu
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index f3bda05536cc..dd3cd3b8157f 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -7,3 +7,4 @@ endif
 ifdef CONFIG_NET_DSA_MV88E6131
 mv88e6xxx_drv-y += mv88e6131.o
 endif
+obj-$(CONFIG_NET_DSA_BCM_SF2)	+= bcm_sf2.o
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
new file mode 100644
index 000000000000..bb7cb8e283b1
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -0,0 +1,626 @@
+/*
+ * Broadcom Starfighter 2 DSA switch driver
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/mii.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <net/dsa.h>
+
+#include "bcm_sf2.h"
+#include "bcm_sf2_regs.h"
+
+/* String, offset, and register size in bytes if different from 4 bytes */
+static const struct bcm_sf2_hw_stats bcm_sf2_mib[] = {
+	{ "TxOctets",		0x000, 8	},
+	{ "TxDropPkts",		0x020		},
+	{ "TxQPKTQ0",		0x030		},
+	{ "TxBroadcastPkts",	0x040		},
+	{ "TxMulticastPkts",	0x050		},
+	{ "TxUnicastPKts",	0x060		},
+	{ "TxCollisions",	0x070		},
+	{ "TxSingleCollision",	0x080		},
+	{ "TxMultipleCollision", 0x090		},
+	{ "TxDeferredCollision", 0x0a0		},
+	{ "TxLateCollision",	0x0b0		},
+	{ "TxExcessiveCollision", 0x0c0		},
+	{ "TxFrameInDisc",	0x0d0		},
+	{ "TxPausePkts",	0x0e0		},
+	{ "TxQPKTQ1",		0x0f0		},
+	{ "TxQPKTQ2",		0x100		},
+	{ "TxQPKTQ3",		0x110		},
+	{ "TxQPKTQ4",		0x120		},
+	{ "TxQPKTQ5",		0x130		},
+	{ "RxOctets",		0x140, 8	},
+	{ "RxUndersizePkts",	0x160		},
+	{ "RxPausePkts",	0x170		},
+	{ "RxPkts64Octets",	0x180		},
+	{ "RxPkts65to127Octets", 0x190		},
+	{ "RxPkts128to255Octets", 0x1a0		},
+	{ "RxPkts256to511Octets", 0x1b0		},
+	{ "RxPkts512to1023Octets", 0x1c0	},
+	{ "RxPkts1024toMaxPktsOctets", 0x1d0	},
+	{ "RxOversizePkts",	0x1e0		},
+	{ "RxJabbers",		0x1f0		},
+	{ "RxAlignmentErrors",	0x200		},
+	{ "RxFCSErrors",	0x210		},
+	{ "RxGoodOctets",	0x220, 8	},
+	{ "RxDropPkts",		0x240		},
+	{ "RxUnicastPkts",	0x250		},
+	{ "RxMulticastPkts",	0x260		},
+	{ "RxBroadcastPkts",	0x270		},
+	{ "RxSAChanges",	0x280		},
+	{ "RxFragments",	0x290		},
+	{ "RxJumboPkt",		0x2a0		},
+	{ "RxSymblErr",		0x2b0		},
+	{ "InRangeErrCount",	0x2c0		},
+	{ "OutRangeErrCount",	0x2d0		},
+	{ "EEELpiEvent",	0x2e0		},
+	{ "EEELpiDuration",	0x2f0		},
+	{ "RxDiscard",		0x300, 8	},
+	{ "TxQPKTQ6",		0x320		},
+	{ "TxQPKTQ7",		0x330		},
+	{ "TxPkts64Octets",	0x340		},
+	{ "TxPkts65to127Octets", 0x350		},
+	{ "TxPkts128to255Octets", 0x360		},
+	{ "TxPkts256to511Ocets", 0x370		},
+	{ "TxPkts512to1023Ocets", 0x380		},
+	{ "TxPkts1024toMaxPktOcets", 0x390	},
+};
+
+#define BCM_SF2_STATS_SIZE	ARRAY_SIZE(bcm_sf2_mib)
+
+static void bcm_sf2_sw_get_strings(struct dsa_switch *ds,
+				   int port, uint8_t *data)
+{
+	unsigned int i;
+
+	for (i = 0; i < BCM_SF2_STATS_SIZE; i++)
+		memcpy(data + i * ETH_GSTRING_LEN,
+		       bcm_sf2_mib[i].string, ETH_GSTRING_LEN);
+}
+
+static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds,
+					 int port, uint64_t *data)
+{
+	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	const struct bcm_sf2_hw_stats *s;
+	unsigned int i;
+	u64 val = 0;
+	u32 offset;
+
+	mutex_lock(&priv->stats_mutex);
+
+	/* Now fetch the per-port counters */
+	for (i = 0; i < BCM_SF2_STATS_SIZE; i++) {
+		s = &bcm_sf2_mib[i];
+
+		/* Do a latched 64-bit read if needed */
+		offset = s->reg + CORE_P_MIB_OFFSET(port);
+		if (s->sizeof_stat == 8)
+			val = core_readq(priv, offset);
+		else
+			val = core_readl(priv, offset);
+
+		data[i] = (u64)val;
+	}
+
+	mutex_unlock(&priv->stats_mutex);
+}
+
+static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds)
+{
+	return BCM_SF2_STATS_SIZE;
+}
+
+static char *bcm_sf2_sw_probe(struct mii_bus *bus, int sw_addr)
+{
+	return "Broadcom Starfighter 2";
+}
+
+static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
+{
+	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	unsigned int i;
+	u32 reg, val;
+
+	/* Enable the port memories */
+	reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+	reg &= ~P_TXQ_PSM_VDD(port);
+	core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+
+	/* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
+	reg = core_readl(priv, CORE_IMP_CTL);
+	reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);
+	reg &= ~(RX_DIS | TX_DIS);
+	core_writel(priv, reg, CORE_IMP_CTL);
+
+	/* Enable forwarding */
+	core_writel(priv, SW_FWDG_EN, CORE_SWMODE);
+
+	/* Enable IMP port in dumb mode */
+	reg = core_readl(priv, CORE_SWITCH_CTRL);
+	reg |= MII_DUMB_FWDG_EN;
+	core_writel(priv, reg, CORE_SWITCH_CTRL);
+
+	/* Resolve which bit controls the Broadcom tag */
+	switch (port) {
+	case 8:
+		val = BRCM_HDR_EN_P8;
+		break;
+	case 7:
+		val = BRCM_HDR_EN_P7;
+		break;
+	case 5:
+		val = BRCM_HDR_EN_P5;
+		break;
+	default:
+		val = 0;
+		break;
+	}
+
+	/* Enable Broadcom tags for IMP port */
+	reg = core_readl(priv, CORE_BRCM_HDR_CTRL);
+	reg |= val;
+	core_writel(priv, reg, CORE_BRCM_HDR_CTRL);
+
+	/* Enable reception Broadcom tag for CPU TX (switch RX) to
+	 * allow us to tag outgoing frames
+	 */
+	reg = core_readl(priv, CORE_BRCM_HDR_RX_DIS);
+	reg &= ~(1 << port);
+	core_writel(priv, reg, CORE_BRCM_HDR_RX_DIS);
+
+	/* Enable transmission of Broadcom tags from the switch (CPU RX) to
+	 * allow delivering frames to the per-port net_devices
+	 */
+	reg = core_readl(priv, CORE_BRCM_HDR_TX_DIS);
+	reg &= ~(1 << port);
+	core_writel(priv, reg, CORE_BRCM_HDR_TX_DIS);
+
+	/* Force link status for IMP port */
+	reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);
+	reg |= (MII_SW_OR | LINK_STS);
+	core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
+
+	/* Enable the IMP Port to be in the same VLAN as the other ports
+	 * on a per-port basis such that we only have Port i and IMP in
+	 * the same VLAN.
+	 */
+	for (i = 0; i < priv->hw_params.num_ports; i++) {
+		if (!((1 << i) & ds->phys_port_mask))
+			continue;
+
+		reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
+		reg |= (1 << port);
+		core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
+	}
+}
+
+static void bcm_sf2_port_setup(struct dsa_switch *ds, int port)
+{
+	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	u32 reg;
+
+	/* Clear the memory power down */
+	reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+	reg &= ~P_TXQ_PSM_VDD(port);
+	core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+
+	/* Clear the Rx and Tx disable bits and set to no spanning tree */
+	core_writel(priv, 0, CORE_G_PCTL_PORT(port));
+
+	/* Enable port 7 interrupts to get notified */
+	if (port == 7)
+		intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
+
+	/* Set this port, and only this one to be in the default VLAN */
+	reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
+	reg &= ~PORT_VLAN_CTRL_MASK;
+	reg |= (1 << port);
+	core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port));
+}
+
+static void bcm_sf2_port_disable(struct dsa_switch *ds, int port)
+{
+	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	u32 off, reg;
+
+	if (dsa_is_cpu_port(ds, port))
+		off = CORE_IMP_CTL;
+	else
+		off = CORE_G_PCTL_PORT(port);
+
+	reg = core_readl(priv, off);
+	reg |= RX_DIS | TX_DIS;
+	core_writel(priv, reg, off);
+
+	/* Power down the port memory */
+	reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+	reg |= P_TXQ_PSM_VDD(port);
+	core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+}
+
+static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
+{
+	struct bcm_sf2_priv *priv = dev_id;
+
+	priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &
+				~priv->irq0_mask;
+	intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id)
+{
+	struct bcm_sf2_priv *priv = dev_id;
+
+	priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) &
+				~priv->irq1_mask;
+	intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
+
+	if (priv->irq1_stat & P_LINK_UP_IRQ(P7_IRQ_OFF))
+		priv->port_sts[7].link = 1;
+	if (priv->irq1_stat & P_LINK_DOWN_IRQ(P7_IRQ_OFF))
+		priv->port_sts[7].link = 0;
+
+	return IRQ_HANDLED;
+}
+
+static int bcm_sf2_sw_setup(struct dsa_switch *ds)
+{
+	const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
+	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	struct device_node *dn;
+	void __iomem **base;
+	unsigned int port;
+	unsigned int i;
+	u32 reg, rev;
+	int ret;
+
+	spin_lock_init(&priv->indir_lock);
+	mutex_init(&priv->stats_mutex);
+
+	/* All the interesting properties are at the parent device_node
+	 * level
+	 */
+	dn = ds->pd->of_node->parent;
+
+	priv->irq0 = irq_of_parse_and_map(dn, 0);
+	priv->irq1 = irq_of_parse_and_map(dn, 1);
+
+	base = &priv->core;
+	for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
+		*base = of_iomap(dn, i);
+		if (*base == NULL) {
+			pr_err("unable to find register: %s\n", reg_names[i]);
+			return -ENODEV;
+		}
+		base++;
+	}
+
+	/* Disable all interrupts and request them */
+	intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+	intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+	intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+	intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+	intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+	intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+
+	ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0,
+			  "switch_0", priv);
+	if (ret < 0) {
+		pr_err("failed to request switch_0 IRQ\n");
+		goto out_unmap;
+	}
+
+	ret = request_irq(priv->irq1, bcm_sf2_switch_1_isr, 0,
+			  "switch_1", priv);
+	if (ret < 0) {
+		pr_err("failed to request switch_1 IRQ\n");
+		goto out_free_irq0;
+	}
+
+	/* Reset the MIB counters */
+	reg = core_readl(priv, CORE_GMNCFGCFG);
+	reg |= RST_MIB_CNT;
+	core_writel(priv, reg, CORE_GMNCFGCFG);
+	reg &= ~RST_MIB_CNT;
+	core_writel(priv, reg, CORE_GMNCFGCFG);
+
+	/* Get the maximum number of ports for this switch */
+	priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;
+	if (priv->hw_params.num_ports > DSA_MAX_PORTS)
+		priv->hw_params.num_ports = DSA_MAX_PORTS;
+
+	/* Assume a single GPHY setup if we can't read that property */
+	if (of_property_read_u32(dn, "brcm,num-gphy",
+				 &priv->hw_params.num_gphy))
+		priv->hw_params.num_gphy = 1;
+
+	/* Enable all valid ports and disable those unused */
+	for (port = 0; port < priv->hw_params.num_ports; port++) {
+		/* IMP port receives special treatment */
+		if ((1 << port) & ds->phys_port_mask)
+			bcm_sf2_port_setup(ds, port);
+		else if (dsa_is_cpu_port(ds, port))
+			bcm_sf2_imp_setup(ds, port);
+		else
+			bcm_sf2_port_disable(ds, port);
+	}
+
+	/* Include the pseudo-PHY address and the broadcast PHY address to
+	 * divert reads towards our workaround
+	 */
+	ds->phys_mii_mask |= ((1 << 30) | (1 << 0));
+
+	rev = reg_readl(priv, REG_SWITCH_REVISION);
+	priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
+					SWITCH_TOP_REV_MASK;
+	priv->hw_params.core_rev = (rev & SF2_REV_MASK);
+
+	pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
+		priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
+		priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
+		priv->core, priv->irq0, priv->irq1);
+
+	return 0;
+
+out_free_irq0:
+	free_irq(priv->irq0, priv);
+out_unmap:
+	base = &priv->core;
+	for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
+		iounmap(*base);
+		base++;
+	}
+	return ret;
+}
+
+static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
+{
+	return 0;
+}
+
+static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr,
+			       int regnum, u16 val)
+{
+	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	int ret = 0;
+	u32 reg;
+
+	reg = reg_readl(priv, REG_SWITCH_CNTRL);
+	reg |= MDIO_MASTER_SEL;
+	reg_writel(priv, reg, REG_SWITCH_CNTRL);
+
+	/* Page << 8 | offset */
+	reg = 0x70;
+	reg <<= 2;
+	core_writel(priv, addr, reg);
+
+	/* Page << 8 | offset */
+	reg = 0x80 << 8 | regnum << 1;
+	reg <<= 2;
+
+	if (op)
+		ret = core_readl(priv, reg);
+	else
+		core_writel(priv, val, reg);
+
+	reg = reg_readl(priv, REG_SWITCH_CNTRL);
+	reg &= ~MDIO_MASTER_SEL;
+	reg_writel(priv, reg, REG_SWITCH_CNTRL);
+
+	return ret & 0xffff;
+}
+
+static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum)
+{
+	/* Intercept reads from the MDIO broadcast address or Broadcom
+	 * pseudo-PHY address
+	 */
+	switch (addr) {
+	case 0:
+	case 30:
+		return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0);
+	default:
+		return 0xffff;
+	}
+}
+
+static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum,
+				u16 val)
+{
+	/* Intercept writes to the MDIO broadcast address or Broadcom
+	 * pseudo-PHY address
+	 */
+	switch (addr) {
+	case 0:
+	case 30:
+		bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val);
+		break;
+	}
+
+	return 0;
+}
+
+static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port,
+				   struct phy_device *phydev)
+{
+	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	u32 id_mode_dis = 0, port_mode;
+	const char *str = NULL;
+	u32 reg;
+
+	switch (phydev->interface) {
+	case PHY_INTERFACE_MODE_RGMII:
+		str = "RGMII (no delay)";
+		id_mode_dis = 1;
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		if (!str)
+			str = "RGMII (TX delay)";
+		port_mode = EXT_GPHY;
+		break;
+	case PHY_INTERFACE_MODE_MII:
+		str = "MII";
+		port_mode = EXT_EPHY;
+		break;
+	case PHY_INTERFACE_MODE_REVMII:
+		str = "Reverse MII";
+		port_mode = EXT_REVMII;
+		break;
+	default:
+		goto force_link;
+	}
+
+	/* Clear id_mode_dis bit, and the existing port mode, but
+	 * make sure we enable the RGMII block for data to pass
+	 */
+	reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+	reg &= ~ID_MODE_DIS;
+	reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
+	reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
+
+	reg |= port_mode | RGMII_MODE_EN;
+	if (id_mode_dis)
+		reg |= ID_MODE_DIS;
+
+	if (phydev->pause) {
+		if (phydev->asym_pause)
+			reg |= TX_PAUSE_EN;
+		reg |= RX_PAUSE_EN;
+	}
+
+	reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+
+	pr_info("Port %d configured for %s\n", port, str);
+
+force_link:
+	/* Force link settings detected from the PHY */
+	reg = SW_OVERRIDE;
+	switch (phydev->speed) {
+	case SPEED_1000:
+		reg |= SPDSTS_1000 << SPEED_SHIFT;
+		break;
+	case SPEED_100:
+		reg |= SPDSTS_100 << SPEED_SHIFT;
+		break;
+	}
+
+	if (phydev->link)
+		reg |= LINK_STS;
+	if (phydev->duplex == DUPLEX_FULL)
+		reg |= DUPLX_MODE;
+
+	core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
+}
+
+static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
+					 struct fixed_phy_status *status)
+{
+	struct bcm_sf2_priv *priv = ds_to_priv(ds);
+	u32 link, duplex, pause, speed;
+	u32 reg;
+
+	link = core_readl(priv, CORE_LNKSTS);
+	duplex = core_readl(priv, CORE_DUPSTS);
+	pause = core_readl(priv, CORE_PAUSESTS);
+	speed = core_readl(priv, CORE_SPDSTS);
+
+	speed >>= (port * SPDSTS_SHIFT);
+	speed &= SPDSTS_MASK;
+
+	status->link = 0;
+
+	/* Port 7 is special as we do not get link status from CORE_LNKSTS,
+	 * which means that we need to force the link at the port override
+	 * level to get the data to flow. We do use what the interrupt handler
+	 * did determine before.
+	 */
+	if (port == 7) {
+		status->link = priv->port_sts[port].link;
+		reg = core_readl(priv, CORE_STS_OVERRIDE_GMIIP_PORT(7));
+		reg |= SW_OVERRIDE;
+		if (status->link)
+			reg |= LINK_STS;
+		else
+			reg &= ~LINK_STS;
+		core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(7));
+		status->duplex = 1;
+	} else {
+		status->link = !!(link & (1 << port));
+		status->duplex = !!(duplex & (1 << port));
+	}
+
+	switch (speed) {
+	case SPDSTS_10:
+		status->speed = SPEED_10;
+		break;
+	case SPDSTS_100:
+		status->speed = SPEED_100;
+		break;
+	case SPDSTS_1000:
+		status->speed = SPEED_1000;
+		break;
+	}
+
+	if ((pause & (1 << port)) &&
+	    (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) {
+		status->asym_pause = 1;
+		status->pause = 1;
+	}
+
+	if (pause & (1 << port))
+		status->pause = 1;
+}
+
+static struct dsa_switch_driver bcm_sf2_switch_driver = {
+	.tag_protocol		= htons(ETH_P_BRCMTAG),
+	.priv_size		= sizeof(struct bcm_sf2_priv),
+	.probe			= bcm_sf2_sw_probe,
+	.setup			= bcm_sf2_sw_setup,
+	.set_addr		= bcm_sf2_sw_set_addr,
+	.phy_read		= bcm_sf2_sw_phy_read,
+	.phy_write		= bcm_sf2_sw_phy_write,
+	.get_strings		= bcm_sf2_sw_get_strings,
+	.get_ethtool_stats	= bcm_sf2_sw_get_ethtool_stats,
+	.get_sset_count		= bcm_sf2_sw_get_sset_count,
+	.adjust_link		= bcm_sf2_sw_adjust_link,
+	.fixed_link_update	= bcm_sf2_sw_fixed_link_update,
+};
+
+static int __init bcm_sf2_init(void)
+{
+	register_switch_driver(&bcm_sf2_switch_driver);
+
+	return 0;
+}
+module_init(bcm_sf2_init);
+
+static void __exit bcm_sf2_exit(void)
+{
+	unregister_switch_driver(&bcm_sf2_switch_driver);
+}
+module_exit(bcm_sf2_exit);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:brcm-sf2");
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
new file mode 100644
index 000000000000..260bab313e58
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -0,0 +1,140 @@
+/*
+ * Broadcom Starfighter2 private context
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __BCM_SF2_H
+#define __BCM_SF2_H
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/mii.h>
+
+#include <net/dsa.h>
+
+#include "bcm_sf2_regs.h"
+
+struct bcm_sf2_hw_params {
+	u16	top_rev;
+	u16	core_rev;
+	u32	num_gphy;
+	u8	num_acb_queue;
+	u8	num_rgmii;
+	u8	num_ports;
+	u8	fcb_pause_override:1;
+	u8	acb_packets_inflight:1;
+};
+
+#define BCM_SF2_REGS_NAME {\
+	"core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb" \
+}
+
+#define BCM_SF2_REGS_NUM	6
+
+struct bcm_sf2_port_status {
+	unsigned int link;
+};
+
+struct bcm_sf2_priv {
+	/* Base registers, keep those in order with BCM_SF2_REGS_NAME */
+	void __iomem			*core;
+	void __iomem			*reg;
+	void __iomem			*intrl2_0;
+	void __iomem			*intrl2_1;
+	void __iomem			*fcb;
+	void __iomem			*acb;
+
+	/* spinlock protecting access to the indirect registers */
+	spinlock_t			indir_lock;
+
+	int				irq0;
+	int				irq1;
+	u32				irq0_stat;
+	u32				irq0_mask;
+	u32				irq1_stat;
+	u32				irq1_mask;
+
+	/* Mutex protecting access to the MIB counters */
+	struct mutex			stats_mutex;
+
+	struct bcm_sf2_hw_params	hw_params;
+
+	struct bcm_sf2_port_status	port_sts[DSA_MAX_PORTS];
+};
+
+struct bcm_sf2_hw_stats {
+	const char	*string;
+	u16		reg;
+	u8		sizeof_stat;
+};
+
+#define SF2_IO_MACRO(name) \
+static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off)	\
+{									\
+	return __raw_readl(priv->name + off);				\
+}									\
+static inline void name##_writel(struct bcm_sf2_priv *priv,		\
+				  u32 val, u32 off)			\
+{									\
+	__raw_writel(val, priv->name + off);				\
+}									\
+
+/* Accesses to 64-bits register requires us to latch the hi/lo pairs
+ * using the REG_DIR_DATA_{READ,WRITE} ancillary registers. The 'indir_lock'
+ * spinlock is automatically grabbed and released to provide relative
+ * atomiticy with latched reads/writes.
+ */
+#define SF2_IO64_MACRO(name) \
+static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off)	\
+{									\
+	u32 indir, dir;							\
+	spin_lock(&priv->indir_lock);					\
+	indir = reg_readl(priv, REG_DIR_DATA_READ);			\
+	dir = __raw_readl(priv->name + off);				\
+	spin_unlock(&priv->indir_lock);					\
+	return (u64)indir << 32 | dir;					\
+}									\
+static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off,	\
+							u64 val)	\
+{									\
+	spin_lock(&priv->indir_lock);					\
+	reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE);	\
+	__raw_writel(lower_32_bits(val), priv->name + off);		\
+	spin_unlock(&priv->indir_lock);					\
+}
+
+#define SWITCH_INTR_L2(which)						\
+static inline void intrl2_##which##_mask_clear(struct bcm_sf2_priv *priv, \
+						u32 mask)		\
+{									\
+	intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);	\
+	priv->irq##which##_mask &= ~(mask);				\
+}									\
+static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \
+						u32 mask)		\
+{									\
+	intrl2_## which##_writel(priv, mask, INTRL2_CPU_MASK_SET);	\
+	priv->irq##which##_mask |= (mask);				\
+}									\
+
+SF2_IO_MACRO(core);
+SF2_IO_MACRO(reg);
+SF2_IO64_MACRO(core);
+SF2_IO_MACRO(intrl2_0);
+SF2_IO_MACRO(intrl2_1);
+SF2_IO_MACRO(fcb);
+SF2_IO_MACRO(acb);
+
+SWITCH_INTR_L2(0);
+SWITCH_INTR_L2(1);
+
+#endif /* __BCM_SF2_H */
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
new file mode 100644
index 000000000000..885c231b03b5
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -0,0 +1,227 @@
+/*
+ * Broadcom Starfighter 2 switch register defines
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __BCM_SF2_REGS_H
+#define __BCM_SF2_REGS_H
+
+/* Register set relative to 'REG' */
+#define REG_SWITCH_CNTRL		0x00
+#define  MDIO_MASTER_SEL		(1 << 0)
+
+#define REG_SWITCH_STATUS		0x04
+#define REG_DIR_DATA_WRITE		0x08
+#define REG_DIR_DATA_READ		0x0C
+
+#define REG_SWITCH_REVISION		0x18
+#define  SF2_REV_MASK			0xffff
+#define  SWITCH_TOP_REV_SHIFT		16
+#define  SWITCH_TOP_REV_MASK		0xffff
+
+#define REG_PHY_REVISION		0x1C
+
+#define REG_SPHY_CNTRL			0x2C
+#define  IDDQ_BIAS			(1 << 0)
+#define  EXT_PWR_DOWN			(1 << 1)
+#define  FORCE_DLL_EN			(1 << 2)
+#define  IDDQ_GLOBAL_PWR		(1 << 3)
+#define  CK25_DIS			(1 << 4)
+#define  PHY_RESET			(1 << 5)
+#define  PHY_PHYAD_SHIFT		8
+#define  PHY_PHYAD_MASK			0x1F
+
+#define REG_RGMII_0_BASE		0x34
+#define REG_RGMII_CNTRL			0x00
+#define REG_RGMII_IB_STATUS		0x04
+#define REG_RGMII_RX_CLOCK_DELAY_CNTRL	0x08
+#define REG_RGMII_CNTRL_SIZE		0x0C
+#define REG_RGMII_CNTRL_P(x)		(REG_RGMII_0_BASE + \
+					((x) * REG_RGMII_CNTRL_SIZE))
+/* Relative to REG_RGMII_CNTRL */
+#define  RGMII_MODE_EN			(1 << 0)
+#define  ID_MODE_DIS			(1 << 1)
+#define  PORT_MODE_SHIFT		2
+#define  INT_EPHY			(0 << PORT_MODE_SHIFT)
+#define  INT_GPHY			(1 << PORT_MODE_SHIFT)
+#define  EXT_EPHY			(2 << PORT_MODE_SHIFT)
+#define  EXT_GPHY			(3 << PORT_MODE_SHIFT)
+#define  EXT_REVMII			(4 << PORT_MODE_SHIFT)
+#define  PORT_MODE_MASK			0x7
+#define  RVMII_REF_SEL			(1 << 5)
+#define  RX_PAUSE_EN			(1 << 6)
+#define  TX_PAUSE_EN			(1 << 7)
+#define  TX_CLK_STOP_EN			(1 << 8)
+#define  LPI_COUNT_SHIFT		9
+#define  LPI_COUNT_MASK			0x3F
+
+/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
+#define INTRL2_CPU_STATUS		0x00
+#define INTRL2_CPU_SET			0x04
+#define INTRL2_CPU_CLEAR		0x08
+#define INTRL2_CPU_MASK_STATUS		0x0c
+#define INTRL2_CPU_MASK_SET		0x10
+#define INTRL2_CPU_MASK_CLEAR		0x14
+
+/* Shared INTRL2_0 and INTRL2_ interrupt sources macros */
+#define P_LINK_UP_IRQ(x)		(1 << (0 + (x)))
+#define P_LINK_DOWN_IRQ(x)		(1 << (1 + (x)))
+#define P_ENERGY_ON_IRQ(x)		(1 << (2 + (x)))
+#define P_ENERGY_OFF_IRQ(x)		(1 << (3 + (x)))
+#define P_GPHY_IRQ(x)			(1 << (4 + (x)))
+#define P_NUM_IRQ			5
+#define P_IRQ_MASK(x)			(P_LINK_UP_IRQ((x)) | \
+					 P_LINK_DOWN_IRQ((x)) | \
+					 P_ENERGY_ON_IRQ((x)) | \
+					 P_ENERGY_OFF_IRQ((x)) | \
+					 P_GPHY_IRQ((x)))
+
+/* INTRL2_0 interrupt sources */
+#define P0_IRQ_OFF			0
+#define MEM_DOUBLE_IRQ			(1 << 5)
+#define EEE_LPI_IRQ			(1 << 6)
+#define P5_CPU_WAKE_IRQ			(1 << 7)
+#define P8_CPU_WAKE_IRQ			(1 << 8)
+#define P7_CPU_WAKE_IRQ			(1 << 9)
+#define IEEE1588_IRQ			(1 << 10)
+#define MDIO_ERR_IRQ			(1 << 11)
+#define MDIO_DONE_IRQ			(1 << 12)
+#define GISB_ERR_IRQ			(1 << 13)
+#define UBUS_ERR_IRQ			(1 << 14)
+#define FAILOVER_ON_IRQ			(1 << 15)
+#define FAILOVER_OFF_IRQ		(1 << 16)
+#define TCAM_SOFT_ERR_IRQ		(1 << 17)
+
+/* INTRL2_1 interrupt sources */
+#define P7_IRQ_OFF			0
+#define P_IRQ_OFF(x)			((6 - (x)) * P_NUM_IRQ)
+
+/* Register set relative to 'CORE' */
+#define CORE_G_PCTL_PORT0		0x00000
+#define CORE_G_PCTL_PORT(x)		(CORE_G_PCTL_PORT0 + (x * 0x4))
+#define CORE_IMP_CTL			0x00020
+#define  RX_DIS				(1 << 0)
+#define  TX_DIS				(1 << 1)
+#define  RX_BCST_EN			(1 << 2)
+#define  RX_MCST_EN			(1 << 3)
+#define  RX_UCST_EN			(1 << 4)
+#define  G_MISTP_STATE_SHIFT		5
+#define  G_MISTP_NO_STP			(0 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_DIS_STATE		(1 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_BLOCK_STATE		(2 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_LISTEN_STATE		(3 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_LEARN_STATE		(4 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_FWD_STATE		(5 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_STATE_MASK		0x7
+
+#define CORE_SWMODE			0x0002c
+#define  SW_FWDG_MODE			(1 << 0)
+#define  SW_FWDG_EN			(1 << 1)
+#define  RTRY_LMT_DIS			(1 << 2)
+
+#define CORE_STS_OVERRIDE_IMP		0x00038
+#define  GMII_SPEED_UP_2G		(1 << 6)
+#define  MII_SW_OR			(1 << 7)
+
+#define CORE_NEW_CTRL			0x00084
+#define  IP_MC				(1 << 0)
+#define  OUTRANGEERR_DISCARD		(1 << 1)
+#define  INRANGEERR_DISCARD		(1 << 2)
+#define  CABLE_DIAG_LEN			(1 << 3)
+#define  OVERRIDE_AUTO_PD_WAR		(1 << 4)
+#define  EN_AUTO_PD_WAR			(1 << 5)
+#define  UC_FWD_EN			(1 << 6)
+#define  MC_FWD_EN			(1 << 7)
+
+#define CORE_SWITCH_CTRL		0x00088
+#define  MII_DUMB_FWDG_EN		(1 << 6)
+
+#define CORE_SFT_LRN_CTRL		0x000f8
+#define  SW_LEARN_CNTL(x)		(1 << (x))
+
+#define CORE_STS_OVERRIDE_GMIIP_PORT(x)	(0x160 + (x) * 4)
+#define  LINK_STS			(1 << 0)
+#define  DUPLX_MODE			(1 << 1)
+#define  SPEED_SHIFT			2
+#define  SPEED_MASK			0x3
+#define  RXFLOW_CNTL			(1 << 4)
+#define  TXFLOW_CNTL			(1 << 5)
+#define  SW_OVERRIDE			(1 << 6)
+
+#define CORE_WATCHDOG_CTRL		0x001e4
+#define  SOFTWARE_RESET			(1 << 7)
+#define  EN_CHIP_RST			(1 << 6)
+#define  EN_SW_RESET			(1 << 4)
+
+#define CORE_LNKSTS			0x00400
+#define  LNK_STS_MASK			0x1ff
+
+#define CORE_SPDSTS			0x00410
+#define  SPDSTS_10			0
+#define  SPDSTS_100			1
+#define  SPDSTS_1000			2
+#define  SPDSTS_SHIFT			2
+#define  SPDSTS_MASK			0x3
+
+#define CORE_DUPSTS			0x00420
+#define  CORE_DUPSTS_MASK		0x1ff
+
+#define CORE_PAUSESTS			0x00428
+#define  PAUSESTS_TX_PAUSE_SHIFT	9
+
+#define CORE_GMNCFGCFG			0x0800
+#define  RST_MIB_CNT			(1 << 0)
+#define  RXBPDU_EN			(1 << 1)
+
+#define CORE_IMP0_PRT_ID		0x0804
+
+#define CORE_BRCM_HDR_CTRL		0x0080c
+#define  BRCM_HDR_EN_P8			(1 << 0)
+#define  BRCM_HDR_EN_P5			(1 << 1)
+#define  BRCM_HDR_EN_P7			(1 << 2)
+
+#define CORE_BRCM_HDR_CTRL2		0x0828
+
+#define CORE_HL_PRTC_CTRL		0x0940
+#define  ARP_EN				(1 << 0)
+#define  RARP_EN			(1 << 1)
+#define  DHCP_EN			(1 << 2)
+#define  ICMPV4_EN			(1 << 3)
+#define  ICMPV6_EN			(1 << 4)
+#define  ICMPV6_FWD_MODE		(1 << 5)
+#define  IGMP_DIP_EN			(1 << 8)
+#define  IGMP_RPTLVE_EN			(1 << 9)
+#define  IGMP_RTPLVE_FWD_MODE		(1 << 10)
+#define  IGMP_QRY_EN			(1 << 11)
+#define  IGMP_QRY_FWD_MODE		(1 << 12)
+#define  IGMP_UKN_EN			(1 << 13)
+#define  IGMP_UKN_FWD_MODE		(1 << 14)
+#define  MLD_RPTDONE_EN			(1 << 15)
+#define  MLD_RPTDONE_FWD_MODE		(1 << 16)
+#define  MLD_QRY_EN			(1 << 17)
+#define  MLD_QRY_FWD_MODE		(1 << 18)
+
+#define CORE_RST_MIB_CNT_EN		0x0950
+
+#define CORE_BRCM_HDR_RX_DIS		0x0980
+#define CORE_BRCM_HDR_TX_DIS		0x0988
+
+#define CORE_MEM_PSM_VDD_CTRL		0x2380
+#define  P_TXQ_PSM_VDD_SHIFT		2
+#define  P_TXQ_PSM_VDD_MASK		0x3
+#define  P_TXQ_PSM_VDD(x)		(P_TXQ_PSM_VDD_MASK << \
+					((x) * P_TXQ_PSM_VDD_SHIFT))
+
+#define	CORE_P0_MIB_OFFSET		0x8000
+#define P_MIB_SIZE			0x400
+#define CORE_P_MIB_OFFSET(x)		(CORE_P0_MIB_OFFSET + (x) * P_MIB_SIZE)
+
+#define CORE_PORT_VLAN_CTL_PORT(x)	(0xc400 + ((x) * 0x8))
+#define  PORT_VLAN_CTRL_MASK		0x1ff
+
+#endif /* __BCM_SF2_REGS_H */
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 03b0d9221d35..95f5cd66633e 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -635,6 +635,7 @@ struct packet_type dsa_pack_type __read_mostly = {
 };
 
 static const struct of_device_id dsa_of_match_table[] = {
+	{ .compatible = "brcm,bcm7445-switch-v4.0" },
 	{ .compatible = "marvell,dsa", },
 	{}
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 12/13] Documentation: devicetree: update dsa binding with optional properties
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (10 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 11/13] net: dsa: add Broadcom SF2 switch driver Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  2014-08-26 22:40   ` Sergei Shtylyov
  2014-08-26  4:49 ` [PATCH net-next v4 13/13] Documentation: devicetree: add Broadcom Starfighter 2 binding Florian Fainelli
  12 siblings, 1 reply; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

Add documentation for a bunch of new optional properties described in
ethernet.txt and fixed-link.txt, this includes: 'phy-handle', 'phy-mode'
and the 'fixed-link' subnode.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 Documentation/devicetree/bindings/net/dsa/dsa.txt | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt
index 49f4f7ae3f51..6192f9a7aa89 100644
--- a/Documentation/devicetree/bindings/net/dsa/dsa.txt
+++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt
@@ -39,6 +39,22 @@ Optionnal property:
 			  This property is only used when switches are being
 			  chained/cascaded together.
 
+- phy-handle		: Phandle to a PHY on an external MDIO bus, not the
+			  switch internal one. See
+			  Documentation/devicetree/bindings/net/ethernet.txt
+			  for details.
+
+- phy-mode		: String representing the connection to the designeted
+			  PHY node specified by the 'phy-handle' property. See
+			  Documentation/devicetree/bindings/net/ethernet.txt
+			  for details.
+
+Optionnal subnodes:
+- 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:
 
 	dsa@0 {
@@ -58,6 +74,7 @@ Example:
 			port@0 {
 				reg = <0>;
 				label = "lan1";
+				phy-handle = <&phy0>;
 			};
 
 			port@1 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v4 13/13] Documentation: devicetree: add Broadcom Starfighter 2 binding
  2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
                   ` (11 preceding siblings ...)
  2014-08-26  4:49 ` [PATCH net-next v4 12/13] Documentation: devicetree: update dsa binding with optional properties Florian Fainelli
@ 2014-08-26  4:49 ` Florian Fainelli
  12 siblings, 0 replies; 19+ messages in thread
From: Florian Fainelli @ 2014-08-26  4:49 UTC (permalink / raw)
  To: netdev; +Cc: Florian Fainelli, davem, linville, jhs, alexander.duyck

Add the binding documentation for the Broadcom Starfighter 2 integrated
switch hardware.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 .../devicetree/bindings/net/broadcom-sf2.txt       | 78 ++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/broadcom-sf2.txt

diff --git a/Documentation/devicetree/bindings/net/broadcom-sf2.txt b/Documentation/devicetree/bindings/net/broadcom-sf2.txt
new file mode 100644
index 000000000000..30d487597ecb
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/broadcom-sf2.txt
@@ -0,0 +1,78 @@
+* Broadcom Starfighter 2 integrated swich
+
+Required properties:
+
+- compatible: should be "brcm,bcm7445-switch-v4.0"
+- reg: addresses and length of the register sets for the device, must be 6
+  pairs of register addresses and lengths
+- interrupts: interrupts for the devices, must be two interrupts
+- dsa,mii-bus: phandle to the MDIO bus controller, see dsa/dsa.txt
+- dsa,ethernet: phandle to the CPU network interface controller, see dsa/dsa.txt
+- #size-cells: must be 0
+- #address-cells: must be 2, see dsa/dsa.txt
+
+Subnodes:
+
+The integrated switch subnode should be specified according to the binding
+described in dsa/dsa.txt.
+
+Optional properties:
+
+- reg-names: litteral names for the device base register addresses, when present
+  must be: "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb"
+
+- interrupt-names: litternal names for the device interrupt lines, when present
+  must be: "switch_0" and "switch_1"
+
+- brcm,num-gphy: specify the maximum number of integrated gigabit PHYs in the
+  switch
+
+- brcm,num-rgmii-ports: specify the maximum number of RGMII interfaces supported
+  by the switch
+
+- brcm,fcb-pause-override: boolean property, if present indicates that the switch
+  supports Failover Control Block pause override capability
+
+- brcm,acb-packets-inflight: boolean property, if present indicates that the switch
+  Admission Control Block supports reporting the number of packets in-flight in a
+  switch queue
+
+Example:
+
+switch_top@f0b00000 {
+	compatible = "simple-bus";
+	#size-cells = <1>;
+	#address-cells = <1>;
+	ranges = <0 0xf0b00000 0x40804>;
+
+	ethernet_switch@0 {
+		compatible = "brcm,bcm7445-switch-v4.0";
+		#size-cells = <0>;
+		#address-cells = <2>;
+		reg = <0x0 0x40000
+			0x40000 0x110
+			0x40340 0x30
+			0x40380 0x30
+			0x40400 0x34
+			0x40600 0x208>;
+		interrupts = <0 0x18 0
+				0 0x19 0>;
+		brcm,num-gphy = <1>;
+		brcm,num-rgmii-ports = <2>;
+		brcm,fcb-pause-override;
+		brcm,acb-packets-inflight;
+
+		...
+		switch@0 {
+			reg = <0 0>;
+			#size-cells = <0>;
+			#address-cells <1>;
+
+			port@0 {
+				label = "gphy";
+				reg = <0>;
+			};
+			...
+		};
+	};
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v4 12/13] Documentation: devicetree: update dsa binding with optional properties
  2014-08-26  4:49 ` [PATCH net-next v4 12/13] Documentation: devicetree: update dsa binding with optional properties Florian Fainelli
@ 2014-08-26 22:40   ` Sergei Shtylyov
  0 siblings, 0 replies; 19+ messages in thread
From: Sergei Shtylyov @ 2014-08-26 22:40 UTC (permalink / raw)
  To: Florian Fainelli, netdev; +Cc: davem, linville, jhs, alexander.duyck

Hello.

On 08/26/2014 08:49 AM, Florian Fainelli wrote:

> Add documentation for a bunch of new optional properties described in
> ethernet.txt and fixed-link.txt, this includes: 'phy-handle', 'phy-mode'
> and the 'fixed-link' subnode.

> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
>   Documentation/devicetree/bindings/net/dsa/dsa.txt | 17 +++++++++++++++++
>   1 file changed, 17 insertions(+)

> diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt
> index 49f4f7ae3f51..6192f9a7aa89 100644
> --- a/Documentation/devicetree/bindings/net/dsa/dsa.txt
> +++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt
> @@ -39,6 +39,22 @@ Optionnal property:
>   			  This property is only used when switches are being
>   			  chained/cascaded together.
>
> +- phy-handle		: Phandle to a PHY on an external MDIO bus, not the
> +			  switch internal one. See
> +			  Documentation/devicetree/bindings/net/ethernet.txt
> +			  for details.
> +
> +- phy-mode		: String representing the connection to the designeted

    Designated?

> +			  PHY node specified by the 'phy-handle' property. See
> +			  Documentation/devicetree/bindings/net/ethernet.txt
> +			  for details.
> +
> +Optionnal subnodes:

    One 'n' is enough (although DaveM may disagree ;-).

WBR, Sergei

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks
  2014-08-26  4:49 ` [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks Florian Fainelli
@ 2014-08-27 15:25   ` Alexander Duyck
  2014-08-27 23:24     ` David Miller
  0 siblings, 1 reply; 19+ messages in thread
From: Alexander Duyck @ 2014-08-27 15:25 UTC (permalink / raw)
  To: Florian Fainelli, netdev; +Cc: davem, linville, jhs, alexander.duyck

On 08/25/2014 09:49 PM, Florian Fainelli wrote:
> DSA is currently registering one packet_type function per EtherType it
> needs to intercept in the receive path of a DSA-enabled Ethernet device.
> Right now we have three of them: trailer, DSA and eDSA, and there might
> be more in the future, this will not scale to the addition of new
> protocols.
> 
> This patch proceeds with adding a new layer of abstraction and two new
> functions:
> 
> dsa_switch_rcv() which will dispatch into the tag-protocol specific
> receive function implemented by net/dsa/tag_*.c
> 
> dsa_slave_xmit() which will dispatch into the tag-protocol specific
> transmit function implemented by net/dsa/tag_*.c
> 
> When we do create the per-port slave network devices, we iterate over
> the switch protocol to assign the DSA-specific receive and transmit
> operations.
> 
> This allows us to greatly simplify the check in eth_type_trans() and
> always override the skb->protocol with ETH_P_DSA for Ethernet switches
> tagged protocol, while also reducing the number repetitive slave
> netdevice_ops assignments.
> 
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> Changes in v4:
> - introduce a level of indirection and dsa_device_ops to limit the
>   number of packet_type functions to just one and do the dispatching
>   in the core dsa code.
> 
> New patch in v3
> 

Just a thought, you might want to consider using a protocol value other
than ETH_P_DSA.  Maybe we should add a new value named ETH_P_XDSA for
this approach since what we are doing is a multiplexed DSA protocol now.

This would allow for much easier back-porting of this if needed and also
prevents us from possibly triggering any issues if there are any
user-space APIs that might be trying to capture packets based on the
protocol value.

Thanks,

Alex

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks
  2014-08-27 15:25   ` Alexander Duyck
@ 2014-08-27 23:24     ` David Miller
  2014-08-27 23:43       ` Florian Fainelli
  0 siblings, 1 reply; 19+ messages in thread
From: David Miller @ 2014-08-27 23:24 UTC (permalink / raw)
  To: alexander.h.duyck; +Cc: f.fainelli, netdev, linville, jhs, alexander.duyck

From: Alexander Duyck <alexander.h.duyck@intel.com>
Date: Wed, 27 Aug 2014 08:25:45 -0700

> Just a thought, you might want to consider using a protocol value other
> than ETH_P_DSA.  Maybe we should add a new value named ETH_P_XDSA for
> this approach since what we are doing is a multiplexed DSA protocol now.
> 
> This would allow for much easier back-porting of this if needed and also
> prevents us from possibly triggering any issues if there are any
> user-space APIs that might be trying to capture packets based on the
> protocol value.

Agreed, Florian can you respin this patch set using a newly allocated
ETH_P_* value for these new semantics?

Thanks.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks
  2014-08-27 23:24     ` David Miller
@ 2014-08-27 23:43       ` Florian Fainelli
  2014-08-28  1:49         ` Alexander Duyck
  0 siblings, 1 reply; 19+ messages in thread
From: Florian Fainelli @ 2014-08-27 23:43 UTC (permalink / raw)
  To: David Miller, alexander.h.duyck; +Cc: netdev, linville, jhs, alexander.duyck

On 08/27/2014 04:24 PM, David Miller wrote:
> From: Alexander Duyck <alexander.h.duyck@intel.com>
> Date: Wed, 27 Aug 2014 08:25:45 -0700
> 
>> Just a thought, you might want to consider using a protocol value other
>> than ETH_P_DSA.  Maybe we should add a new value named ETH_P_XDSA for
>> this approach since what we are doing is a multiplexed DSA protocol now.
>>
>> This would allow for much easier back-porting of this if needed and also
>> prevents us from possibly triggering any issues if there are any
>> user-space APIs that might be trying to capture packets based on the
>> protocol value.
> 
> Agreed, Florian can you respin this patch set using a newly allocated
> ETH_P_* value for these new semantics?

Absolutely. While at it, I just realized that ETH_P_BRCMTAG should
probably remain within include/net/dsa.h. We don't want that to be
exported to user-space since it is used for internal DSA de-multiplexing.

Stay tuned!
--
Florian

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks
  2014-08-27 23:43       ` Florian Fainelli
@ 2014-08-28  1:49         ` Alexander Duyck
  0 siblings, 0 replies; 19+ messages in thread
From: Alexander Duyck @ 2014-08-28  1:49 UTC (permalink / raw)
  To: Florian Fainelli, David Miller, alexander.h.duyck; +Cc: netdev, linville, jhs

On 08/27/2014 04:43 PM, Florian Fainelli wrote:
> On 08/27/2014 04:24 PM, David Miller wrote:
>> From: Alexander Duyck <alexander.h.duyck@intel.com>
>> Date: Wed, 27 Aug 2014 08:25:45 -0700
>>
>>> Just a thought, you might want to consider using a protocol value other
>>> than ETH_P_DSA.  Maybe we should add a new value named ETH_P_XDSA for
>>> this approach since what we are doing is a multiplexed DSA protocol now.
>>>
>>> This would allow for much easier back-porting of this if needed and also
>>> prevents us from possibly triggering any issues if there are any
>>> user-space APIs that might be trying to capture packets based on the
>>> protocol value.
>> Agreed, Florian can you respin this patch set using a newly allocated
>> ETH_P_* value for these new semantics?
> Absolutely. While at it, I just realized that ETH_P_BRCMTAG should
> probably remain within include/net/dsa.h. We don't want that to be
> exported to user-space since it is used for internal DSA de-multiplexing.
>
> Stay tuned!
> --
> Florian
>

Actually you could probably simplify this all a bit more by replacing
the ETH_P_BRCMTAG and tag_protcol values with a simple enum/u16 instead
of having to use be16 values.  It would make things a bit more explicit
as well since you could specify something like DSA_TAG_NONE = 0.

If you can't get to it I will probably work on submitting a patch for it
next week.

Thanks,

Alex

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2014-08-28  1:49 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-26  4:49 [PATCH net-next v4 00/13] dsa: Broadcom Starfighter 2 switch support Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 01/13] net: dsa: reduce number of protocol hooks Florian Fainelli
2014-08-27 15:25   ` Alexander Duyck
2014-08-27 23:24     ` David Miller
2014-08-27 23:43       ` Florian Fainelli
2014-08-28  1:49         ` Alexander Duyck
2014-08-26  4:49 ` [PATCH net-next v4 02/13] net: phy: add generic UniMAC MDIO bus driver Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 03/13] net: phy: provide stub for fixed_phy_set_link_update Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 04/13] net: dsa: provide a switch device device tree node pointer Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 05/13] net: dsa: retain a per-port device_node pointer Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 06/13] net: dsa: allow for more complex PHY setups Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 07/13] net: dsa: allow switches to work without tagging Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 08/13] net: dsa: allow drivers to do link adjustment Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 09/13] net: dsa: allow updating fixed PHY link information Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 10/13] net: dsa: add Broadcom tag RX/TX handler Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 11/13] net: dsa: add Broadcom SF2 switch driver Florian Fainelli
2014-08-26  4:49 ` [PATCH net-next v4 12/13] Documentation: devicetree: update dsa binding with optional properties Florian Fainelli
2014-08-26 22:40   ` Sergei Shtylyov
2014-08-26  4:49 ` [PATCH net-next v4 13/13] Documentation: devicetree: add Broadcom Starfighter 2 binding Florian Fainelli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).