Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1177091 > unrolled thread

[PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table Unit

Started byVivien Didelot <vivien.didelot@savoirfairelinux.com>
First post2015-07-06 04:20 +0200
Last post2015-07-07 18:30 +0200
Articles 9 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table Unit Vivien Didelot <vivien.didelot@savoirfairelinux.com> - 2015-07-06 04:20 +0200
    [PATCH v3 2/3] net: dsa: add support for switchdev VLAN objects Vivien Didelot <vivien.didelot@savoirfairelinux.com> - 2015-07-06 04:20 +0200
    [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU Vivien Didelot <vivien.didelot@savoirfairelinux.com> - 2015-07-06 04:20 +0200
      Re: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for  VTU Guenter Roeck <linux@roeck-us.net> - 2015-07-07 18:20 +0200
      Re: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for  VTU Vivien Didelot <vivien.didelot@savoirfairelinux.com> - 2015-07-07 18:20 +0200
      Re: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU Andrew Lunn <andrew@lunn.ch> - 2015-07-07 18:20 +0200
    [PATCH v3 3/3] net: dsa: mv88e6xxx: add switchdev VLAN operations Vivien Didelot <vivien.didelot@savoirfairelinux.com> - 2015-07-06 04:20 +0200
    Re: [PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table  Unit Vivien Didelot <vivien.didelot@savoirfairelinux.com> - 2015-07-07 18:20 +0200
      Re: [PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table  Unit Andrew Lunn <andrew@lunn.ch> - 2015-07-07 18:30 +0200

#1177091 — [PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table Unit

FromVivien Didelot <vivien.didelot@savoirfairelinux.com>
Date2015-07-06 04:20 +0200
Subject[PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table Unit
Message-ID<pJ4aJ-2gZ-3@gated-at.bofh.it>
Hi all,

This patchset brings full support for hardware VLANs in DSA, and the Marvell
88E6xxx compatible switch chips.

The first patch adds the VTU operations to the mv88e6xxx code, as well as a
"vtu" debugfs file to read and modify the hardware VLAN table.

The second patch adds the glue between DSA and the switchdev VLAN objects.

The third patch finally implements the necessary functions in the mv88e6xxx
code to interact with the hardware VLAN through switchdev, from userspace
commands such as "bridge vlan".

Below is an example of what can be done with this patchset.

    "VID 550: 1t 3u"
    "VID 1000: 2t"
    "VID 1200: 2t 4t"

The VLAN setup above can be achieved with the following bridge commands:

    bridge vlan add vid 550 dev swp1 master
    bridge vlan add vid 550 dev swp3 master untagged pvid
    bridge vlan add vid 1000 dev swp2 master
    bridge vlan add vid 1200 dev swp2 master
    bridge vlan add vid 1200 dev swp4 master

Removing the port 1 from VLAN 550 is done with:

    bridge vlan del vid 550 dev swp1

The bridge command would output the following setup:

    # bridge vlan
    port	vlan ids
    swp0	None
    swp0
    swp1	None
    swp1
    swp2	1000
		1200

    swp2	1000
		1200

    swp3	550 PVID Egress Untagged

    swp3	550 PVID Egress Untagged

    swp4	1200

    swp4	1200

    br0	None

Assuming that swp5 is the CPU port, the "vtu" debugfs file would show:

    # cat /sys/kernel/debug/dsa0/vtu
    VID  FID  SID  0  1  2  3  4  5  6
    550  550  0    x  x  x  u  x  t  x
    1000 1000 0    x  x  t  x  x  t  x
    1200 1200 0    x  x  t  x  t  t  x

Cheers,
  -v


Vivien Didelot (3):
  net: dsa: mv88e6xxx: add debugfs interface for VTU
  net: dsa: add support for switchdev VLAN objects
  net: dsa: mv88e6xxx: add switchdev VLAN operations

 drivers/net/dsa/mv88e6123_61_65.c |   3 +
 drivers/net/dsa/mv88e6131.c       |   3 +
 drivers/net/dsa/mv88e6171.c       |   3 +
 drivers/net/dsa/mv88e6352.c       |   3 +
 drivers/net/dsa/mv88e6xxx.c       | 463 ++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx.h       |  29 +++
 include/net/dsa.h                 |   9 +
 net/dsa/dsa_priv.h                |   6 +
 net/dsa/slave.c                   | 137 +++++++++++
 9 files changed, 656 insertions(+)

-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1177092 — [PATCH v3 2/3] net: dsa: add support for switchdev VLAN objects

FromVivien Didelot <vivien.didelot@savoirfairelinux.com>
Date2015-07-06 04:20 +0200
Subject[PATCH v3 2/3] net: dsa: add support for switchdev VLAN objects
Message-ID<pJ4aJ-2gZ-7@gated-at.bofh.it>
In reply to#1177091
This patch adds the glue between DSA and switchdev operations to add,
delete and dump SWITCHDEV_OBJ_PORT_VLAN objects.

This is a first step to link the "bridge vlan" command with hardware
entries for DSA compatible switch chips.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 include/net/dsa.h  |   9 ++++
 net/dsa/dsa_priv.h |   6 +++
 net/dsa/slave.c    | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 152 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index fbca63b..cabf2a5 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -302,6 +302,15 @@ struct dsa_switch_driver {
 			   const unsigned char *addr, u16 vid);
 	int	(*fdb_getnext)(struct dsa_switch *ds, int port,
 			       unsigned char *addr, bool *is_static);
+
+	/*
+	 * VLAN support
+	 */
+	int	(*port_vlan_add)(struct dsa_switch *ds, int port, u16 vid,
+				 u16 bridge_flags);
+	int	(*port_vlan_del)(struct dsa_switch *ds, int port, u16 vid);
+	int	(*port_vlan_dump)(struct dsa_switch *ds, int port, u16 vid,
+				  u16 *bridge_flags);
 };
 
 void register_switch_driver(struct dsa_switch_driver *type);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index d5f1f9b..9029717 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -13,6 +13,7 @@
 
 #include <linux/phy.h>
 #include <linux/netdevice.h>
+#include <linux/if_vlan.h>
 
 struct dsa_device_ops {
 	netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev);
@@ -47,6 +48,11 @@ struct dsa_slave_priv {
 	int			old_duplex;
 
 	struct net_device	*bridge_dev;
+
+	/*
+	 * Which VLANs this port is a member of.
+	 */
+	DECLARE_BITMAP(vlan_bitmap, VLAN_N_VID);
 };
 
 /* dsa.c */
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 04ffad3..47c459b 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -18,6 +18,7 @@
 #include <net/rtnetlink.h>
 #include <net/switchdev.h>
 #include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
 #include "dsa_priv.h"
 
 /* slave mii_bus handling ***************************************************/
@@ -363,6 +364,136 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
 	return ret;
 }
 
+static int dsa_slave_port_vlans_add(struct net_device *dev,
+				     struct switchdev_obj *obj)
+{
+	struct switchdev_obj_vlan *vlan = &obj->u.vlan;
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
+	int vid, err = 0;
+
+	if (!ds->drv->port_vlan_add)
+		return -EOPNOTSUPP;
+
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
+		err = ds->drv->port_vlan_add(ds, p->port, vid, vlan->flags);
+		if (err)
+			break;
+		set_bit(vid, p->vlan_bitmap);
+	}
+
+	return err;
+}
+
+static int dsa_slave_port_obj_add(struct net_device *dev,
+				  struct switchdev_obj *obj)
+{
+	int err;
+
+	/*
+	 * Skip the prepare phase, since currently the DSA drivers don't need to
+	 * allocate any memory for operations and they will not fail to HW
+	 * (unless something horrible goes wrong on the MDIO bus, in which case
+	 * the prepare phase wouldn't have been able to predict anyway).
+	 */
+	if (obj->trans != SWITCHDEV_TRANS_COMMIT)
+		return 0;
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_PORT_VLAN:
+		err = dsa_slave_port_vlans_add(dev, obj);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static int dsa_slave_port_vlans_del(struct net_device *dev,
+				     struct switchdev_obj *obj)
+{
+	struct switchdev_obj_vlan *vlan = &obj->u.vlan;
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
+	int vid, err = 0;
+
+	if (!ds->drv->port_vlan_del)
+		return -EOPNOTSUPP;
+
+	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
+		err = ds->drv->port_vlan_del(ds, p->port, vid);
+		if (err)
+			break;
+		clear_bit(vid, p->vlan_bitmap);
+	}
+
+	return err;
+}
+
+static int dsa_slave_port_obj_del(struct net_device *dev,
+				  struct switchdev_obj *obj)
+{
+	int err;
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_PORT_VLAN:
+		err = dsa_slave_port_vlans_del(dev, obj);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static int dsa_slave_port_vlans_dump(struct net_device *dev,
+				     struct switchdev_obj *obj)
+{
+	struct switchdev_obj_vlan *vlan = &obj->u.vlan;
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	struct dsa_switch *ds = p->parent;
+	int vid, err = 0;
+
+	if (!ds->drv->port_vlan_dump)
+		return -EOPNOTSUPP;
+
+	for_each_set_bit(vid, p->vlan_bitmap, VLAN_N_VID) {
+		u16 flags = 0;
+
+		err = ds->drv->port_vlan_dump(ds, p->port, vid, &flags);
+		if (err)
+			break;
+
+		vlan->flags = flags;
+		vlan->vid_begin = vlan->vid_end = vid;
+		err = obj->cb(dev, obj);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+static int dsa_slave_port_obj_dump(struct net_device *dev,
+				   struct switchdev_obj *obj)
+{
+	int err;
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_PORT_VLAN:
+		err = dsa_slave_port_vlans_dump(dev, obj);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
 static int dsa_slave_bridge_port_join(struct net_device *dev,
 				      struct net_device *br)
 {
@@ -697,11 +828,17 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
 	.ndo_fdb_dump		= dsa_slave_fdb_dump,
 	.ndo_do_ioctl		= dsa_slave_ioctl,
 	.ndo_get_iflink		= dsa_slave_get_iflink,
+	.ndo_bridge_getlink	= switchdev_port_bridge_getlink,
+	.ndo_bridge_setlink	= switchdev_port_bridge_setlink,
+	.ndo_bridge_dellink	= switchdev_port_bridge_dellink,
 };
 
 static const struct switchdev_ops dsa_slave_switchdev_ops = {
 	.switchdev_port_attr_get	= dsa_slave_port_attr_get,
 	.switchdev_port_attr_set	= dsa_slave_port_attr_set,
+	.switchdev_port_obj_add		= dsa_slave_port_obj_add,
+	.switchdev_port_obj_del		= dsa_slave_port_obj_del,
+	.switchdev_port_obj_dump	= dsa_slave_port_obj_dump,
 };
 
 static void dsa_slave_adjust_link(struct net_device *dev)
-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1177093 — [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU

FromVivien Didelot <vivien.didelot@savoirfairelinux.com>
Date2015-07-06 04:20 +0200
Subject[PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU
Message-ID<pJ4aJ-2gZ-1@gated-at.bofh.it>
In reply to#1177091
Implement the Get Next and Load Purge operations for the VLAN Table
Unit, and a "vtu" debugfs file to read and write the hardware VLANs.

A populated VTU look like this:

    # cat /sys/kernel/debug/dsa0/vtu
     VID  FID  SID  0  1  2  3  4  5  6
     550  562    0  x  x  x  u  x  t  x
    1000 1012    0  x  x  t  x  x  t  x
    1200 1212    0  x  x  t  x  t  t  x

Where "t", "u", "x", "-", respectively means that the port is tagged,
untagged, excluded or unmodified, for a given VLAN entry.

VTU entries can be added by echoing the same format:

    echo 1300 1312 0 x x t x t t x > vtu

and can be deleted by echoing only the VID:

    echo 1000 > vtu

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 311 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx.h |  24 ++++
 2 files changed, 335 insertions(+)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 8c130c0..ffd9fc6 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2,6 +2,9 @@
  * net/dsa/mv88e6xxx.c - Marvell 88e6xxx switch chip support
  * Copyright (c) 2008 Marvell Semiconductor
  *
+ * Copyright (c) 2015 CMC Electronics, Inc.
+ *	Added support for 802.1Q VLAN Table Unit
+ *
  * 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
@@ -1366,6 +1369,181 @@ static void mv88e6xxx_bridge_work(struct work_struct *work)
 	}
 }
 
+static int _mv88e6xxx_vtu_wait(struct dsa_switch *ds)
+{
+	return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_VTU_OP,
+			       GLOBAL_VTU_OP_BUSY);
+}
+
+static int _mv88e6xxx_vtu_cmd(struct dsa_switch *ds, u16 op)
+{
+	int ret;
+
+	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_OP, op);
+	if (ret < 0)
+		return ret;
+
+	return _mv88e6xxx_vtu_wait(ds);
+}
+
+static int _mv88e6xxx_stu_loadpurge(struct dsa_switch *ds, u8 sid, bool valid)
+{
+	int ret, data;
+
+	ret = _mv88e6xxx_vtu_wait(ds);
+	if (ret < 0)
+		return ret;
+
+	data = sid & GLOBAL_VTU_SID_MASK;
+	if (valid)
+		data |= GLOBAL_VTU_VID_VALID;
+
+	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID, data);
+	if (ret < 0)
+		return ret;
+
+	/* Unused (yet) data registers */
+	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_DATA_0_3, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_DATA_4_7, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_DATA_8_11, 0);
+	if (ret < 0)
+		return ret;
+
+	return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_LOAD_PURGE);
+}
+
+static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds, u16 vid,
+				  struct mv88e6xxx_vtu_entry *entry)
+{
+	int ret, i;
+
+	ret = _mv88e6xxx_vtu_wait(ds);
+	if (ret < 0)
+		return ret;
+
+	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID,
+				   vid & GLOBAL_VTU_VID_MASK);
+	if (ret < 0)
+		return ret;
+
+	ret = _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_GET_NEXT);
+	if (ret < 0)
+		return ret;
+
+	ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_VID);
+	if (ret < 0)
+		return ret;
+
+	entry->vid = ret & GLOBAL_VTU_VID_MASK;
+	entry->valid = !!(ret & GLOBAL_VTU_VID_VALID);
+
+	if (entry->valid) {
+		/* Ports 0-3, offsets 0, 4, 8, 12 */
+		ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_DATA_0_3);
+		if (ret < 0)
+			return ret;
+
+		for (i = 0; i < 4; ++i)
+			entry->tags[i] = (ret >> (i * 4)) & 3;
+
+		/* Ports 4-6, offsets 0, 4, 8 */
+		ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_DATA_4_7);
+		if (ret < 0)
+			return ret;
+
+		for (i = 4; i < 7; ++i)
+			entry->tags[i] = (ret >> ((i - 4) * 4)) & 3;
+
+		if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
+		    mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
+			ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
+						  GLOBAL_VTU_FID);
+			if (ret < 0)
+				return ret;
+
+			entry->fid = ret & GLOBAL_VTU_FID_MASK;
+
+			ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
+						  GLOBAL_VTU_SID);
+			if (ret < 0)
+				return ret;
+
+			entry->sid = ret & GLOBAL_VTU_SID_MASK;
+		} else {
+			entry->fid = 0;
+			entry->sid = 0;
+		}
+	}
+
+	return 0;
+}
+
+static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
+				    struct mv88e6xxx_vtu_entry *entry)
+{
+	u16 data = 0;
+	int ret, i;
+
+	ret = _mv88e6xxx_vtu_wait(ds);
+	if (ret < 0)
+		return ret;
+
+	if (entry->valid) {
+		/* Set Data Register, ports 0-3, offsets 0, 4, 8, 12 */
+		for (data = i = 0; i < 4; ++i)
+			data |= entry->tags[i] << (i * 4);
+		ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_DATA_0_3,
+					   data);
+		if (ret < 0)
+			return ret;
+
+		/* Set Data Register, ports 4-6, offsets 0, 4, 8 */
+		for (data = 0, i = 4; i < 7; ++i)
+			data |= entry->tags[i] << ((i - 4) * 4);
+		ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_DATA_4_7,
+					   data);
+		if (ret < 0)
+			return ret;
+
+		/* Unused Data Register */
+		ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_DATA_8_11,
+					   0);
+		if (ret < 0)
+			return ret;
+
+		if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
+		    mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
+			data = entry->sid & GLOBAL_VTU_SID_MASK;
+			ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL,
+						   GLOBAL_VTU_SID, data);
+			if (ret < 0)
+				return ret;
+
+			data = entry->fid & GLOBAL_VTU_FID_MASK;
+			ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL,
+						   GLOBAL_VTU_FID, data);
+			if (ret < 0)
+				return ret;
+		}
+
+		/* Valid bit set means load, unset means purge */
+		data = GLOBAL_VTU_VID_VALID;
+	}
+
+	data |= entry->vid & GLOBAL_VTU_VID_MASK;
+	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID, data);
+	if (ret < 0)
+		return ret;
+
+	return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_LOAD_PURGE);
+}
+
 static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
@@ -1739,6 +1917,136 @@ static const struct file_operations mv88e6xxx_atu_fops = {
 	.owner  = THIS_MODULE,
 };
 
+static int mv88e6xxx_vtu_show(struct seq_file *s, void *p)
+{
+	struct dsa_switch *ds = s->private;
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	int port, ret = 0, vid = 0xfff; /* find the first or lowest VID */
+
+	seq_puts(s, " VID  FID  SID");
+	for (port = 0; port < ps->num_ports; ++port)
+		seq_printf(s, " %2d", port);
+	seq_puts(s, "\n");
+
+	mutex_lock(&ps->smi_mutex);
+
+	do {
+		struct mv88e6xxx_vtu_entry next = { 0 };
+
+		ret = _mv88e6xxx_vtu_getnext(ds, vid, &next);
+		if (ret < 0)
+			goto unlock;
+
+		if (!next.valid)
+			break;
+
+		seq_printf(s, "%4d %4d   %2d", next.vid, next.fid, next.sid);
+		for (port = 0; port < ps->num_ports; ++port) {
+			switch (next.tags[port]) {
+			case GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED:
+				seq_puts(s, "  -");
+				break;
+			case GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED:
+				seq_puts(s, "  u");
+				break;
+			case GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED:
+				seq_puts(s, "  t");
+				break;
+			case GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER:
+				seq_puts(s, "  x");
+				break;
+			default:
+				seq_puts(s, "  ?");
+				break;
+			}
+		}
+		seq_puts(s, "\n");
+
+		vid = next.vid;
+	} while (vid < 0xfff);
+
+unlock:
+	mutex_unlock(&ps->smi_mutex);
+
+	return ret;
+}
+
+static ssize_t mv88e6xxx_vtu_write(struct file *file, const char __user *buf,
+				   size_t count, loff_t *ppos)
+{
+	struct seq_file *s = file->private_data;
+	struct dsa_switch *ds = s->private;
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	struct mv88e6xxx_vtu_entry entry = { 0 };
+	bool valid = true;
+	char tags[12]; /* DSA_MAX_PORTS */
+	int vid, fid, sid, port, ret;
+
+	/* scan 12 chars instead of num_ports to avoid dynamic scanning... */
+	ret = sscanf(buf, "%d %d %d %c %c %c %c %c %c %c %c %c %c %c %c", &vid,
+		     &fid, &sid, &tags[0], &tags[1], &tags[2], &tags[3],
+		     &tags[4], &tags[5], &tags[6], &tags[7], &tags[8], &tags[9],
+		     &tags[10], &tags[11]);
+	if (ret == 1)
+		valid = false;
+	else if (ret != 3 + ps->num_ports)
+		return -EINVAL;
+
+	entry.vid = vid;
+	entry.valid = valid;
+
+	if (valid) {
+		entry.fid = fid;
+		entry.sid = sid;
+		/* Note: The VTU entry pointed by VID will be loaded but not
+		 * considered valid until the STU entry pointed by SID is valid.
+		 */
+
+		for (port = 0; port < ps->num_ports; ++port) {
+			u8 tag;
+
+			switch (tags[port]) {
+			case 'u':
+				tag = GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED;
+				break;
+			case 't':
+				tag = GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
+				break;
+			case 'x':
+				tag = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
+				break;
+			case '-':
+				tag = GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
+				break;
+			default:
+				return -EINVAL;
+			}
+
+			entry.tags[port] = tag;
+		}
+	}
+
+	mutex_lock(&ps->smi_mutex);
+	ret = _mv88e6xxx_vtu_loadpurge(ds, &entry);
+	mutex_unlock(&ps->smi_mutex);
+
+	return ret < 0 ? ret : count;
+}
+
+static int mv88e6xxx_vtu_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mv88e6xxx_vtu_show, inode->i_private);
+}
+
+static const struct file_operations mv88e6xxx_vtu_fops = {
+	.open		= mv88e6xxx_vtu_open,
+	.read		= seq_read,
+	.write		= mv88e6xxx_vtu_write,
+	.llseek		= no_llseek,
+	.release	= single_release,
+	.owner		= THIS_MODULE,
+};
+
 static void mv88e6xxx_stats_show_header(struct seq_file *s,
 					struct mv88e6xxx_priv_state *ps)
 {
@@ -1901,6 +2209,9 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds)
 	debugfs_create_file("atu", S_IRUGO, ps->dbgfs, ds,
 			    &mv88e6xxx_atu_fops);
 
+	debugfs_create_file("vtu", S_IRUGO | S_IWUSR, ps->dbgfs, ds,
+			    &mv88e6xxx_vtu_fops);
+
 	debugfs_create_file("stats", S_IRUGO, ps->dbgfs, ds,
 			    &mv88e6xxx_stats_fops);
 
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 1bc5a3e..65645b7 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -124,6 +124,7 @@
 #define PORT_CONTROL_1		0x05
 #define PORT_BASE_VLAN		0x06
 #define PORT_DEFAULT_VLAN	0x07
+#define PORT_DEFAULT_VLAN_MASK	0xfff
 #define PORT_CONTROL_2		0x08
 #define PORT_CONTROL_2_IGNORE_FCS	BIT(15)
 #define PORT_CONTROL_2_VTU_PRI_OVERRIDE	BIT(14)
@@ -170,6 +171,10 @@
 #define GLOBAL_MAC_01		0x01
 #define GLOBAL_MAC_23		0x02
 #define GLOBAL_MAC_45		0x03
+#define GLOBAL_VTU_FID		0x02	/* 6097 6165 6351 6352 */
+#define GLOBAL_VTU_FID_MASK	0xfff
+#define GLOBAL_VTU_SID		0x03	/* 6097 6165 6351 6352 */
+#define GLOBAL_VTU_SID_MASK	0x3f
 #define GLOBAL_CONTROL		0x04
 #define GLOBAL_CONTROL_SW_RESET		BIT(15)
 #define GLOBAL_CONTROL_PPU_ENABLE	BIT(14)
@@ -186,9 +191,20 @@
 #define GLOBAL_CONTROL_TCAM_EN		BIT(1)
 #define GLOBAL_CONTROL_EEPROM_DONE_EN	BIT(0)
 #define GLOBAL_VTU_OP		0x05
+#define GLOBAL_VTU_OP_BUSY	BIT(15)
+#define GLOBAL_VTU_OP_FLUSH_ALL		((1 << 12) | GLOBAL_VTU_OP_BUSY)
+#define GLOBAL_VTU_OP_VTU_LOAD_PURGE	((3 << 12) | GLOBAL_VTU_OP_BUSY)
+#define GLOBAL_VTU_OP_VTU_GET_NEXT	((4 << 12) | GLOBAL_VTU_OP_BUSY)
+#define GLOBAL_VTU_OP_STU_LOAD_PURGE	((5 << 12) | GLOBAL_VTU_OP_BUSY)
 #define GLOBAL_VTU_VID		0x06
+#define GLOBAL_VTU_VID_MASK	0xfff
+#define GLOBAL_VTU_VID_VALID	BIT(12)
 #define GLOBAL_VTU_DATA_0_3	0x07
 #define GLOBAL_VTU_DATA_4_7	0x08
+#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED	0
+#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED	1
+#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED	2
+#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER	3
 #define GLOBAL_VTU_DATA_8_11	0x09
 #define GLOBAL_ATU_CONTROL	0x0a
 #define GLOBAL_ATU_CONTROL_LEARN2ALL	BIT(3)
@@ -310,6 +326,14 @@
 #define GLOBAL2_QOS_WEIGHT	0x1c
 #define GLOBAL2_MISC		0x1d
 
+struct mv88e6xxx_vtu_entry {
+	u16	vid;
+	u16	fid;
+	u8	sid;
+	bool	valid;
+	u8	tags[DSA_MAX_PORTS];
+};
+
 struct mv88e6xxx_priv_state {
 	/* When using multi-chip addressing, this mutex protects
 	 * access to the indirect access registers.  (In single-chip
-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1178696 — Re: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU

FromGuenter Roeck <linux@roeck-us.net>
Date2015-07-07 18:20 +0200
SubjectRe: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU
Message-ID<pJDLb-7RF-3@gated-at.bofh.it>
In reply to#1177093
On 07/07/2015 08:52 AM, Vivien Didelot wrote:
> Hi Andrew,
>
> On Jul 6, 2015, at 10:08 PM, Andrew Lunn andrew@lunn.ch wrote:
>
>>> +static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds, u16 vid,
>>> +				  struct mv88e6xxx_vtu_entry *entry)
>>> +{
>>> +	int ret, i;
>>> +
>>> +	ret = _mv88e6xxx_vtu_wait(ds);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID,
>>> +				   vid & GLOBAL_VTU_VID_MASK);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	ret = _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_GET_NEXT);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_VID);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	entry->vid = ret & GLOBAL_VTU_VID_MASK;
>>> +	entry->valid = !!(ret & GLOBAL_VTU_VID_VALID);
>>> +
>>> +	if (entry->valid) {
>>> +		/* Ports 0-3, offsets 0, 4, 8, 12 */
>>> +		ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_DATA_0_3);
>>> +		if (ret < 0)
>>> +			return ret;
>>> +
>>> +		for (i = 0; i < 4; ++i)
>>> +			entry->tags[i] = (ret >> (i * 4)) & 3;
>>> +
>>> +		/* Ports 4-6, offsets 0, 4, 8 */
>>> +		ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_VTU_DATA_4_7);
>>> +		if (ret < 0)
>>> +			return ret;
>>> +
>>> +		for (i = 4; i < 7; ++i)
>>> +			entry->tags[i] = (ret >> ((i - 4) * 4)) & 3;
>>
>> Hi Vivien
>>
>> It looks like you still have up to 7 ports, rather than use
>> ps->num_ports. I have a ten port switch i would like to use VLANs with
>> :-)
>>
>>> +
>>> +		if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
>>> +		    mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
>>> +			ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
>>> +						  GLOBAL_VTU_FID);
>>> +			if (ret < 0)
>>> +				return ret;
>>> +
>>> +			entry->fid = ret & GLOBAL_VTU_FID_MASK;
>>> +
>>> +			ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL,
>>> +						  GLOBAL_VTU_SID);
>>> +			if (ret < 0)
>>> +				return ret;
>>> +
>>> +			entry->sid = ret & GLOBAL_VTU_SID_MASK;
>>> +		} else {
>>> +			entry->fid = 0;
>>> +			entry->sid = 0;
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
>>> +				    struct mv88e6xxx_vtu_entry *entry)
>>> +{
>>> +	u16 data = 0;
>>> +	int ret, i;
>>> +
>>> +	ret = _mv88e6xxx_vtu_wait(ds);
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	if (entry->valid) {
>>> +		/* Set Data Register, ports 0-3, offsets 0, 4, 8, 12 */
>>> +		for (data = i = 0; i < 4; ++i)
>>> +			data |= entry->tags[i] << (i * 4);
>>> +		ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_DATA_0_3,
>>> +					   data);
>>> +		if (ret < 0)
>>> +			return ret;
>>> +
>>> +		/* Set Data Register, ports 4-6, offsets 0, 4, 8 */
>>> +		for (data = 0, i = 4; i < 7; ++i)
>>> +			data |= entry->tags[i] << ((i - 4) * 4);
>>> +		ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_DATA_4_7,
>>> +					   data);
>>
>> Same again here.
>>
>>       Andrew
>
> Indeed, I intentionally kept it as is, since the 88E6352 datasheet is not
> really clear about this. I see that the register 0x09 (called
> GLOBAL_VTU_DATA_8_11 in mv88e6xxx.h) only contains VID priority related bits in
> 15:12, in my case. As bits 11:0 are reserved, I suspect that the offsets of
> Member TagP7, Member TagP8 and Member TagP9 are respectively 0, 4 and 8 for
> you. Can you confirm? If so, I'll make that generic with these values.
>

For 6152 and 6185: Port 7 is in bit 12:15 of GLOBAL_VTU_DATA_4_7, port 8 and 9
are in register 9, bit 0:3 and 4:7.

Guenter

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1178700 — Re: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU

FromVivien Didelot <vivien.didelot@savoirfairelinux.com>
Date2015-07-07 18:20 +0200
SubjectRe: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU
Message-ID<pJDLc-7RF-21@gated-at.bofh.it>
In reply to#1177093
Hi Guenter, Andrew,

----- On Jul 7, 2015, at 12:07 PM, Andrew Lunn andrew@lunn.ch wrote:

>> Indeed, I intentionally kept it as is, since the 88E6352 datasheet is not
>> really clear about this. I see that the register 0x09 (called
>> GLOBAL_VTU_DATA_8_11 in mv88e6xxx.h) only contains VID priority related bits in
>> 15:12, in my case. As bits 11:0 are reserved, I suspect that the offsets of
>> Member TagP7, Member TagP8 and Member TagP9 are respectively 0, 4 and 8 for
>> you. Can you confirm? If so, I'll make that generic with these values.
> 
> Yes, the pattern continues for up to 11 ports, if you look at the DSDT
> sources from Marvell. The mv88e6131.c driver has one device, the 6095,
> with 11 ports.

Thanks for the details. I make the change and send a v4 asap.

Best,
-v
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1178701 — Re: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU

FromAndrew Lunn <andrew@lunn.ch>
Date2015-07-07 18:20 +0200
SubjectRe: [PATCH v3 1/3] net: dsa: mv88e6xxx: add debugfs interface for VTU
Message-ID<pJDLc-7RF-23@gated-at.bofh.it>
In reply to#1177093
> Indeed, I intentionally kept it as is, since the 88E6352 datasheet is not
> really clear about this. I see that the register 0x09 (called
> GLOBAL_VTU_DATA_8_11 in mv88e6xxx.h) only contains VID priority related bits in
> 15:12, in my case. As bits 11:0 are reserved, I suspect that the offsets of
> Member TagP7, Member TagP8 and Member TagP9 are respectively 0, 4 and 8 for
> you. Can you confirm? If so, I'll make that generic with these values.

Yes, the pattern continues for up to 11 ports, if you look at the DSDT
sources from Marvell. The mv88e6131.c driver has one device, the 6095,
with 11 ports.

     Thanks
          Andrew
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1177094 — [PATCH v3 3/3] net: dsa: mv88e6xxx: add switchdev VLAN operations

FromVivien Didelot <vivien.didelot@savoirfairelinux.com>
Date2015-07-06 04:20 +0200
Subject[PATCH v3 3/3] net: dsa: mv88e6xxx: add switchdev VLAN operations
Message-ID<pJ4aJ-2gZ-5@gated-at.bofh.it>
In reply to#1177091
This commit implements the switchdev operations to add, delete and dump
VLANs for the Marvell 88E6352 and compatible switch chips.

This allows to access the switch VLAN Table Unit from standard userspace
commands such as "bridge vlan".

A configuration like "1t 2t 3t 4u" for VLAN 10 is achieved like this:

    # bridge vlan add dev swp1 vid 10 master
    # bridge vlan add dev swp2 vid 10 master
    # bridge vlan add dev swp3 vid 10 master
    # bridge vlan add dev swp4 vid 10 master untagged pvid

This calls port_vlan_add() for each command. Removing the port 3 from
VLAN 10 is done with:

    # bridge vlan del dev swp3 vid 10

This calls port_vlan_del() for port 3. Dumping VLANs is done with:

    # bridge vlan show
    port    vlan ids
    swp0    None
    swp0
    swp1     10

    swp1     10

    swp2     10

    swp2     10

    swp3    None
    swp3
    swp4     10 PVID Egress Untagged

    swp4     10 PVID Egress Untagged

    br0     None

This calls port_vlan_dump() for each ports.

Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6123_61_65.c |   3 +
 drivers/net/dsa/mv88e6131.c       |   3 +
 drivers/net/dsa/mv88e6171.c       |   3 +
 drivers/net/dsa/mv88e6352.c       |   3 +
 drivers/net/dsa/mv88e6xxx.c       | 152 ++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/mv88e6xxx.h       |   5 ++
 6 files changed, 169 insertions(+)

diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c
index 71a29a7..8e679ff 100644
--- a/drivers/net/dsa/mv88e6123_61_65.c
+++ b/drivers/net/dsa/mv88e6123_61_65.c
@@ -134,6 +134,9 @@ struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
 #endif
 	.get_regs_len		= mv88e6xxx_get_regs_len,
 	.get_regs		= mv88e6xxx_get_regs,
+	.port_vlan_add		= mv88e6xxx_port_vlan_add,
+	.port_vlan_del		= mv88e6xxx_port_vlan_del,
+	.port_vlan_dump		= mv88e6xxx_port_vlan_dump,
 };
 
 MODULE_ALIAS("platform:mv88e6123");
diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c
index 32f4a08..c4d914b 100644
--- a/drivers/net/dsa/mv88e6131.c
+++ b/drivers/net/dsa/mv88e6131.c
@@ -182,6 +182,9 @@ struct dsa_switch_driver mv88e6131_switch_driver = {
 	.get_strings		= mv88e6xxx_get_strings,
 	.get_ethtool_stats	= mv88e6xxx_get_ethtool_stats,
 	.get_sset_count		= mv88e6xxx_get_sset_count,
+	.port_vlan_add		= mv88e6xxx_port_vlan_add,
+	.port_vlan_del		= mv88e6xxx_port_vlan_del,
+	.port_vlan_dump		= mv88e6xxx_port_vlan_dump,
 };
 
 MODULE_ALIAS("platform:mv88e6085");
diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c
index 1c78084..7701ce6 100644
--- a/drivers/net/dsa/mv88e6171.c
+++ b/drivers/net/dsa/mv88e6171.c
@@ -119,6 +119,9 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
 	.fdb_add		= mv88e6xxx_port_fdb_add,
 	.fdb_del		= mv88e6xxx_port_fdb_del,
 	.fdb_getnext		= mv88e6xxx_port_fdb_getnext,
+	.port_vlan_add		= mv88e6xxx_port_vlan_add,
+	.port_vlan_del		= mv88e6xxx_port_vlan_del,
+	.port_vlan_dump		= mv88e6xxx_port_vlan_dump,
 };
 
 MODULE_ALIAS("platform:mv88e6171");
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index 632815c..b981be4a 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -392,6 +392,9 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
 	.fdb_add		= mv88e6xxx_port_fdb_add,
 	.fdb_del		= mv88e6xxx_port_fdb_del,
 	.fdb_getnext		= mv88e6xxx_port_fdb_getnext,
+	.port_vlan_add		= mv88e6xxx_port_vlan_add,
+	.port_vlan_del		= mv88e6xxx_port_vlan_del,
+	.port_vlan_dump		= mv88e6xxx_port_vlan_dump,
 };
 
 MODULE_ALIAS("platform:mv88e6352");
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index ffd9fc6..d5812ba 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1544,6 +1544,158 @@ static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
 	return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_LOAD_PURGE);
 }
 
+int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
+			    u16 bridge_flags)
+{
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	struct mv88e6xxx_vtu_entry entry = { 0 };
+	int prev_vid = vid ? vid - 1 : 0xfff;
+	int i, ret;
+
+	mutex_lock(&ps->smi_mutex);
+	ret = _mv88e6xxx_vtu_getnext(ds, prev_vid, &entry);
+	if (ret < 0)
+		goto unlock;
+
+	/* If the VLAN does not exist, re-initialize the entry for addition */
+	if (entry.vid != vid || !entry.valid) {
+		memset(&entry, 0, sizeof(entry));
+		entry.valid = true;
+		entry.vid = vid;
+		entry.fid = vid; /* We use one FID per VLAN at the moment */
+		entry.sid = 0; /* We don't use 802.1s (yet) */
+
+		/* The DSA port-based VLAN setup also reserves one FID per port;
+		 * thus, warn when requesting one of the first num_ports VIDs.
+		 */
+		if (entry.fid < ps->num_ports)
+			netdev_warn(ds->ports[vid], "using reserved FID\n");
+
+		if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
+		    mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
+			/* A VTU entry need a valid STU entry (undocumented).
+			 * The default STU pointer for a VTU entry is 0. If per
+			 * VLAN spanning tree is not used then only one STU
+			 * entry is needed to cover all VTU entries. Thus,
+			 * validate the STU entry 0.
+			 */
+			ret = _mv88e6xxx_stu_loadpurge(ds, 0, true);
+			if (ret < 0)
+				goto unlock;
+		}
+
+		for (i = 0; i < ps->num_ports; ++i)
+			entry.tags[i] = dsa_is_cpu_port(ds, i) ?
+				GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED :
+				GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
+	}
+
+	entry.tags[port] = bridge_flags & BRIDGE_VLAN_INFO_UNTAGGED ?
+		GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
+		GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
+
+	ret = _mv88e6xxx_vtu_loadpurge(ds, &entry);
+
+	/* Set port default VID */
+	if (bridge_flags & BRIDGE_VLAN_INFO_PVID)
+		ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+					   PORT_DEFAULT_VLAN,
+					   vid & PORT_DEFAULT_VLAN_MASK);
+unlock:
+	mutex_unlock(&ps->smi_mutex);
+
+	return ret;
+}
+
+int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
+{
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	struct mv88e6xxx_vtu_entry entry = { 0 };
+	int i, ret, prev_vid = vid ? vid - 1 : 0xfff;
+	bool keep = false;
+
+	mutex_lock(&ps->smi_mutex);
+	ret = _mv88e6xxx_vtu_getnext(ds, prev_vid, &entry);
+	if (ret < 0)
+		goto unlock;
+
+	if (entry.vid != vid || !entry.valid) {
+		ret = -ENOENT;
+		goto unlock;
+	}
+
+	entry.tags[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
+
+	/* keep the VLAN unless all ports are excluded */
+	for (i = 0; i < ps->num_ports; ++i) {
+		if (dsa_is_cpu_port(ds, i))
+			continue;
+
+		if (entry.tags[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
+			keep = true;
+			break;
+		}
+	}
+
+	entry.valid = keep;
+	ret = _mv88e6xxx_vtu_loadpurge(ds, &entry);
+	if (ret < 0)
+		goto unlock;
+
+	/* TODO reset PVID if it was this VID? */
+
+	if (!keep)
+		ret = _mv88e6xxx_update_bridge_config(ds, entry.fid);
+unlock:
+	mutex_unlock(&ps->smi_mutex);
+
+	return ret;
+}
+
+int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, u16 vid,
+			     u16 *bridge_flags)
+{
+	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+	struct mv88e6xxx_vtu_entry entry = { 0 };
+	int prev_vid = vid ? vid - 1 : 0xfff;
+	int ret;
+
+	mutex_lock(&ps->smi_mutex);
+	ret = _mv88e6xxx_vtu_getnext(ds, prev_vid, &entry);
+	if (ret < 0)
+		goto unlock;
+
+	if (entry.vid != vid || !entry.valid) {
+		ret = -ENOENT;
+		goto unlock;
+	}
+
+	switch (entry.tags[port]) {
+	case GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED:
+		*bridge_flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+		break;
+	case GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED:
+		break;
+	default:
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	/* check PVID */
+	ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_DEFAULT_VLAN);
+	if (ret < 0)
+		goto unlock;
+
+	if ((ret & PORT_DEFAULT_VLAN_MASK) == vid)
+		*bridge_flags |= BRIDGE_VLAN_INFO_PVID;
+
+	ret = 0;
+unlock:
+	mutex_unlock(&ps->smi_mutex);
+
+	return ret;
+}
+
 static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
 {
 	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 65645b7..be8b6cc 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -440,6 +440,11 @@ int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
 int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg);
 int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
 			     int reg, int val);
+int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
+			    u16 bridge_flags);
+int mv88e6xxx_port_vlan_del(struct dsa_switch *ds,int port, u16 vid);
+int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds,int port, u16 vid,
+			     u16 *bridge_flags);
 extern struct dsa_switch_driver mv88e6131_switch_driver;
 extern struct dsa_switch_driver mv88e6123_61_65_switch_driver;
 extern struct dsa_switch_driver mv88e6352_switch_driver;
-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1178698 — Re: [PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table Unit

FromVivien Didelot <vivien.didelot@savoirfairelinux.com>
Date2015-07-07 18:20 +0200
SubjectRe: [PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table Unit
Message-ID<pJDLb-7RF-9@gated-at.bofh.it>
In reply to#1177091
Hi Andrew, Scott,

On Jul 6, 2015, at 11:46 PM, Scott Feldman sfeldma@gmail.com wrote:

> On Mon, Jul 6, 2015 at 7:00 PM, Andrew Lunn <andrew@lunn.ch> wrote:
>> On Tue, Jul 07, 2015 at 01:38:04AM +0200, Andrew Lunn wrote:
>>> On Sun, Jul 05, 2015 at 10:14:50PM -0400, Vivien Didelot wrote:
>>> > Hi all,
>>> >
>>> > This patchset brings full support for hardware VLANs in DSA, and the Marvell
>>> > 88E6xxx compatible switch chips.
>>>
>>> Hi Vivien
>>>
>>> I just booted these patches on my board, and i'm getting WARNINGS:
>>>
>>> [   61.111302] WARNING: CPU: 0 PID: 2751 at net/switchdev/switchdev.c:265
>>> switchdev_port_obj_add+0xd4/0xdc()
>>
>> Hi Vivien
>>
>> I debugged this a bit.
>>
>> The problem comes from:
>>
>> static int dsa_slave_port_obj_add(struct net_device *dev,
>>                                   struct switchdev_obj *obj)
>> {
>>         int err;
>>
>>         /*
>>          * Skip the prepare phase, since currently the DSA drivers don't need to
>>          * allocate any memory for operations and they will not fail to HW
>>          * (unless something horrible goes wrong on the MDIO bus, in which case
>>          * the prepare phase wouldn't have been able to predict anyway).
>>          */
>>         if (obj->trans != SWITCHDEV_TRANS_COMMIT)
>>                 return 0;
>>
>>         switch (obj->id) {
>>         case SWITCHDEV_OBJ_PORT_VLAN:
>>                 err = dsa_slave_port_vlans_add(dev, obj);
>>                 break;
>>         default:
>>                 err = -EOPNOTSUPP;
>>                 break;
>>         }
>>
>>         return err;
>> }
>>
>> It is being called with obj->id of 2, which is
>> SWITCHDEV_OBJ_IPV4_FIB. This function is called twice. The first time
>> it is with SWITCHDEV_TRANS_PREPARE and we are allowed to return an
>> error. The second time, with SWITCHDEV_TRANS_COMMIT, errors are not
>> allowed.
>>
>> EOPNOTSUPP is considered an error, so since we don't support
>> SWITCHDEV_OBJ_IPV4_FIB we error out the COMMIT phase.
>>
>> Not sure which is cleaner. Test to see if we support the object during
>> the prepare, or allow the commit to accept EOPNOTSUPP as not being an
>> error?
> 
> I think we should return EOPNOTSUPP on PREPARE, so move the trans !=
> COMMIT test inside the case for PORT_VLAN.  That would future-proof
> the func when new objects are added to switchdev (and not supported by
> dsa_slave).

Does this fixup http://ix.io/jxq look good to you?

Thanks,
-v
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1178706 — Re: [PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table Unit

FromAndrew Lunn <andrew@lunn.ch>
Date2015-07-07 18:30 +0200
SubjectRe: [PATCH v3 0/3] net: dsa: mv88e6xxx: add support for VLAN Table Unit
Message-ID<pJDUS-7UN-7@gated-at.bofh.it>
In reply to#1178698
On Tue, Jul 07, 2015 at 12:17:57PM -0400, Vivien Didelot wrote:
> Hi Andrew, Scott,
> Does this fixup http://ix.io/jxq look good to you?

Yes, that looks good.

     Andrew
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web