forked from luck/tmp_suning_uos_patched
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
06d3e19630
|
@ -18,6 +18,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/if_bridge.h>
|
||||
|
||||
#include "lan9303.h"
|
||||
|
||||
|
@ -146,6 +147,7 @@
|
|||
# define LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 (0)
|
||||
# define LAN9303_SWE_PORT_STATE_LEARNING_PORT0 BIT(1)
|
||||
# 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_SNIFF_ALL BIT(8)
|
||||
# define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT2 BIT(7)
|
||||
|
@ -156,7 +158,9 @@
|
|||
# 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_TX_MIRRORING BIT(0)
|
||||
# define LAN9303_SWE_PORT_MIRROR_DISABLED 0
|
||||
#define LAN9303_SWE_INGRESS_PORT_TYPE 0x1847
|
||||
#define LAN9303_SWE_INGRESS_PORT_TYPE_VLAN 3
|
||||
#define LAN9303_BM_CFG 0x1c00
|
||||
#define LAN9303_BM_EGRSS_PORT_TYPE 0x1c0c
|
||||
# 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,
|
|||
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:
|
||||
* - do not forward packets between port 1 and 2
|
||||
* - forward everything from port 1 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)
|
||||
{
|
||||
|
@ -529,22 +552,6 @@ static int lan9303_separate_ports(struct lan9303 *chip)
|
|||
if (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 */
|
||||
return lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE,
|
||||
LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 |
|
||||
|
@ -552,6 +559,16 @@ static int lan9303_separate_ports(struct lan9303 *chip)
|
|||
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)
|
||||
{
|
||||
if (!chip->reset_gpio)
|
||||
|
@ -644,6 +661,10 @@ static int lan9303_setup(struct dsa_switch *ds)
|
|||
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);
|
||||
if (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,
|
|||
}
|
||||
}
|
||||
|
||||
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 = {
|
||||
.get_tag_protocol = lan9303_get_tag_protocol,
|
||||
.setup = lan9303_setup,
|
||||
|
@ -847,6 +934,9 @@ static const struct dsa_switch_ops lan9303_switch_ops = {
|
|||
.get_sset_count = lan9303_get_sset_count,
|
||||
.port_enable = lan9303_port_enable,
|
||||
.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)
|
||||
|
|
|
@ -21,6 +21,8 @@ struct lan9303 {
|
|||
struct dsa_switch *ds;
|
||||
struct mutex indirect_mutex; /* protect indexed register access */
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user