Commit 06d3e196 authored by David S. Miller's avatar David S. Miller

Merge branch 'lan9303-Add-basic-offloading-of-unicast-traffic'

Egil Hjelmeland says:

====================
lan9303: Add basic offloading of unicast traffic

This series add basic offloading of unicast traffic to the lan9303
DSA driver.

Review welcome!

Changes v1 -> v2:
 - Patch 1: Codestyle linting.
 - Patch 2: Remember SWE_PORT_STATE while not bridged.
            Added constant LAN9303_SWE_PORT_MIRROR_DISABLED.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4a269818 d99a86ae
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/if_bridge.h>
#include "lan9303.h" #include "lan9303.h"
...@@ -146,6 +147,7 @@ ...@@ -146,6 +147,7 @@
# define LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 (0) # define LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 (0)
# define LAN9303_SWE_PORT_STATE_LEARNING_PORT0 BIT(1) # define LAN9303_SWE_PORT_STATE_LEARNING_PORT0 BIT(1)
# define LAN9303_SWE_PORT_STATE_BLOCKING_PORT0 BIT(0) # define LAN9303_SWE_PORT_STATE_BLOCKING_PORT0 BIT(0)
# define LAN9303_SWE_PORT_STATE_DISABLED_PORT0 (3)
#define LAN9303_SWE_PORT_MIRROR 0x1846 #define LAN9303_SWE_PORT_MIRROR 0x1846
# define LAN9303_SWE_PORT_MIRROR_SNIFF_ALL BIT(8) # define LAN9303_SWE_PORT_MIRROR_SNIFF_ALL BIT(8)
# define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT2 BIT(7) # define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT2 BIT(7)
...@@ -156,7 +158,9 @@ ...@@ -156,7 +158,9 @@
# define LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT0 BIT(2) # define LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT0 BIT(2)
# define LAN9303_SWE_PORT_MIRROR_ENABLE_RX_MIRRORING BIT(1) # define LAN9303_SWE_PORT_MIRROR_ENABLE_RX_MIRRORING BIT(1)
# define LAN9303_SWE_PORT_MIRROR_ENABLE_TX_MIRRORING BIT(0) # define LAN9303_SWE_PORT_MIRROR_ENABLE_TX_MIRRORING BIT(0)
# define LAN9303_SWE_PORT_MIRROR_DISABLED 0
#define LAN9303_SWE_INGRESS_PORT_TYPE 0x1847 #define LAN9303_SWE_INGRESS_PORT_TYPE 0x1847
#define LAN9303_SWE_INGRESS_PORT_TYPE_VLAN 3
#define LAN9303_BM_CFG 0x1c00 #define LAN9303_BM_CFG 0x1c00
#define LAN9303_BM_EGRSS_PORT_TYPE 0x1c0c #define LAN9303_BM_EGRSS_PORT_TYPE 0x1c0c
# define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT2 (BIT(17) | BIT(16)) # define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT2 (BIT(17) | BIT(16))
...@@ -510,11 +514,30 @@ static int lan9303_enable_processing_port(struct lan9303 *chip, ...@@ -510,11 +514,30 @@ static int lan9303_enable_processing_port(struct lan9303 *chip,
LAN9303_MAC_TX_CFG_X_TX_ENABLE); LAN9303_MAC_TX_CFG_X_TX_ENABLE);
} }
/* forward special tagged packets from port 0 to port 1 *or* port 2 */
static int lan9303_setup_tagging(struct lan9303 *chip)
{
int ret;
u32 val;
/* enable defining the destination port via special VLAN tagging
* for port 0
*/
ret = lan9303_write_switch_reg(chip, LAN9303_SWE_INGRESS_PORT_TYPE,
LAN9303_SWE_INGRESS_PORT_TYPE_VLAN);
if (ret)
return ret;
/* tag incoming packets at port 1 and 2 on their way to port 0 to be
* able to discover their source port
*/
val = LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT0;
return lan9303_write_switch_reg(chip, LAN9303_BM_EGRSS_PORT_TYPE, val);
}
/* We want a special working switch: /* We want a special working switch:
* - do not forward packets between port 1 and 2 * - do not forward packets between port 1 and 2
* - forward everything from port 1 to port 0 * - forward everything from port 1 to port 0
* - forward everything from port 2 to port 0 * - forward everything from port 2 to port 0
* - forward special tagged packets from port 0 to port 1 *or* port 2
*/ */
static int lan9303_separate_ports(struct lan9303 *chip) static int lan9303_separate_ports(struct lan9303 *chip)
{ {
...@@ -529,22 +552,6 @@ static int lan9303_separate_ports(struct lan9303 *chip) ...@@ -529,22 +552,6 @@ static int lan9303_separate_ports(struct lan9303 *chip)
if (ret) if (ret)
return ret; return ret;
/* enable defining the destination port via special VLAN tagging
* for port 0
*/
ret = lan9303_write_switch_reg(chip, LAN9303_SWE_INGRESS_PORT_TYPE,
0x03);
if (ret)
return ret;
/* tag incoming packets at port 1 and 2 on their way to port 0 to be
* able to discover their source port
*/
ret = lan9303_write_switch_reg(chip, LAN9303_BM_EGRSS_PORT_TYPE,
LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT0);
if (ret)
return ret;
/* prevent port 1 and 2 from forwarding packets by their own */ /* prevent port 1 and 2 from forwarding packets by their own */
return lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE, return lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE,
LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 | LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 |
...@@ -552,6 +559,16 @@ static int lan9303_separate_ports(struct lan9303 *chip) ...@@ -552,6 +559,16 @@ static int lan9303_separate_ports(struct lan9303 *chip)
LAN9303_SWE_PORT_STATE_BLOCKING_PORT2); LAN9303_SWE_PORT_STATE_BLOCKING_PORT2);
} }
static void lan9303_bridge_ports(struct lan9303 *chip)
{
/* ports bridged: remove mirroring */
lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_MIRROR,
LAN9303_SWE_PORT_MIRROR_DISABLED);
lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE,
chip->swe_port_state);
}
static int lan9303_handle_reset(struct lan9303 *chip) static int lan9303_handle_reset(struct lan9303 *chip)
{ {
if (!chip->reset_gpio) if (!chip->reset_gpio)
...@@ -644,6 +661,10 @@ static int lan9303_setup(struct dsa_switch *ds) ...@@ -644,6 +661,10 @@ static int lan9303_setup(struct dsa_switch *ds)
return -EINVAL; return -EINVAL;
} }
ret = lan9303_setup_tagging(chip);
if (ret)
dev_err(chip->dev, "failed to setup port tagging %d\n", ret);
ret = lan9303_separate_ports(chip); ret = lan9303_separate_ports(chip);
if (ret) if (ret)
dev_err(chip->dev, "failed to separate ports %d\n", ret); dev_err(chip->dev, "failed to separate ports %d\n", ret);
...@@ -836,6 +857,72 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port, ...@@ -836,6 +857,72 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port,
} }
} }
static int lan9303_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *br)
{
struct lan9303 *chip = ds->priv;
dev_dbg(chip->dev, "%s(port %d)\n", __func__, port);
if (ds->ports[1].bridge_dev == ds->ports[2].bridge_dev) {
lan9303_bridge_ports(chip);
chip->is_bridged = true; /* unleash stp_state_set() */
}
return 0;
}
static void lan9303_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *br)
{
struct lan9303 *chip = ds->priv;
dev_dbg(chip->dev, "%s(port %d)\n", __func__, port);
if (chip->is_bridged) {
lan9303_separate_ports(chip);
chip->is_bridged = false;
}
}
static void lan9303_port_stp_state_set(struct dsa_switch *ds, int port,
u8 state)
{
int portmask, portstate;
struct lan9303 *chip = ds->priv;
dev_dbg(chip->dev, "%s(port %d, state %d)\n",
__func__, port, state);
switch (state) {
case BR_STATE_DISABLED:
portstate = LAN9303_SWE_PORT_STATE_DISABLED_PORT0;
break;
case BR_STATE_BLOCKING:
case BR_STATE_LISTENING:
portstate = LAN9303_SWE_PORT_STATE_BLOCKING_PORT0;
break;
case BR_STATE_LEARNING:
portstate = LAN9303_SWE_PORT_STATE_LEARNING_PORT0;
break;
case BR_STATE_FORWARDING:
portstate = LAN9303_SWE_PORT_STATE_FORWARDING_PORT0;
break;
default:
portstate = LAN9303_SWE_PORT_STATE_DISABLED_PORT0;
dev_err(chip->dev, "unknown stp state: port %d, state %d\n",
port, state);
}
portmask = 0x3 << (port * 2);
portstate <<= (port * 2);
chip->swe_port_state = (chip->swe_port_state & ~portmask) | portstate;
if (chip->is_bridged)
lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE,
chip->swe_port_state);
/* else: touching SWE_PORT_STATE would break port separation */
}
static const struct dsa_switch_ops lan9303_switch_ops = { static const struct dsa_switch_ops lan9303_switch_ops = {
.get_tag_protocol = lan9303_get_tag_protocol, .get_tag_protocol = lan9303_get_tag_protocol,
.setup = lan9303_setup, .setup = lan9303_setup,
...@@ -847,6 +934,9 @@ static const struct dsa_switch_ops lan9303_switch_ops = { ...@@ -847,6 +934,9 @@ static const struct dsa_switch_ops lan9303_switch_ops = {
.get_sset_count = lan9303_get_sset_count, .get_sset_count = lan9303_get_sset_count,
.port_enable = lan9303_port_enable, .port_enable = lan9303_port_enable,
.port_disable = lan9303_port_disable, .port_disable = lan9303_port_disable,
.port_bridge_join = lan9303_port_bridge_join,
.port_bridge_leave = lan9303_port_bridge_leave,
.port_stp_state_set = lan9303_port_stp_state_set,
}; };
static int lan9303_register_switch(struct lan9303 *chip) static int lan9303_register_switch(struct lan9303 *chip)
......
...@@ -21,6 +21,8 @@ struct lan9303 { ...@@ -21,6 +21,8 @@ struct lan9303 {
struct dsa_switch *ds; struct dsa_switch *ds;
struct mutex indirect_mutex; /* protect indexed register access */ struct mutex indirect_mutex; /* protect indexed register access */
const struct lan9303_phy_ops *ops; const struct lan9303_phy_ops *ops;
bool is_bridged; /* true if port 1 and 2 are bridged */
u32 swe_port_state; /* remember SWE_PORT_STATE while not bridged */
}; };
extern const struct regmap_access_table lan9303_register_set; extern const struct regmap_access_table lan9303_register_set;
......
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