net: lan966x: More MAC table functionality
This patch adds support for adding/removing mac entries in the SW list of entries and in the HW table. This is used by the bridge functionality. Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
5ccd66e01c
commit
25ee9561ec
|
@ -111,6 +111,14 @@ int lan966x_mac_cpu_forget(struct lan966x *lan966x, const char *addr, u16 vid)
|
||||||
return lan966x_mac_forget(lan966x, addr, vid, ENTRYTYPE_LOCKED);
|
return lan966x_mac_forget(lan966x, addr, vid, ENTRYTYPE_LOCKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lan966x_mac_set_ageing(struct lan966x *lan966x,
|
||||||
|
u32 ageing)
|
||||||
|
{
|
||||||
|
lan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(ageing / 2),
|
||||||
|
ANA_AUTOAGE_AGE_PERIOD,
|
||||||
|
lan966x, ANA_AUTOAGE);
|
||||||
|
}
|
||||||
|
|
||||||
void lan966x_mac_init(struct lan966x *lan966x)
|
void lan966x_mac_init(struct lan966x *lan966x)
|
||||||
{
|
{
|
||||||
/* Clear the MAC table */
|
/* Clear the MAC table */
|
||||||
|
@ -137,6 +145,48 @@ static struct lan966x_mac_entry *lan966x_mac_alloc_entry(const unsigned char *ma
|
||||||
return mac_entry;
|
return mac_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct lan966x_mac_entry *lan966x_mac_find_entry(struct lan966x *lan966x,
|
||||||
|
const unsigned char *mac,
|
||||||
|
u16 vid, u16 port_index)
|
||||||
|
{
|
||||||
|
struct lan966x_mac_entry *res = NULL;
|
||||||
|
struct lan966x_mac_entry *mac_entry;
|
||||||
|
|
||||||
|
spin_lock(&lan966x->mac_lock);
|
||||||
|
list_for_each_entry(mac_entry, &lan966x->mac_entries, list) {
|
||||||
|
if (mac_entry->vid == vid &&
|
||||||
|
ether_addr_equal(mac, mac_entry->mac) &&
|
||||||
|
mac_entry->port_index == port_index) {
|
||||||
|
res = mac_entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&lan966x->mac_lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lan966x_mac_lookup(struct lan966x *lan966x,
|
||||||
|
const unsigned char mac[ETH_ALEN],
|
||||||
|
unsigned int vid, enum macaccess_entry_type type)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lan966x_mac_select(lan966x, mac, vid);
|
||||||
|
|
||||||
|
/* Issue a read command */
|
||||||
|
lan_wr(ANA_MACACCESS_ENTRYTYPE_SET(type) |
|
||||||
|
ANA_MACACCESS_VALID_SET(1) |
|
||||||
|
ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_READ),
|
||||||
|
lan966x, ANA_MACACCESS);
|
||||||
|
|
||||||
|
ret = lan966x_mac_wait_for_completion(lan966x);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return ANA_MACACCESS_VALID_GET(lan_rd(lan966x, ANA_MACACCESS));
|
||||||
|
}
|
||||||
|
|
||||||
static void lan966x_fdb_call_notifiers(enum switchdev_notifier_type type,
|
static void lan966x_fdb_call_notifiers(enum switchdev_notifier_type type,
|
||||||
const char *mac, u16 vid,
|
const char *mac, u16 vid,
|
||||||
struct net_device *dev)
|
struct net_device *dev)
|
||||||
|
@ -149,6 +199,61 @@ static void lan966x_fdb_call_notifiers(enum switchdev_notifier_type type,
|
||||||
call_switchdev_notifiers(type, dev, &info.info, NULL);
|
call_switchdev_notifiers(type, dev, &info.info, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lan966x_mac_add_entry(struct lan966x *lan966x, struct lan966x_port *port,
|
||||||
|
const unsigned char *addr, u16 vid)
|
||||||
|
{
|
||||||
|
struct lan966x_mac_entry *mac_entry;
|
||||||
|
|
||||||
|
if (lan966x_mac_lookup(lan966x, addr, vid, ENTRYTYPE_NORMAL))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* In case the entry already exists, don't add it again to SW,
|
||||||
|
* just update HW, but we need to look in the actual HW because
|
||||||
|
* it is possible for an entry to be learn by HW and before we
|
||||||
|
* get the interrupt the frame will reach CPU and the CPU will
|
||||||
|
* add the entry but without the extern_learn flag.
|
||||||
|
*/
|
||||||
|
mac_entry = lan966x_mac_find_entry(lan966x, addr, vid, port->chip_port);
|
||||||
|
if (mac_entry)
|
||||||
|
return lan966x_mac_learn(lan966x, port->chip_port,
|
||||||
|
addr, vid, ENTRYTYPE_LOCKED);
|
||||||
|
|
||||||
|
mac_entry = lan966x_mac_alloc_entry(addr, vid, port->chip_port);
|
||||||
|
if (!mac_entry)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
spin_lock(&lan966x->mac_lock);
|
||||||
|
list_add_tail(&mac_entry->list, &lan966x->mac_entries);
|
||||||
|
spin_unlock(&lan966x->mac_lock);
|
||||||
|
|
||||||
|
lan966x_mac_learn(lan966x, port->chip_port, addr, vid, ENTRYTYPE_LOCKED);
|
||||||
|
lan966x_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, addr, vid, port->dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lan966x_mac_del_entry(struct lan966x *lan966x, const unsigned char *addr,
|
||||||
|
u16 vid)
|
||||||
|
{
|
||||||
|
struct lan966x_mac_entry *mac_entry, *tmp;
|
||||||
|
|
||||||
|
spin_lock(&lan966x->mac_lock);
|
||||||
|
list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,
|
||||||
|
list) {
|
||||||
|
if (mac_entry->vid == vid &&
|
||||||
|
ether_addr_equal(addr, mac_entry->mac)) {
|
||||||
|
lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,
|
||||||
|
ENTRYTYPE_LOCKED);
|
||||||
|
|
||||||
|
list_del(&mac_entry->list);
|
||||||
|
kfree(mac_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&lan966x->mac_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void lan966x_mac_purge_entries(struct lan966x *lan966x)
|
void lan966x_mac_purge_entries(struct lan966x *lan966x)
|
||||||
{
|
{
|
||||||
struct lan966x_mac_entry *mac_entry, *tmp;
|
struct lan966x_mac_entry *mac_entry, *tmp;
|
||||||
|
|
|
@ -145,6 +145,15 @@ int lan966x_mac_forget(struct lan966x *lan966x,
|
||||||
int lan966x_mac_cpu_learn(struct lan966x *lan966x, const char *addr, u16 vid);
|
int lan966x_mac_cpu_learn(struct lan966x *lan966x, const char *addr, u16 vid);
|
||||||
int lan966x_mac_cpu_forget(struct lan966x *lan966x, const char *addr, u16 vid);
|
int lan966x_mac_cpu_forget(struct lan966x *lan966x, const char *addr, u16 vid);
|
||||||
void lan966x_mac_init(struct lan966x *lan966x);
|
void lan966x_mac_init(struct lan966x *lan966x);
|
||||||
|
void lan966x_mac_set_ageing(struct lan966x *lan966x,
|
||||||
|
u32 ageing);
|
||||||
|
int lan966x_mac_del_entry(struct lan966x *lan966x,
|
||||||
|
const unsigned char *addr,
|
||||||
|
u16 vid);
|
||||||
|
int lan966x_mac_add_entry(struct lan966x *lan966x,
|
||||||
|
struct lan966x_port *port,
|
||||||
|
const unsigned char *addr,
|
||||||
|
u16 vid);
|
||||||
void lan966x_mac_purge_entries(struct lan966x *lan966x);
|
void lan966x_mac_purge_entries(struct lan966x *lan966x);
|
||||||
irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x);
|
irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue