Commit 4bb2f84a authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents c21815f1 da7dc875
...@@ -1497,7 +1497,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, ...@@ -1497,7 +1497,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
fid = vlan.fid; fid = vlan.fid;
} }
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; entry.state = 0;
ether_addr_copy(entry.mac, addr); ether_addr_copy(entry.mac, addr);
eth_addr_dec(entry.mac); eth_addr_dec(entry.mac);
...@@ -1506,17 +1506,16 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, ...@@ -1506,17 +1506,16 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
return err; return err;
/* Initialize a fresh ATU entry if it isn't found */ /* Initialize a fresh ATU entry if it isn't found */
if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED || if (!entry.state || !ether_addr_equal(entry.mac, addr)) {
!ether_addr_equal(entry.mac, addr)) {
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
ether_addr_copy(entry.mac, addr); ether_addr_copy(entry.mac, addr);
} }
/* Purge the ATU entry only if no port is using it anymore */ /* 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); entry.portvec &= ~BIT(port);
if (!entry.portvec) if (!entry.portvec)
entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; entry.state = 0;
} else { } else {
entry.portvec |= BIT(port); entry.portvec |= BIT(port);
entry.state = state; entry.state = state;
...@@ -1525,6 +1524,216 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, ...@@ -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); 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, static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
u16 vid) u16 vid)
{ {
...@@ -1732,8 +1941,7 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, ...@@ -1732,8 +1941,7 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
int err; int err;
mv88e6xxx_reg_lock(chip); mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
mv88e6xxx_reg_unlock(chip); mv88e6xxx_reg_unlock(chip);
return err; return err;
...@@ -1747,7 +1955,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, ...@@ -1747,7 +1955,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
bool is_static; bool is_static;
int err; int err;
addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; addr.state = 0;
eth_broadcast_addr(addr.mac); eth_broadcast_addr(addr.mac);
do { do {
...@@ -1755,7 +1963,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, ...@@ -1755,7 +1963,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
if (err) if (err)
return err; return err;
if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) if (!addr.state)
break; break;
if (addr.trunk || (addr.portvec & BIT(port)) == 0) if (addr.trunk || (addr.portvec & BIT(port)) == 0)
...@@ -3134,6 +3342,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { ...@@ -3134,6 +3342,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed, .port_set_speed = mv88e6352_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -3220,6 +3429,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { ...@@ -3220,6 +3429,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed, .port_set_speed = mv88e6352_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -3305,6 +3515,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { ...@@ -3305,6 +3515,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.port_set_speed = mv88e6390_port_set_speed, .port_set_speed = mv88e6390_port_set_speed,
.port_max_speed_mode = mv88e6390_port_max_speed_mode, .port_max_speed_mode = mv88e6390_port_max_speed_mode,
.port_tag_remap = mv88e6390_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -3353,6 +3564,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { ...@@ -3353,6 +3564,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.port_set_speed = mv88e6390x_port_set_speed, .port_set_speed = mv88e6390x_port_set_speed,
.port_max_speed_mode = mv88e6390x_port_max_speed_mode, .port_max_speed_mode = mv88e6390x_port_max_speed_mode,
.port_tag_remap = mv88e6390_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -3450,6 +3662,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { ...@@ -3450,6 +3662,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed, .port_set_speed = mv88e6352_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -3541,6 +3754,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { ...@@ -3541,6 +3754,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.port_set_speed = mv88e6390_port_set_speed, .port_set_speed = mv88e6390_port_set_speed,
.port_max_speed_mode = mv88e6390_port_max_speed_mode, .port_max_speed_mode = mv88e6390_port_max_speed_mode,
.port_tag_remap = mv88e6390_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -3811,6 +4025,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { ...@@ -3811,6 +4025,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
.port_set_speed = mv88e6352_port_set_speed, .port_set_speed = mv88e6352_port_set_speed,
.port_tag_remap = mv88e6095_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -3865,6 +4080,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { ...@@ -3865,6 +4080,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.port_set_speed = mv88e6390_port_set_speed, .port_set_speed = mv88e6390_port_set_speed,
.port_max_speed_mode = mv88e6390_port_max_speed_mode, .port_max_speed_mode = mv88e6390_port_max_speed_mode,
.port_tag_remap = mv88e6390_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -3917,6 +4133,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { ...@@ -3917,6 +4133,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.port_set_speed = mv88e6390x_port_set_speed, .port_set_speed = mv88e6390x_port_set_speed,
.port_max_speed_mode = mv88e6390x_port_max_speed_mode, .port_max_speed_mode = mv88e6390x_port_max_speed_mode,
.port_tag_remap = mv88e6390_port_tag_remap, .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_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_egress_floods = mv88e6352_port_set_egress_floods,
.port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_ether_type = mv88e6351_port_set_ether_type,
...@@ -4648,6 +4865,7 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) ...@@ -4648,6 +4865,7 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
mutex_init(&chip->reg_lock); mutex_init(&chip->reg_lock);
INIT_LIST_HEAD(&chip->mdios); INIT_LIST_HEAD(&chip->mdios);
idr_init(&chip->policies);
return chip; return chip;
} }
...@@ -4690,8 +4908,7 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, ...@@ -4690,8 +4908,7 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
int err; int err;
mv88e6xxx_reg_lock(chip); mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, 0);
MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
mv88e6xxx_reg_unlock(chip); mv88e6xxx_reg_unlock(chip);
return err; return err;
...@@ -4733,6 +4950,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { ...@@ -4733,6 +4950,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.set_eeprom = mv88e6xxx_set_eeprom, .set_eeprom = mv88e6xxx_set_eeprom,
.get_regs_len = mv88e6xxx_get_regs_len, .get_regs_len = mv88e6xxx_get_regs_len,
.get_regs = mv88e6xxx_get_regs, .get_regs = mv88e6xxx_get_regs,
.get_rxnfc = mv88e6xxx_get_rxnfc,
.set_rxnfc = mv88e6xxx_set_rxnfc,
.set_ageing_time = mv88e6xxx_set_ageing_time, .set_ageing_time = mv88e6xxx_set_ageing_time,
.port_bridge_join = mv88e6xxx_port_bridge_join, .port_bridge_join = mv88e6xxx_port_bridge_join,
.port_bridge_leave = mv88e6xxx_port_bridge_leave, .port_bridge_leave = mv88e6xxx_port_bridge_leave,
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#ifndef _MV88E6XXX_CHIP_H #ifndef _MV88E6XXX_CHIP_H
#define _MV88E6XXX_CHIP_H #define _MV88E6XXX_CHIP_H
#include <linux/idr.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
...@@ -189,6 +190,33 @@ struct mv88e6xxx_port_hwtstamp { ...@@ -189,6 +190,33 @@ struct mv88e6xxx_port_hwtstamp {
struct hwtstamp_config tstamp_config; 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_port {
struct mv88e6xxx_chip *chip; struct mv88e6xxx_chip *chip;
int port; int port;
...@@ -247,6 +275,9 @@ struct mv88e6xxx_chip { ...@@ -247,6 +275,9 @@ struct mv88e6xxx_chip {
/* List of mdio busses */ /* List of mdio busses */
struct list_head mdios; struct list_head mdios;
/* Policy Control List IDs and rules */
struct idr policies;
/* There can be two interrupt controllers, which are chained /* There can be two interrupt controllers, which are chained
* off a GPIO as interrupt source * off a GPIO as interrupt source
*/ */
...@@ -381,6 +412,10 @@ struct mv88e6xxx_ops { ...@@ -381,6 +412,10 @@ struct mv88e6xxx_ops {
int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port); 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, int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port,
enum mv88e6xxx_frame_mode mode); enum mv88e6xxx_frame_mode mode);
int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port, int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port,
......
...@@ -133,14 +133,31 @@ ...@@ -133,14 +133,31 @@
#define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK 0x00f0 #define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK 0x00f0
#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 #define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK 0x3ff0
#define MV88E6XXX_G1_ATU_DATA_STATE_MASK 0x000f #define MV88E6XXX_G1_ATU_DATA_STATE_MASK 0x000f
#define MV88E6XXX_G1_ATU_DATA_STATE_UNUSED 0x0000 #define MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED 0x0000
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_MGMT 0x000d #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 0x000e
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_PRIO_OVER 0x000f #define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_PO 0x000f
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_NONE_RATE 0x0005 #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 0x0007
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_MGMT 0x000e #define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY_PO 0x000c
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_PRIO_OVER 0x000f #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 0x0D: ATU MAC Address Register Bytes 0 & 1
* Offset 0x0E: ATU MAC Address Register Bytes 2 & 3 * Offset 0x0E: ATU MAC Address Register Bytes 2 & 3
......
...@@ -135,7 +135,7 @@ static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip, ...@@ -135,7 +135,7 @@ static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
return err; return err;
entry->state = val & 0xf; 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->trunk = !!(val & MV88E6XXX_G1_ATU_DATA_TRUNK);
entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip); entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip);
} }
...@@ -148,7 +148,7 @@ static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip, ...@@ -148,7 +148,7 @@ static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip,
{ {
u16 data = entry->state & 0xf; u16 data = entry->state & 0xf;
if (entry->state != MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) { if (entry->state) {
if (entry->trunk) if (entry->trunk)
data |= MV88E6XXX_G1_ATU_DATA_TRUNK; data |= MV88E6XXX_G1_ATU_DATA_TRUNK;
...@@ -209,7 +209,7 @@ int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid, ...@@ -209,7 +209,7 @@ int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
return err; return err;
/* Write the MAC address to iterate from only once */ /* 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); err = mv88e6xxx_g1_atu_mac_write(chip, entry);
if (err) if (err)
return err; return err;
......
...@@ -1341,3 +1341,77 @@ int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port) ...@@ -1341,3 +1341,77 @@ int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
return 0; 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, &reg);
if (err)
return err;
reg &= ~mask;
reg |= (val << shift) & mask;
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg);
}
...@@ -223,6 +223,18 @@ ...@@ -223,6 +223,18 @@
/* Offset 0x0E: Policy Control Register */ /* 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 */ /* Offset 0x0F: Port Special Ether Type */
#define MV88E6XXX_PORT_ETH_TYPE 0x0f #define MV88E6XXX_PORT_ETH_TYPE 0x0f
...@@ -324,6 +336,9 @@ int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, ...@@ -324,6 +336,9 @@ int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
bool unicast, bool multicast); bool unicast, bool multicast);
int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port,
bool unicast, bool multicast); 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, int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
u16 etype); u16 etype);
int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,
......
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