Merge branch 'net-dsa-mv88e6xxx-add-PCL-support'
Vivien Didelot says: ==================== net: dsa: mv88e6xxx: add PCL support This small series implements the ethtool RXNFC operations in the mv88e6xxx DSA driver to configure a port's Layer 2 Policy Control List (PCL) supported by models such as 88E6352 and 88E6390 and equivalent. This allows to configure a port to discard frames based on a configured destination or source MAC address and an optional VLAN, with e.g.: # ethtool --config-nfc lan1 flow-type ether src 00:11:22:33:44:55 action -1 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
4bb2f84a2a
@ -1497,7 +1497,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
|
||||
fid = vlan.fid;
|
||||
}
|
||||
|
||||
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||
entry.state = 0;
|
||||
ether_addr_copy(entry.mac, addr);
|
||||
eth_addr_dec(entry.mac);
|
||||
|
||||
@ -1506,17 +1506,16 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
|
||||
return err;
|
||||
|
||||
/* Initialize a fresh ATU entry if it isn't found */
|
||||
if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED ||
|
||||
!ether_addr_equal(entry.mac, addr)) {
|
||||
if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
ether_addr_copy(entry.mac, addr);
|
||||
}
|
||||
|
||||
/* Purge the ATU entry only if no port is using it anymore */
|
||||
if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
|
||||
if (!state) {
|
||||
entry.portvec &= ~BIT(port);
|
||||
if (!entry.portvec)
|
||||
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||
entry.state = 0;
|
||||
} else {
|
||||
entry.portvec |= BIT(port);
|
||||
entry.state = state;
|
||||
@ -1525,6 +1524,216 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
|
||||
return mv88e6xxx_g1_atu_loadpurge(chip, fid, &entry);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_policy_apply(struct mv88e6xxx_chip *chip, int port,
|
||||
const struct mv88e6xxx_policy *policy)
|
||||
{
|
||||
enum mv88e6xxx_policy_mapping mapping = policy->mapping;
|
||||
enum mv88e6xxx_policy_action action = policy->action;
|
||||
const u8 *addr = policy->addr;
|
||||
u16 vid = policy->vid;
|
||||
u8 state;
|
||||
int err;
|
||||
int id;
|
||||
|
||||
if (!chip->info->ops->port_set_policy)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (mapping) {
|
||||
case MV88E6XXX_POLICY_MAPPING_DA:
|
||||
case MV88E6XXX_POLICY_MAPPING_SA:
|
||||
if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
|
||||
state = 0; /* Dissociate the port and address */
|
||||
else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
|
||||
is_multicast_ether_addr(addr))
|
||||
state = MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY;
|
||||
else if (action == MV88E6XXX_POLICY_ACTION_DISCARD &&
|
||||
is_unicast_ether_addr(addr))
|
||||
state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY;
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
|
||||
state);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Skip the port's policy clearing if the mapping is still in use */
|
||||
if (action == MV88E6XXX_POLICY_ACTION_NORMAL)
|
||||
idr_for_each_entry(&chip->policies, policy, id)
|
||||
if (policy->port == port &&
|
||||
policy->mapping == mapping &&
|
||||
policy->action != action)
|
||||
return 0;
|
||||
|
||||
return chip->info->ops->port_set_policy(chip, port, mapping, action);
|
||||
}
|
||||
|
||||
static int mv88e6xxx_policy_insert(struct mv88e6xxx_chip *chip, int port,
|
||||
struct ethtool_rx_flow_spec *fs)
|
||||
{
|
||||
struct ethhdr *mac_entry = &fs->h_u.ether_spec;
|
||||
struct ethhdr *mac_mask = &fs->m_u.ether_spec;
|
||||
enum mv88e6xxx_policy_mapping mapping;
|
||||
enum mv88e6xxx_policy_action action;
|
||||
struct mv88e6xxx_policy *policy;
|
||||
u16 vid = 0;
|
||||
u8 *addr;
|
||||
int err;
|
||||
int id;
|
||||
|
||||
if (fs->location != RX_CLS_LOC_ANY)
|
||||
return -EINVAL;
|
||||
|
||||
if (fs->ring_cookie == RX_CLS_FLOW_DISC)
|
||||
action = MV88E6XXX_POLICY_ACTION_DISCARD;
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (fs->flow_type & ~FLOW_EXT) {
|
||||
case ETHER_FLOW:
|
||||
if (!is_zero_ether_addr(mac_mask->h_dest) &&
|
||||
is_zero_ether_addr(mac_mask->h_source)) {
|
||||
mapping = MV88E6XXX_POLICY_MAPPING_DA;
|
||||
addr = mac_entry->h_dest;
|
||||
} else if (is_zero_ether_addr(mac_mask->h_dest) &&
|
||||
!is_zero_ether_addr(mac_mask->h_source)) {
|
||||
mapping = MV88E6XXX_POLICY_MAPPING_SA;
|
||||
addr = mac_entry->h_source;
|
||||
} else {
|
||||
/* Cannot support DA and SA mapping in the same rule */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if ((fs->flow_type & FLOW_EXT) && fs->m_ext.vlan_tci) {
|
||||
if (fs->m_ext.vlan_tci != 0xffff)
|
||||
return -EOPNOTSUPP;
|
||||
vid = be16_to_cpu(fs->h_ext.vlan_tci) & VLAN_VID_MASK;
|
||||
}
|
||||
|
||||
idr_for_each_entry(&chip->policies, policy, id) {
|
||||
if (policy->port == port && policy->mapping == mapping &&
|
||||
policy->action == action && policy->vid == vid &&
|
||||
ether_addr_equal(policy->addr, addr))
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
policy = devm_kzalloc(chip->dev, sizeof(*policy), GFP_KERNEL);
|
||||
if (!policy)
|
||||
return -ENOMEM;
|
||||
|
||||
fs->location = 0;
|
||||
err = idr_alloc_u32(&chip->policies, policy, &fs->location, 0xffffffff,
|
||||
GFP_KERNEL);
|
||||
if (err) {
|
||||
devm_kfree(chip->dev, policy);
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(&policy->fs, fs, sizeof(*fs));
|
||||
ether_addr_copy(policy->addr, addr);
|
||||
policy->mapping = mapping;
|
||||
policy->action = action;
|
||||
policy->port = port;
|
||||
policy->vid = vid;
|
||||
|
||||
err = mv88e6xxx_policy_apply(chip, port, policy);
|
||||
if (err) {
|
||||
idr_remove(&chip->policies, fs->location);
|
||||
devm_kfree(chip->dev, policy);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
|
||||
struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
|
||||
{
|
||||
struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
|
||||
struct mv88e6xxx_chip *chip = ds->priv;
|
||||
struct mv88e6xxx_policy *policy;
|
||||
int err;
|
||||
int id;
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
|
||||
switch (rxnfc->cmd) {
|
||||
case ETHTOOL_GRXCLSRLCNT:
|
||||
rxnfc->data = 0;
|
||||
rxnfc->data |= RX_CLS_LOC_SPECIAL;
|
||||
rxnfc->rule_cnt = 0;
|
||||
idr_for_each_entry(&chip->policies, policy, id)
|
||||
if (policy->port == port)
|
||||
rxnfc->rule_cnt++;
|
||||
err = 0;
|
||||
break;
|
||||
case ETHTOOL_GRXCLSRULE:
|
||||
err = -ENOENT;
|
||||
policy = idr_find(&chip->policies, fs->location);
|
||||
if (policy) {
|
||||
memcpy(fs, &policy->fs, sizeof(*fs));
|
||||
err = 0;
|
||||
}
|
||||
break;
|
||||
case ETHTOOL_GRXCLSRLALL:
|
||||
rxnfc->data = 0;
|
||||
rxnfc->rule_cnt = 0;
|
||||
idr_for_each_entry(&chip->policies, policy, id)
|
||||
if (policy->port == port)
|
||||
rule_locs[rxnfc->rule_cnt++] = id;
|
||||
err = 0;
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
mv88e6xxx_reg_unlock(chip);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_set_rxnfc(struct dsa_switch *ds, int port,
|
||||
struct ethtool_rxnfc *rxnfc)
|
||||
{
|
||||
struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
|
||||
struct mv88e6xxx_chip *chip = ds->priv;
|
||||
struct mv88e6xxx_policy *policy;
|
||||
int err;
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
|
||||
switch (rxnfc->cmd) {
|
||||
case ETHTOOL_SRXCLSRLINS:
|
||||
err = mv88e6xxx_policy_insert(chip, port, fs);
|
||||
break;
|
||||
case ETHTOOL_SRXCLSRLDEL:
|
||||
err = -ENOENT;
|
||||
policy = idr_remove(&chip->policies, fs->location);
|
||||
if (policy) {
|
||||
policy->action = MV88E6XXX_POLICY_ACTION_NORMAL;
|
||||
err = mv88e6xxx_policy_apply(chip, port, policy);
|
||||
devm_kfree(chip->dev, policy);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
mv88e6xxx_reg_unlock(chip);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
|
||||
u16 vid)
|
||||
{
|
||||
@ -1732,8 +1941,7 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
|
||||
int err;
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
|
||||
MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
|
||||
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
|
||||
mv88e6xxx_reg_unlock(chip);
|
||||
|
||||
return err;
|
||||
@ -1747,7 +1955,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
|
||||
bool is_static;
|
||||
int err;
|
||||
|
||||
addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
|
||||
addr.state = 0;
|
||||
eth_broadcast_addr(addr.mac);
|
||||
|
||||
do {
|
||||
@ -1755,7 +1963,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED)
|
||||
if (!addr.state)
|
||||
break;
|
||||
|
||||
if (addr.trunk || (addr.portvec & BIT(port)) == 0)
|
||||
@ -3134,6 +3342,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
|
||||
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
|
||||
.port_set_speed = mv88e6352_port_set_speed,
|
||||
.port_tag_remap = mv88e6095_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -3220,6 +3429,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
|
||||
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
|
||||
.port_set_speed = mv88e6352_port_set_speed,
|
||||
.port_tag_remap = mv88e6095_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -3305,6 +3515,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
|
||||
.port_set_speed = mv88e6390_port_set_speed,
|
||||
.port_max_speed_mode = mv88e6390_port_max_speed_mode,
|
||||
.port_tag_remap = mv88e6390_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -3353,6 +3564,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
|
||||
.port_set_speed = mv88e6390x_port_set_speed,
|
||||
.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
|
||||
.port_tag_remap = mv88e6390_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -3450,6 +3662,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
|
||||
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
|
||||
.port_set_speed = mv88e6352_port_set_speed,
|
||||
.port_tag_remap = mv88e6095_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -3541,6 +3754,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
|
||||
.port_set_speed = mv88e6390_port_set_speed,
|
||||
.port_max_speed_mode = mv88e6390_port_max_speed_mode,
|
||||
.port_tag_remap = mv88e6390_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -3811,6 +4025,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
|
||||
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
|
||||
.port_set_speed = mv88e6352_port_set_speed,
|
||||
.port_tag_remap = mv88e6095_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -3865,6 +4080,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
|
||||
.port_set_speed = mv88e6390_port_set_speed,
|
||||
.port_max_speed_mode = mv88e6390_port_max_speed_mode,
|
||||
.port_tag_remap = mv88e6390_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -3917,6 +4133,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
|
||||
.port_set_speed = mv88e6390x_port_set_speed,
|
||||
.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
|
||||
.port_tag_remap = mv88e6390_port_tag_remap,
|
||||
.port_set_policy = mv88e6352_port_set_policy,
|
||||
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
||||
.port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
||||
.port_set_ether_type = mv88e6351_port_set_ether_type,
|
||||
@ -4648,6 +4865,7 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
|
||||
|
||||
mutex_init(&chip->reg_lock);
|
||||
INIT_LIST_HEAD(&chip->mdios);
|
||||
idr_init(&chip->policies);
|
||||
|
||||
return chip;
|
||||
}
|
||||
@ -4690,8 +4908,7 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
|
||||
int err;
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
|
||||
MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
|
||||
err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
|
||||
mv88e6xxx_reg_unlock(chip);
|
||||
|
||||
return err;
|
||||
@ -4733,6 +4950,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
|
||||
.set_eeprom = mv88e6xxx_set_eeprom,
|
||||
.get_regs_len = mv88e6xxx_get_regs_len,
|
||||
.get_regs = mv88e6xxx_get_regs,
|
||||
.get_rxnfc = mv88e6xxx_get_rxnfc,
|
||||
.set_rxnfc = mv88e6xxx_set_rxnfc,
|
||||
.set_ageing_time = mv88e6xxx_set_ageing_time,
|
||||
.port_bridge_join = mv88e6xxx_port_bridge_join,
|
||||
.port_bridge_leave = mv88e6xxx_port_bridge_leave,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#ifndef _MV88E6XXX_CHIP_H
|
||||
#define _MV88E6XXX_CHIP_H
|
||||
|
||||
#include <linux/idr.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
@ -189,6 +190,33 @@ struct mv88e6xxx_port_hwtstamp {
|
||||
struct hwtstamp_config tstamp_config;
|
||||
};
|
||||
|
||||
enum mv88e6xxx_policy_mapping {
|
||||
MV88E6XXX_POLICY_MAPPING_DA,
|
||||
MV88E6XXX_POLICY_MAPPING_SA,
|
||||
MV88E6XXX_POLICY_MAPPING_VTU,
|
||||
MV88E6XXX_POLICY_MAPPING_ETYPE,
|
||||
MV88E6XXX_POLICY_MAPPING_PPPOE,
|
||||
MV88E6XXX_POLICY_MAPPING_VBAS,
|
||||
MV88E6XXX_POLICY_MAPPING_OPT82,
|
||||
MV88E6XXX_POLICY_MAPPING_UDP,
|
||||
};
|
||||
|
||||
enum mv88e6xxx_policy_action {
|
||||
MV88E6XXX_POLICY_ACTION_NORMAL,
|
||||
MV88E6XXX_POLICY_ACTION_MIRROR,
|
||||
MV88E6XXX_POLICY_ACTION_TRAP,
|
||||
MV88E6XXX_POLICY_ACTION_DISCARD,
|
||||
};
|
||||
|
||||
struct mv88e6xxx_policy {
|
||||
enum mv88e6xxx_policy_mapping mapping;
|
||||
enum mv88e6xxx_policy_action action;
|
||||
struct ethtool_rx_flow_spec fs;
|
||||
u8 addr[ETH_ALEN];
|
||||
int port;
|
||||
u16 vid;
|
||||
};
|
||||
|
||||
struct mv88e6xxx_port {
|
||||
struct mv88e6xxx_chip *chip;
|
||||
int port;
|
||||
@ -247,6 +275,9 @@ struct mv88e6xxx_chip {
|
||||
/* List of mdio busses */
|
||||
struct list_head mdios;
|
||||
|
||||
/* Policy Control List IDs and rules */
|
||||
struct idr policies;
|
||||
|
||||
/* There can be two interrupt controllers, which are chained
|
||||
* off a GPIO as interrupt source
|
||||
*/
|
||||
@ -381,6 +412,10 @@ struct mv88e6xxx_ops {
|
||||
|
||||
int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port);
|
||||
|
||||
int (*port_set_policy)(struct mv88e6xxx_chip *chip, int port,
|
||||
enum mv88e6xxx_policy_mapping mapping,
|
||||
enum mv88e6xxx_policy_action action);
|
||||
|
||||
int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port,
|
||||
enum mv88e6xxx_frame_mode mode);
|
||||
int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port,
|
||||
|
@ -128,19 +128,36 @@
|
||||
#define MV88E6XXX_G1_ATU_OP_FULL_VIOLATION BIT(4)
|
||||
|
||||
/* Offset 0x0C: ATU Data Register */
|
||||
#define MV88E6XXX_G1_ATU_DATA 0x0c
|
||||
#define MV88E6XXX_G1_ATU_DATA_TRUNK 0x8000
|
||||
#define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK 0x00f0
|
||||
#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK 0x3ff0
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MASK 0x000f
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UNUSED 0x0000
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_MGMT 0x000d
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC 0x000e
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_PRIO_OVER 0x000f
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_NONE_RATE 0x0005
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC 0x0007
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_MGMT 0x000e
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_PRIO_OVER 0x000f
|
||||
#define MV88E6XXX_G1_ATU_DATA 0x0c
|
||||
#define MV88E6XXX_G1_ATU_DATA_TRUNK 0x8000
|
||||
#define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK 0x00f0
|
||||
#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK 0x3ff0
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MASK 0x000f
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED 0x0000
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_1_OLDEST 0x0001
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_2 0x0002
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_3 0x0003
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_4 0x0004
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_5 0x0005
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_6 0x0006
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST 0x0007
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY 0x0008
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY_PO 0x0009
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_AVB_NRL 0x000a
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_AVB_NRL_PO 0x000b
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_DA_MGMT 0x000c
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_DA_MGMT_PO 0x000d
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC 0x000e
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_PO 0x000f
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED 0x0000
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY 0x0004
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_AVB_NRL 0x0005
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_DA_MGMT 0x0006
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC 0x0007
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY_PO 0x000c
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_AVB_NRL_PO 0x000d
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_DA_MGMT_PO 0x000e
|
||||
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_PO 0x000f
|
||||
|
||||
/* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1
|
||||
* Offset 0x0E: ATU MAC Address Register Bytes 2 & 3
|
||||
|
@ -135,7 +135,7 @@ static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
|
||||
return err;
|
||||
|
||||
entry->state = val & 0xf;
|
||||
if (entry->state != MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
|
||||
if (entry->state) {
|
||||
entry->trunk = !!(val & MV88E6XXX_G1_ATU_DATA_TRUNK);
|
||||
entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip);
|
||||
}
|
||||
@ -148,7 +148,7 @@ static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip,
|
||||
{
|
||||
u16 data = entry->state & 0xf;
|
||||
|
||||
if (entry->state != MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
|
||||
if (entry->state) {
|
||||
if (entry->trunk)
|
||||
data |= MV88E6XXX_G1_ATU_DATA_TRUNK;
|
||||
|
||||
@ -209,7 +209,7 @@ int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
|
||||
return err;
|
||||
|
||||
/* Write the MAC address to iterate from only once */
|
||||
if (entry->state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) {
|
||||
if (!entry->state) {
|
||||
err = mv88e6xxx_g1_atu_mac_write(chip, entry);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -1341,3 +1341,77 @@ int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Offset 0x0E: Policy Control Register */
|
||||
|
||||
int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,
|
||||
enum mv88e6xxx_policy_mapping mapping,
|
||||
enum mv88e6xxx_policy_action action)
|
||||
{
|
||||
u16 reg, mask, val;
|
||||
int shift;
|
||||
int err;
|
||||
|
||||
switch (mapping) {
|
||||
case MV88E6XXX_POLICY_MAPPING_DA:
|
||||
shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_DA_MASK);
|
||||
mask = MV88E6XXX_PORT_POLICY_CTL_DA_MASK;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_MAPPING_SA:
|
||||
shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_SA_MASK);
|
||||
mask = MV88E6XXX_PORT_POLICY_CTL_SA_MASK;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_MAPPING_VTU:
|
||||
shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VTU_MASK);
|
||||
mask = MV88E6XXX_PORT_POLICY_CTL_VTU_MASK;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_MAPPING_ETYPE:
|
||||
shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK);
|
||||
mask = MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_MAPPING_PPPOE:
|
||||
shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK);
|
||||
mask = MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_MAPPING_VBAS:
|
||||
shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK);
|
||||
mask = MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_MAPPING_OPT82:
|
||||
shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK);
|
||||
mask = MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_MAPPING_UDP:
|
||||
shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_UDP_MASK);
|
||||
mask = MV88E6XXX_PORT_POLICY_CTL_UDP_MASK;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case MV88E6XXX_POLICY_ACTION_NORMAL:
|
||||
val = MV88E6XXX_PORT_POLICY_CTL_NORMAL;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_ACTION_MIRROR:
|
||||
val = MV88E6XXX_PORT_POLICY_CTL_MIRROR;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_ACTION_TRAP:
|
||||
val = MV88E6XXX_PORT_POLICY_CTL_TRAP;
|
||||
break;
|
||||
case MV88E6XXX_POLICY_ACTION_DISCARD:
|
||||
val = MV88E6XXX_PORT_POLICY_CTL_DISCARD;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_POLICY_CTL, ®);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
reg &= ~mask;
|
||||
reg |= (val << shift) & mask;
|
||||
|
||||
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg);
|
||||
}
|
||||
|
@ -222,7 +222,19 @@
|
||||
#define MV88E6XXX_PORT_PRI_OVERRIDE 0x0d
|
||||
|
||||
/* Offset 0x0E: Policy Control Register */
|
||||
#define MV88E6XXX_PORT_POLICY_CTL 0x0e
|
||||
#define MV88E6XXX_PORT_POLICY_CTL 0x0e
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_DA_MASK 0xc000
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_SA_MASK 0x3000
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_VTU_MASK 0x0c00
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK 0x0300
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK 0x00c0
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK 0x0030
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK 0x000c
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_UDP_MASK 0x0003
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_NORMAL 0x0000
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_MIRROR 0x0001
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_TRAP 0x0002
|
||||
#define MV88E6XXX_PORT_POLICY_CTL_DISCARD 0x0003
|
||||
|
||||
/* Offset 0x0F: Port Special Ether Type */
|
||||
#define MV88E6XXX_PORT_ETH_TYPE 0x0f
|
||||
@ -324,6 +336,9 @@ int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
|
||||
bool unicast, bool multicast);
|
||||
int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
|
||||
bool unicast, bool multicast);
|
||||
int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,
|
||||
enum mv88e6xxx_policy_mapping mapping,
|
||||
enum mv88e6xxx_policy_action action);
|
||||
int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
|
||||
u16 etype);
|
||||
int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
|
||||
|
Loading…
x
Reference in New Issue
Block a user