mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 17:23:55 +08:00
Merge branch 'lan966x-extend-switchdev-and-mdb-support'
Horatiu Vultur says: ==================== net: lan966x: Extend switchdev with mdb support This patch series extends lan966x with mdb support by implementing the switchdev callbacks: SWITCHDEV_OBJ_ID_PORT_MDB and SWITCHDEV_OBJ_ID_HOST_MDB. It adds support for both ipv4/ipv6 entries and l2 entries. v2->v3: - rename PGID_FIRST and PGID_LAST to PGID_GP_START and PGID_GP_END - don't forget and relearn an entry for the CPU if there are more references to the cpu. v1->v2: - rename lan966x_mac_learn_impl to __lan966x_mac_learn - rename lan966x_mac_cpu_copy to lan966x_mac_ip_learn - fix grammar and typos in comments and commit messages - add reference counter for entries that copy frames to CPU ==================== Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c5bcdd8228
@ -7,4 +7,4 @@ obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
|
||||
|
||||
lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
|
||||
lan966x_mac.o lan966x_ethtool.o lan966x_switchdev.o \
|
||||
lan966x_vlan.o lan966x_fdb.o
|
||||
lan966x_vlan.o lan966x_fdb.o lan966x_mdb.o
|
||||
|
@ -68,17 +68,19 @@ static void lan966x_mac_select(struct lan966x *lan966x,
|
||||
lan_wr(mach, lan966x, ANA_MACHDATA);
|
||||
}
|
||||
|
||||
int lan966x_mac_learn(struct lan966x *lan966x, int port,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid,
|
||||
enum macaccess_entry_type type)
|
||||
static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
|
||||
bool cpu_copy,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
lan966x_mac_select(lan966x, mac, vid);
|
||||
|
||||
/* Issue a write command */
|
||||
lan_wr(ANA_MACACCESS_VALID_SET(1) |
|
||||
ANA_MACACCESS_CHANGE2SW_SET(0) |
|
||||
ANA_MACACCESS_DEST_IDX_SET(port) |
|
||||
ANA_MACACCESS_MAC_CPU_COPY_SET(cpu_copy) |
|
||||
ANA_MACACCESS_DEST_IDX_SET(pgid) |
|
||||
ANA_MACACCESS_ENTRYTYPE_SET(type) |
|
||||
ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_LEARN),
|
||||
lan966x, ANA_MACACCESS);
|
||||
@ -86,6 +88,30 @@ int lan966x_mac_learn(struct lan966x *lan966x, int port,
|
||||
return lan966x_mac_wait_for_completion(lan966x);
|
||||
}
|
||||
|
||||
/* The mask of the front ports is encoded inside the mac parameter via a call
|
||||
* to lan966x_mdb_encode_mac().
|
||||
*/
|
||||
int lan966x_mac_ip_learn(struct lan966x *lan966x,
|
||||
bool cpu_copy,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
WARN_ON(type != ENTRYTYPE_MACV4 && type != ENTRYTYPE_MACV6);
|
||||
|
||||
return __lan966x_mac_learn(lan966x, 0, cpu_copy, mac, vid, type);
|
||||
}
|
||||
|
||||
int lan966x_mac_learn(struct lan966x *lan966x, int port,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
WARN_ON(type != ENTRYTYPE_NORMAL && type != ENTRYTYPE_LOCKED);
|
||||
|
||||
return __lan966x_mac_learn(lan966x, port, false, mac, vid, type);
|
||||
}
|
||||
|
||||
int lan966x_mac_forget(struct lan966x *lan966x,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid,
|
||||
|
@ -926,6 +926,7 @@ static int lan966x_probe(struct platform_device *pdev)
|
||||
lan966x_port_init(lan966x->ports[p]);
|
||||
}
|
||||
|
||||
lan966x_mdb_init(lan966x);
|
||||
err = lan966x_fdb_init(lan966x);
|
||||
if (err)
|
||||
goto cleanup_ports;
|
||||
@ -955,6 +956,7 @@ static int lan966x_remove(struct platform_device *pdev)
|
||||
mutex_destroy(&lan966x->stats_lock);
|
||||
|
||||
lan966x_mac_purge_entries(lan966x);
|
||||
lan966x_mdb_deinit(lan966x);
|
||||
lan966x_fdb_deinit(lan966x);
|
||||
|
||||
return 0;
|
||||
|
@ -30,6 +30,8 @@
|
||||
/* Reserved amount for (SRC, PRIO) at index 8*SRC + PRIO */
|
||||
#define QSYS_Q_RSRV 95
|
||||
|
||||
#define CPU_PORT 8
|
||||
|
||||
/* Reserved PGIDs */
|
||||
#define PGID_CPU (PGID_AGGR - 6)
|
||||
#define PGID_UC (PGID_AGGR - 5)
|
||||
@ -38,14 +40,16 @@
|
||||
#define PGID_MCIPV4 (PGID_AGGR - 2)
|
||||
#define PGID_MCIPV6 (PGID_AGGR - 1)
|
||||
|
||||
/* Non-reserved PGIDs, used for general purpose */
|
||||
#define PGID_GP_START (CPU_PORT + 1)
|
||||
#define PGID_GP_END PGID_CPU
|
||||
|
||||
#define LAN966X_SPEED_NONE 0
|
||||
#define LAN966X_SPEED_2500 1
|
||||
#define LAN966X_SPEED_1000 1
|
||||
#define LAN966X_SPEED_100 2
|
||||
#define LAN966X_SPEED_10 3
|
||||
|
||||
#define CPU_PORT 8
|
||||
|
||||
/* MAC table entry types.
|
||||
* ENTRYTYPE_NORMAL is subject to aging.
|
||||
* ENTRYTYPE_LOCKED is not subject to aging.
|
||||
@ -105,6 +109,10 @@ struct lan966x {
|
||||
/* worqueue for fdb */
|
||||
struct workqueue_struct *fdb_work;
|
||||
struct list_head fdb_entries;
|
||||
|
||||
/* mdb */
|
||||
struct list_head mdb_entries;
|
||||
struct list_head pgid_entries;
|
||||
};
|
||||
|
||||
struct lan966x_port_config {
|
||||
@ -157,6 +165,11 @@ int lan966x_port_pcs_set(struct lan966x_port *port,
|
||||
struct lan966x_port_config *config);
|
||||
void lan966x_port_init(struct lan966x_port *port);
|
||||
|
||||
int lan966x_mac_ip_learn(struct lan966x *lan966x,
|
||||
bool cpu_copy,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid,
|
||||
enum macaccess_entry_type type);
|
||||
int lan966x_mac_learn(struct lan966x *lan966x, int port,
|
||||
const unsigned char mac[ETH_ALEN],
|
||||
unsigned int vid,
|
||||
@ -206,6 +219,15 @@ int lan966x_handle_fdb(struct net_device *dev,
|
||||
unsigned long event, const void *ctx,
|
||||
const struct switchdev_notifier_fdb_info *fdb_info);
|
||||
|
||||
void lan966x_mdb_init(struct lan966x *lan966x);
|
||||
void lan966x_mdb_deinit(struct lan966x *lan966x);
|
||||
int lan966x_handle_port_mdb_add(struct lan966x_port *port,
|
||||
const struct switchdev_obj *obj);
|
||||
int lan966x_handle_port_mdb_del(struct lan966x_port *port,
|
||||
const struct switchdev_obj *obj);
|
||||
void lan966x_mdb_erase_entries(struct lan966x *lan966x, u16 vid);
|
||||
void lan966x_mdb_write_entries(struct lan966x *lan966x, u16 vid);
|
||||
|
||||
static inline void __iomem *lan_addr(void __iomem *base[],
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase, int ginst,
|
||||
|
506
drivers/net/ethernet/microchip/lan966x/lan966x_mdb.c
Normal file
506
drivers/net/ethernet/microchip/lan966x/lan966x_mdb.c
Normal file
@ -0,0 +1,506 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "lan966x_main.h"
|
||||
|
||||
struct lan966x_pgid_entry {
|
||||
struct list_head list;
|
||||
int index;
|
||||
refcount_t refcount;
|
||||
u16 ports;
|
||||
};
|
||||
|
||||
struct lan966x_mdb_entry {
|
||||
struct list_head list;
|
||||
unsigned char mac[ETH_ALEN];
|
||||
u16 vid;
|
||||
u16 ports;
|
||||
struct lan966x_pgid_entry *pgid;
|
||||
u8 cpu_copy;
|
||||
};
|
||||
|
||||
void lan966x_mdb_init(struct lan966x *lan966x)
|
||||
{
|
||||
INIT_LIST_HEAD(&lan966x->mdb_entries);
|
||||
INIT_LIST_HEAD(&lan966x->pgid_entries);
|
||||
}
|
||||
|
||||
static void lan966x_mdb_purge_mdb_entries(struct lan966x *lan966x)
|
||||
{
|
||||
struct lan966x_mdb_entry *mdb_entry, *tmp;
|
||||
|
||||
list_for_each_entry_safe(mdb_entry, tmp, &lan966x->mdb_entries, list) {
|
||||
list_del(&mdb_entry->list);
|
||||
kfree(mdb_entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void lan966x_mdb_purge_pgid_entries(struct lan966x *lan966x)
|
||||
{
|
||||
struct lan966x_pgid_entry *pgid_entry, *tmp;
|
||||
|
||||
list_for_each_entry_safe(pgid_entry, tmp, &lan966x->pgid_entries, list) {
|
||||
list_del(&pgid_entry->list);
|
||||
kfree(pgid_entry);
|
||||
}
|
||||
}
|
||||
|
||||
void lan966x_mdb_deinit(struct lan966x *lan966x)
|
||||
{
|
||||
lan966x_mdb_purge_mdb_entries(lan966x);
|
||||
lan966x_mdb_purge_pgid_entries(lan966x);
|
||||
}
|
||||
|
||||
static struct lan966x_mdb_entry *
|
||||
lan966x_mdb_entry_get(struct lan966x *lan966x,
|
||||
const unsigned char *mac,
|
||||
u16 vid)
|
||||
{
|
||||
struct lan966x_mdb_entry *mdb_entry;
|
||||
|
||||
list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
|
||||
if (ether_addr_equal(mdb_entry->mac, mac) &&
|
||||
mdb_entry->vid == vid)
|
||||
return mdb_entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct lan966x_mdb_entry *
|
||||
lan966x_mdb_entry_add(struct lan966x *lan966x,
|
||||
const struct switchdev_obj_port_mdb *mdb)
|
||||
{
|
||||
struct lan966x_mdb_entry *mdb_entry;
|
||||
|
||||
mdb_entry = kzalloc(sizeof(*mdb_entry), GFP_KERNEL);
|
||||
if (!mdb_entry)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ether_addr_copy(mdb_entry->mac, mdb->addr);
|
||||
mdb_entry->vid = mdb->vid;
|
||||
|
||||
list_add_tail(&mdb_entry->list, &lan966x->mdb_entries);
|
||||
|
||||
return mdb_entry;
|
||||
}
|
||||
|
||||
static void lan966x_mdb_encode_mac(unsigned char *mac,
|
||||
struct lan966x_mdb_entry *mdb_entry,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
ether_addr_copy(mac, mdb_entry->mac);
|
||||
|
||||
if (type == ENTRYTYPE_MACV4) {
|
||||
mac[0] = 0;
|
||||
mac[1] = mdb_entry->ports >> 8;
|
||||
mac[2] = mdb_entry->ports & 0xff;
|
||||
} else if (type == ENTRYTYPE_MACV6) {
|
||||
mac[0] = mdb_entry->ports >> 8;
|
||||
mac[1] = mdb_entry->ports & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static int lan966x_mdb_ip_add(struct lan966x_port *port,
|
||||
const struct switchdev_obj_port_mdb *mdb,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
struct lan966x_mdb_entry *mdb_entry;
|
||||
unsigned char mac[ETH_ALEN];
|
||||
bool cpu_copy = false;
|
||||
|
||||
mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
|
||||
if (!mdb_entry) {
|
||||
mdb_entry = lan966x_mdb_entry_add(lan966x, mdb);
|
||||
if (IS_ERR(mdb_entry))
|
||||
return PTR_ERR(mdb_entry);
|
||||
} else {
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
if (cpu_port)
|
||||
mdb_entry->cpu_copy++;
|
||||
else
|
||||
mdb_entry->ports |= BIT(port->chip_port);
|
||||
|
||||
/* Copy the frame to CPU only if the CPU is in the VLAN */
|
||||
if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, mdb_entry->vid) &&
|
||||
mdb_entry->cpu_copy)
|
||||
cpu_copy = true;
|
||||
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
return lan966x_mac_ip_learn(lan966x, cpu_copy,
|
||||
mac, mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
static int lan966x_mdb_ip_del(struct lan966x_port *port,
|
||||
const struct switchdev_obj_port_mdb *mdb,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
struct lan966x_mdb_entry *mdb_entry;
|
||||
unsigned char mac[ETH_ALEN];
|
||||
u16 ports;
|
||||
|
||||
mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
|
||||
if (!mdb_entry)
|
||||
return -ENOENT;
|
||||
|
||||
ports = mdb_entry->ports;
|
||||
if (cpu_port) {
|
||||
/* If there are still other references to the CPU port then
|
||||
* there is no point to delete and add again the same entry
|
||||
*/
|
||||
mdb_entry->cpu_copy--;
|
||||
if (mdb_entry->cpu_copy)
|
||||
return 0;
|
||||
} else {
|
||||
ports &= ~BIT(port->chip_port);
|
||||
}
|
||||
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
|
||||
|
||||
mdb_entry->ports = ports;
|
||||
|
||||
if (!mdb_entry->ports && !mdb_entry->cpu_copy) {
|
||||
list_del(&mdb_entry->list);
|
||||
kfree(mdb_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
return lan966x_mac_ip_learn(lan966x, mdb_entry->cpu_copy,
|
||||
mac, mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
static struct lan966x_pgid_entry *
|
||||
lan966x_pgid_entry_add(struct lan966x *lan966x, int index, u16 ports)
|
||||
{
|
||||
struct lan966x_pgid_entry *pgid_entry;
|
||||
|
||||
pgid_entry = kzalloc(sizeof(*pgid_entry), GFP_KERNEL);
|
||||
if (!pgid_entry)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pgid_entry->ports = ports;
|
||||
pgid_entry->index = index;
|
||||
refcount_set(&pgid_entry->refcount, 1);
|
||||
|
||||
list_add_tail(&pgid_entry->list, &lan966x->pgid_entries);
|
||||
|
||||
return pgid_entry;
|
||||
}
|
||||
|
||||
static struct lan966x_pgid_entry *
|
||||
lan966x_pgid_entry_get(struct lan966x *lan966x,
|
||||
struct lan966x_mdb_entry *mdb_entry)
|
||||
{
|
||||
struct lan966x_pgid_entry *pgid_entry;
|
||||
int index;
|
||||
|
||||
/* Try to find an existing pgid that uses the same ports as the
|
||||
* mdb_entry
|
||||
*/
|
||||
list_for_each_entry(pgid_entry, &lan966x->pgid_entries, list) {
|
||||
if (pgid_entry->ports == mdb_entry->ports) {
|
||||
refcount_inc(&pgid_entry->refcount);
|
||||
return pgid_entry;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to find an empty pgid entry and allocate one in case it finds it,
|
||||
* otherwise it means that there are no more resources
|
||||
*/
|
||||
for (index = PGID_GP_START; index < PGID_GP_END; index++) {
|
||||
bool used = false;
|
||||
|
||||
list_for_each_entry(pgid_entry, &lan966x->pgid_entries, list) {
|
||||
if (pgid_entry->index == index) {
|
||||
used = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!used)
|
||||
return lan966x_pgid_entry_add(lan966x, index,
|
||||
mdb_entry->ports);
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENOSPC);
|
||||
}
|
||||
|
||||
static void lan966x_pgid_entry_del(struct lan966x *lan966x,
|
||||
struct lan966x_pgid_entry *pgid_entry)
|
||||
{
|
||||
if (!refcount_dec_and_test(&pgid_entry->refcount))
|
||||
return;
|
||||
|
||||
list_del(&pgid_entry->list);
|
||||
kfree(pgid_entry);
|
||||
}
|
||||
|
||||
static int lan966x_mdb_l2_add(struct lan966x_port *port,
|
||||
const struct switchdev_obj_port_mdb *mdb,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
struct lan966x_pgid_entry *pgid_entry;
|
||||
struct lan966x_mdb_entry *mdb_entry;
|
||||
unsigned char mac[ETH_ALEN];
|
||||
|
||||
mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
|
||||
if (!mdb_entry) {
|
||||
mdb_entry = lan966x_mdb_entry_add(lan966x, mdb);
|
||||
if (IS_ERR(mdb_entry))
|
||||
return PTR_ERR(mdb_entry);
|
||||
} else {
|
||||
lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
if (cpu_port) {
|
||||
mdb_entry->ports |= BIT(CPU_PORT);
|
||||
mdb_entry->cpu_copy++;
|
||||
} else {
|
||||
mdb_entry->ports |= BIT(port->chip_port);
|
||||
}
|
||||
|
||||
pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
|
||||
if (IS_ERR(pgid_entry)) {
|
||||
list_del(&mdb_entry->list);
|
||||
kfree(mdb_entry);
|
||||
return PTR_ERR(pgid_entry);
|
||||
}
|
||||
mdb_entry->pgid = pgid_entry;
|
||||
|
||||
/* Copy the frame to CPU only if the CPU is in the VLAN */
|
||||
if (!lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, mdb_entry->vid) &&
|
||||
mdb_entry->cpu_copy)
|
||||
mdb_entry->ports &= BIT(CPU_PORT);
|
||||
|
||||
lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
|
||||
ANA_PGID_PGID,
|
||||
lan966x, ANA_PGID(pgid_entry->index));
|
||||
|
||||
return lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
|
||||
mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
static int lan966x_mdb_l2_del(struct lan966x_port *port,
|
||||
const struct switchdev_obj_port_mdb *mdb,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
bool cpu_port = netif_is_bridge_master(mdb->obj.orig_dev);
|
||||
struct lan966x *lan966x = port->lan966x;
|
||||
struct lan966x_pgid_entry *pgid_entry;
|
||||
struct lan966x_mdb_entry *mdb_entry;
|
||||
unsigned char mac[ETH_ALEN];
|
||||
u16 ports;
|
||||
|
||||
mdb_entry = lan966x_mdb_entry_get(lan966x, mdb->addr, mdb->vid);
|
||||
if (!mdb_entry)
|
||||
return -ENOENT;
|
||||
|
||||
ports = mdb_entry->ports;
|
||||
if (cpu_port) {
|
||||
/* If there are still other references to the CPU port then
|
||||
* there is no point to delete and add again the same entry
|
||||
*/
|
||||
mdb_entry->cpu_copy--;
|
||||
if (mdb_entry->cpu_copy)
|
||||
return 0;
|
||||
|
||||
ports &= ~BIT(CPU_PORT);
|
||||
} else {
|
||||
ports &= ~BIT(port->chip_port);
|
||||
}
|
||||
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
|
||||
lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
|
||||
|
||||
mdb_entry->ports = ports;
|
||||
|
||||
if (!mdb_entry->ports) {
|
||||
list_del(&mdb_entry->list);
|
||||
kfree(mdb_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
|
||||
if (IS_ERR(pgid_entry)) {
|
||||
list_del(&mdb_entry->list);
|
||||
kfree(mdb_entry);
|
||||
return PTR_ERR(pgid_entry);
|
||||
}
|
||||
mdb_entry->pgid = pgid_entry;
|
||||
|
||||
lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
|
||||
ANA_PGID_PGID,
|
||||
lan966x, ANA_PGID(pgid_entry->index));
|
||||
|
||||
return lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
|
||||
mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
static enum macaccess_entry_type
|
||||
lan966x_mdb_classify(const unsigned char *mac)
|
||||
{
|
||||
if (mac[0] == 0x01 && mac[1] == 0x00 && mac[2] == 0x5e)
|
||||
return ENTRYTYPE_MACV4;
|
||||
if (mac[0] == 0x33 && mac[1] == 0x33)
|
||||
return ENTRYTYPE_MACV6;
|
||||
return ENTRYTYPE_LOCKED;
|
||||
}
|
||||
|
||||
int lan966x_handle_port_mdb_add(struct lan966x_port *port,
|
||||
const struct switchdev_obj *obj)
|
||||
{
|
||||
const struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
|
||||
enum macaccess_entry_type type;
|
||||
|
||||
/* Split the way the entries are added for ipv4/ipv6 and for l2. The
|
||||
* reason is that for ipv4/ipv6 it doesn't require to use any pgid
|
||||
* entry, while for l2 is required to use pgid entries
|
||||
*/
|
||||
type = lan966x_mdb_classify(mdb->addr);
|
||||
if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
|
||||
return lan966x_mdb_ip_add(port, mdb, type);
|
||||
|
||||
return lan966x_mdb_l2_add(port, mdb, type);
|
||||
}
|
||||
|
||||
int lan966x_handle_port_mdb_del(struct lan966x_port *port,
|
||||
const struct switchdev_obj *obj)
|
||||
{
|
||||
const struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
|
||||
enum macaccess_entry_type type;
|
||||
|
||||
/* Split the way the entries are removed for ipv4/ipv6 and for l2. The
|
||||
* reason is that for ipv4/ipv6 it doesn't require to use any pgid
|
||||
* entry, while for l2 is required to use pgid entries
|
||||
*/
|
||||
type = lan966x_mdb_classify(mdb->addr);
|
||||
if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
|
||||
return lan966x_mdb_ip_del(port, mdb, type);
|
||||
|
||||
return lan966x_mdb_l2_del(port, mdb, type);
|
||||
}
|
||||
|
||||
static void lan966x_mdb_ip_cpu_copy(struct lan966x *lan966x,
|
||||
struct lan966x_mdb_entry *mdb_entry,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
unsigned char mac[ETH_ALEN];
|
||||
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
|
||||
lan966x_mac_ip_learn(lan966x, true, mac, mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
static void lan966x_mdb_l2_cpu_copy(struct lan966x *lan966x,
|
||||
struct lan966x_mdb_entry *mdb_entry,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
struct lan966x_pgid_entry *pgid_entry;
|
||||
unsigned char mac[ETH_ALEN];
|
||||
|
||||
lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
|
||||
|
||||
mdb_entry->ports |= BIT(CPU_PORT);
|
||||
|
||||
pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
|
||||
if (IS_ERR(pgid_entry))
|
||||
return;
|
||||
|
||||
mdb_entry->pgid = pgid_entry;
|
||||
|
||||
lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
|
||||
ANA_PGID_PGID,
|
||||
lan966x, ANA_PGID(pgid_entry->index));
|
||||
|
||||
lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
|
||||
mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
void lan966x_mdb_write_entries(struct lan966x *lan966x, u16 vid)
|
||||
{
|
||||
struct lan966x_mdb_entry *mdb_entry;
|
||||
enum macaccess_entry_type type;
|
||||
|
||||
list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
|
||||
if (mdb_entry->vid != vid || !mdb_entry->cpu_copy)
|
||||
continue;
|
||||
|
||||
type = lan966x_mdb_classify(mdb_entry->mac);
|
||||
if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
|
||||
lan966x_mdb_ip_cpu_copy(lan966x, mdb_entry, type);
|
||||
else
|
||||
lan966x_mdb_l2_cpu_copy(lan966x, mdb_entry, type);
|
||||
}
|
||||
}
|
||||
|
||||
static void lan966x_mdb_ip_cpu_remove(struct lan966x *lan966x,
|
||||
struct lan966x_mdb_entry *mdb_entry,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
unsigned char mac[ETH_ALEN];
|
||||
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
|
||||
lan966x_mac_ip_learn(lan966x, false, mac, mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
static void lan966x_mdb_l2_cpu_remove(struct lan966x *lan966x,
|
||||
struct lan966x_mdb_entry *mdb_entry,
|
||||
enum macaccess_entry_type type)
|
||||
{
|
||||
struct lan966x_pgid_entry *pgid_entry;
|
||||
unsigned char mac[ETH_ALEN];
|
||||
|
||||
lan966x_pgid_entry_del(lan966x, mdb_entry->pgid);
|
||||
lan966x_mdb_encode_mac(mac, mdb_entry, type);
|
||||
lan966x_mac_forget(lan966x, mac, mdb_entry->vid, type);
|
||||
|
||||
mdb_entry->ports &= ~BIT(CPU_PORT);
|
||||
|
||||
pgid_entry = lan966x_pgid_entry_get(lan966x, mdb_entry);
|
||||
if (IS_ERR(pgid_entry))
|
||||
return;
|
||||
|
||||
mdb_entry->pgid = pgid_entry;
|
||||
|
||||
lan_rmw(ANA_PGID_PGID_SET(mdb_entry->ports),
|
||||
ANA_PGID_PGID,
|
||||
lan966x, ANA_PGID(pgid_entry->index));
|
||||
|
||||
lan966x_mac_learn(lan966x, pgid_entry->index, mdb_entry->mac,
|
||||
mdb_entry->vid, type);
|
||||
}
|
||||
|
||||
void lan966x_mdb_erase_entries(struct lan966x *lan966x, u16 vid)
|
||||
{
|
||||
struct lan966x_mdb_entry *mdb_entry;
|
||||
enum macaccess_entry_type type;
|
||||
|
||||
list_for_each_entry(mdb_entry, &lan966x->mdb_entries, list) {
|
||||
if (mdb_entry->vid != vid || !mdb_entry->cpu_copy)
|
||||
continue;
|
||||
|
||||
type = lan966x_mdb_classify(mdb_entry->mac);
|
||||
if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6)
|
||||
lan966x_mdb_ip_cpu_remove(lan966x, mdb_entry, type);
|
||||
else
|
||||
lan966x_mdb_l2_cpu_remove(lan966x, mdb_entry, type);
|
||||
}
|
||||
}
|
@ -169,6 +169,12 @@ enum lan966x_target {
|
||||
#define ANA_MACACCESS_CHANGE2SW_GET(x)\
|
||||
FIELD_GET(ANA_MACACCESS_CHANGE2SW, x)
|
||||
|
||||
#define ANA_MACACCESS_MAC_CPU_COPY BIT(16)
|
||||
#define ANA_MACACCESS_MAC_CPU_COPY_SET(x)\
|
||||
FIELD_PREP(ANA_MACACCESS_MAC_CPU_COPY, x)
|
||||
#define ANA_MACACCESS_MAC_CPU_COPY_GET(x)\
|
||||
FIELD_GET(ANA_MACACCESS_MAC_CPU_COPY, x)
|
||||
|
||||
#define ANA_MACACCESS_VALID BIT(12)
|
||||
#define ANA_MACACCESS_VALID_SET(x)\
|
||||
FIELD_PREP(ANA_MACACCESS_VALID, x)
|
||||
|
@ -438,6 +438,10 @@ static int lan966x_handle_port_obj_add(struct net_device *dev, const void *ctx,
|
||||
case SWITCHDEV_OBJ_ID_PORT_VLAN:
|
||||
err = lan966x_handle_port_vlan_add(port, obj);
|
||||
break;
|
||||
case SWITCHDEV_OBJ_ID_PORT_MDB:
|
||||
case SWITCHDEV_OBJ_ID_HOST_MDB:
|
||||
err = lan966x_handle_port_mdb_add(port, obj);
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
@ -473,6 +477,10 @@ static int lan966x_handle_port_obj_del(struct net_device *dev, const void *ctx,
|
||||
case SWITCHDEV_OBJ_ID_PORT_VLAN:
|
||||
err = lan966x_handle_port_vlan_del(port, obj);
|
||||
break;
|
||||
case SWITCHDEV_OBJ_ID_PORT_MDB:
|
||||
case SWITCHDEV_OBJ_ID_HOST_MDB:
|
||||
err = lan966x_handle_port_mdb_del(port, obj);
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
|
@ -219,6 +219,7 @@ void lan966x_vlan_port_add_vlan(struct lan966x_port *port,
|
||||
if (lan966x_vlan_cpu_member_cpu_vlan_mask(lan966x, vid)) {
|
||||
lan966x_vlan_cpu_add_vlan_mask(lan966x, vid);
|
||||
lan966x_fdb_write_entries(lan966x, vid);
|
||||
lan966x_mdb_write_entries(lan966x, vid);
|
||||
}
|
||||
|
||||
lan966x_vlan_port_set_vid(port, vid, pvid, untagged);
|
||||
@ -241,6 +242,7 @@ void lan966x_vlan_port_del_vlan(struct lan966x_port *port, u16 vid)
|
||||
if (!lan966x_vlan_port_any_vlan_mask(lan966x, vid)) {
|
||||
lan966x_vlan_cpu_del_vlan_mask(lan966x, vid);
|
||||
lan966x_fdb_erase_entries(lan966x, vid);
|
||||
lan966x_mdb_erase_entries(lan966x, vid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,8 +256,10 @@ void lan966x_vlan_cpu_add_vlan(struct lan966x *lan966x, u16 vid)
|
||||
* information so when a front port is added then it would add also the
|
||||
* CPU port.
|
||||
*/
|
||||
if (lan966x_vlan_port_any_vlan_mask(lan966x, vid))
|
||||
if (lan966x_vlan_port_any_vlan_mask(lan966x, vid)) {
|
||||
lan966x_vlan_cpu_add_vlan_mask(lan966x, vid);
|
||||
lan966x_mdb_write_entries(lan966x, vid);
|
||||
}
|
||||
|
||||
lan966x_vlan_cpu_add_cpu_vlan_mask(lan966x, vid);
|
||||
lan966x_fdb_write_entries(lan966x, vid);
|
||||
@ -267,6 +271,7 @@ void lan966x_vlan_cpu_del_vlan(struct lan966x *lan966x, u16 vid)
|
||||
lan966x_vlan_cpu_del_cpu_vlan_mask(lan966x, vid);
|
||||
lan966x_vlan_cpu_del_vlan_mask(lan966x, vid);
|
||||
lan966x_fdb_erase_entries(lan966x, vid);
|
||||
lan966x_mdb_erase_entries(lan966x, vid);
|
||||
}
|
||||
|
||||
void lan966x_vlan_init(struct lan966x *lan966x)
|
||||
|
Loading…
Reference in New Issue
Block a user