Commit c3bc6deb authored by David S. Miller's avatar David S. Miller

Merge branch 'Fixes-for-DSA-tagging-using-802-1Q'

Vladimir Oltean says:

====================
Fixes for DSA tagging using 802.1Q

During the prototyping for the "Decoupling PHYLINK from struct
net_device" patchset, the CPU port of the sja1105 driver was moved to a
different spot.  This uncovered an issue in the tag_8021q DSA code,
which used to work by mistake - the CPU port was the last hardware port
numerically, and this was masking an ordering issue which is very likely
to be seen in other drivers that make use of 802.1Q tags.

A question was also raised whether the VID numbers bear any meaning, and
the conclusion was that they don't, at least not in an absolute sense.
The second patch defines bit fields inside the DSA 802.1Q VID so that
tcpdump can decode it unambiguously (although the meaning is now clear
even by visual inspection).
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 21808437 0471dd42
......@@ -11,20 +11,59 @@
#include "dsa_priv.h"
/* Allocating two VLAN tags per port - one for the RX VID and
* the other for the TX VID - see below
/* Binary structure of the fake 12-bit VID field (when the TPID is
* ETH_P_DSA_8021Q):
*
* | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* +-----------+-----+-----------------+-----------+-----------------------+
* | DIR | RSV | SWITCH_ID | RSV | PORT |
* +-----------+-----+-----------------+-----------+-----------------------+
*
* DIR - VID[11:10]:
* Direction flags.
* * 1 (0b01) for RX VLAN,
* * 2 (0b10) for TX VLAN.
* These values make the special VIDs of 0, 1 and 4095 to be left
* unused by this coding scheme.
*
* RSV - VID[9]:
* To be used for further expansion of SWITCH_ID or for other purposes.
*
* SWITCH_ID - VID[8:6]:
* Index of switch within DSA tree. Must be between 0 and
* DSA_MAX_SWITCHES - 1.
*
* RSV - VID[5:4]:
* To be used for further expansion of PORT or for other purposes.
*
* PORT - VID[3:0]:
* Index of switch port. Must be between 0 and DSA_MAX_PORTS - 1.
*/
#define DSA_8021Q_VID_RANGE (DSA_MAX_SWITCHES * DSA_MAX_PORTS)
#define DSA_8021Q_VID_BASE (VLAN_N_VID - 2 * DSA_8021Q_VID_RANGE - 1)
#define DSA_8021Q_RX_VID_BASE (DSA_8021Q_VID_BASE)
#define DSA_8021Q_TX_VID_BASE (DSA_8021Q_VID_BASE + DSA_8021Q_VID_RANGE)
#define DSA_8021Q_DIR_SHIFT 10
#define DSA_8021Q_DIR_MASK GENMASK(11, 10)
#define DSA_8021Q_DIR(x) (((x) << DSA_8021Q_DIR_SHIFT) & \
DSA_8021Q_DIR_MASK)
#define DSA_8021Q_DIR_RX DSA_8021Q_DIR(1)
#define DSA_8021Q_DIR_TX DSA_8021Q_DIR(2)
#define DSA_8021Q_SWITCH_ID_SHIFT 6
#define DSA_8021Q_SWITCH_ID_MASK GENMASK(8, 6)
#define DSA_8021Q_SWITCH_ID(x) (((x) << DSA_8021Q_SWITCH_ID_SHIFT) & \
DSA_8021Q_SWITCH_ID_MASK)
#define DSA_8021Q_PORT_SHIFT 0
#define DSA_8021Q_PORT_MASK GENMASK(3, 0)
#define DSA_8021Q_PORT(x) (((x) << DSA_8021Q_PORT_SHIFT) & \
DSA_8021Q_PORT_MASK)
/* Returns the VID to be inserted into the frame from xmit for switch steering
* instructions on egress. Encodes switch ID and port ID.
*/
u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port)
{
return DSA_8021Q_TX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port;
return DSA_8021Q_DIR_TX | DSA_8021Q_SWITCH_ID(ds->index) |
DSA_8021Q_PORT(port);
}
EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid);
......@@ -33,21 +72,22 @@ EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid);
*/
u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port)
{
return DSA_8021Q_RX_VID_BASE + (DSA_MAX_PORTS * ds->index) + port;
return DSA_8021Q_DIR_RX | DSA_8021Q_SWITCH_ID(ds->index) |
DSA_8021Q_PORT(port);
}
EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid);
/* Returns the decoded switch ID from the RX VID. */
int dsa_8021q_rx_switch_id(u16 vid)
{
return ((vid - DSA_8021Q_RX_VID_BASE) / DSA_MAX_PORTS);
return (vid & DSA_8021Q_SWITCH_ID_MASK) >> DSA_8021Q_SWITCH_ID_SHIFT;
}
EXPORT_SYMBOL_GPL(dsa_8021q_rx_switch_id);
/* Returns the decoded port ID from the RX VID. */
int dsa_8021q_rx_source_port(u16 vid)
{
return ((vid - DSA_8021Q_RX_VID_BASE) % DSA_MAX_PORTS);
return (vid & DSA_8021Q_PORT_MASK) >> DSA_8021Q_PORT_SHIFT;
}
EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);
......@@ -128,10 +168,7 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
u16 flags;
if (i == upstream)
/* CPU port needs to see this port's RX VID
* as tagged egress.
*/
flags = 0;
continue;
else if (i == port)
/* The RX VID is pvid on this port */
flags = BRIDGE_VLAN_INFO_UNTAGGED |
......@@ -150,6 +187,20 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
return err;
}
}
/* CPU port needs to see this port's RX VID
* as tagged egress.
*/
if (enabled)
err = dsa_port_vid_add(upstream_dp, rx_vid, 0);
else
err = dsa_port_vid_del(upstream_dp, rx_vid);
if (err) {
dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %d\n",
rx_vid, port, err);
return err;
}
/* Finally apply the TX VID on this port and on the CPU port */
if (enabled)
err = dsa_port_vid_add(dp, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment