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
This diff is collapsed.
...@@ -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,
......
...@@ -128,19 +128,36 @@ ...@@ -128,19 +128,36 @@
#define MV88E6XXX_G1_ATU_OP_FULL_VIOLATION BIT(4) #define MV88E6XXX_G1_ATU_OP_FULL_VIOLATION BIT(4)
/* Offset 0x0C: ATU Data Register */ /* Offset 0x0C: ATU Data Register */
#define MV88E6XXX_G1_ATU_DATA 0x0c #define MV88E6XXX_G1_ATU_DATA 0x0c
#define MV88E6XXX_G1_ATU_DATA_TRUNK 0x8000 #define MV88E6XXX_G1_ATU_DATA_TRUNK 0x8000
#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_STATIC 0x000e #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_2 0x0002
#define MV88E6XXX_G1_ATU_DATA_STATE_UC_PRIO_OVER 0x000f #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_3 0x0003
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_NONE_RATE 0x0005 #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_4 0x0004
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC 0x0007 #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_5 0x0005
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_MGMT 0x000e #define MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_6 0x0006
#define MV88E6XXX_G1_ATU_DATA_STATE_MC_PRIO_OVER 0x000f #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 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);
}
...@@ -222,7 +222,19 @@ ...@@ -222,7 +222,19 @@
#define MV88E6XXX_PORT_PRI_OVERRIDE 0x0d #define MV88E6XXX_PORT_PRI_OVERRIDE 0x0d
/* 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