diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 93c0a4d0e33a..1fd149dd6115 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o -icssm-prueth-y := icssm/icssm_prueth.o +icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o obj-$(CONFIG_TI_CPSW) += cpsw-common.o obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h index 8e7e0af08144..4b50133c5a72 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h @@ -15,6 +15,7 @@ #include "icssm_switch.h" #include "icssm_prueth_ptp.h" +#include "icssm_prueth_fdb_tbl.h" /* ICSSM size of redundancy tag */ #define ICSSM_LRE_TAG_SIZE 6 @@ -248,6 +249,8 @@ struct prueth { struct prueth_emac *emac[PRUETH_NUM_MACS]; struct net_device *registered_netdevs[PRUETH_NUM_MACS]; + struct fdb_tbl *fdb_tbl; + unsigned int eth_type; size_t ocmc_ram_size; u8 emac_configured; diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h new file mode 100644 index 000000000000..9089259d96ea --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_fdb_tbl.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2019-2021 Texas Instruments Incorporated - https://www.ti.com */ +#ifndef __NET_TI_PRUSS_FDB_TBL_H +#define __NET_TI_PRUSS_FDB_TBL_H + +#include +#include +#include "icssm_prueth.h" + +/* 4 bytes */ +struct fdb_index_tbl_entry { + /* Bucket Table index of first Bucket with this MAC address */ + u16 bucket_idx; + u16 bucket_entries; /* Number of entries in this bucket */ +}; + +/* 4 * 256 = 1024 = 0x200 bytes */ +struct fdb_index_array { + struct fdb_index_tbl_entry index_tbl_entry[FDB_INDEX_TBL_MAX_ENTRIES]; +}; + +/* 10 bytes */ +struct fdb_mac_tbl_entry { + u8 mac[ETH_ALEN]; + u16 age; + u8 port; /* 0 based: 0=port1, 1=port2 */ + union { + struct { + u8 is_static:1; + u8 active:1; + }; + u8 flags; + }; +}; + +/* 10 * 256 = 2560 = 0xa00 bytes */ +struct fdb_mac_tbl_array { + struct fdb_mac_tbl_entry mac_tbl_entry[FDB_MAC_TBL_MAX_ENTRIES]; +}; + +/* 1 byte */ +struct fdb_stp_config { + u8 state; /* per-port STP state (defined in FW header) */ +}; + +/* 1 byte */ +struct fdb_flood_config { + u8 host_flood_enable:1; + u8 port1_flood_enable:1; + u8 port2_flood_enable:1; +}; + +/* 2 byte */ +struct fdb_arbitration { + u8 host_lock; + u8 pru_locks; +}; + +struct fdb_tbl { + /* fdb index table */ + struct fdb_index_array __iomem *index_a; + /* fdb MAC table */ + struct fdb_mac_tbl_array __iomem *mac_tbl_a; + /* port 1 stp config */ + struct fdb_stp_config __iomem *port1_stp_cfg; + /* port 2 stp config */ + struct fdb_stp_config __iomem *port2_stp_cfg; + /* per-port flood enable */ + struct fdb_flood_config __iomem *flood_enable_flags; + /* fdb locking mechanism */ + struct fdb_arbitration __iomem *locks; + /* total number of entries in hash table */ + u16 total_entries; +}; + +#endif diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c new file mode 100644 index 000000000000..2d13f62ab0c3 --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Texas Instruments PRUETH Switch Driver + * + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com + */ +#include +#include +#include +#include +#include "icssm_prueth.h" +#include "icssm_prueth_switch.h" +#include "icssm_prueth_fdb_tbl.h" + +#define FDB_IDX_TBL_ENTRY(n) (&prueth->fdb_tbl->index_a->index_tbl_entry[n]) + +#define FDB_MAC_TBL_ENTRY(n) (&prueth->fdb_tbl->mac_tbl_a->mac_tbl_entry[n]) + +#define FLAG_IS_STATIC BIT(0) +#define FLAG_ACTIVE BIT(1) + +void icssm_prueth_sw_free_fdb_table(struct prueth *prueth) +{ + if (prueth->emac_configured) + return; + + kfree(prueth->fdb_tbl); + prueth->fdb_tbl = NULL; +} + +void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth) +{ + struct fdb_tbl *t = prueth->fdb_tbl; + void __iomem *sram_base; + u8 val; + + sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va; + + t->index_a = sram_base + V2_1_FDB_TBL_OFFSET; + t->mac_tbl_a = sram_base + FDB_MAC_TBL_OFFSET; + t->port1_stp_cfg = sram_base + FDB_PORT1_STP_CFG_OFFSET; + t->port2_stp_cfg = sram_base + FDB_PORT2_STP_CFG_OFFSET; + t->flood_enable_flags = sram_base + FDB_FLOOD_ENABLE_FLAGS_OFFSET; + t->locks = sram_base + FDB_LOCKS_OFFSET; + + val = readb(t->flood_enable_flags); + /* host_flood_enable = 1 */ + val |= BIT(0); + /* port1_flood_enable = 1 */ + val |= BIT(1); + /* port2_flood_enable = 1 */ + val |= BIT(2); + writeb(val, t->flood_enable_flags); + + writeb(0, &t->locks->host_lock); + t->total_entries = 0; +} + +static u8 icssm_pru_lock_done(struct fdb_tbl *fdb_tbl) +{ + return readb(&fdb_tbl->locks->pru_locks); +} + +static int icssm_prueth_sw_fdb_spin_lock(struct fdb_tbl *fdb_tbl) +{ + u8 done; + int ret; + + /* Take the host lock */ + writeb(1, &fdb_tbl->locks->host_lock); + + /* Wait for the PRUs to release their locks */ + ret = read_poll_timeout(icssm_pru_lock_done, done, done == 0, + 1, 10, false, fdb_tbl); + if (ret == -ETIMEDOUT) + writeb(0, &fdb_tbl->locks->host_lock); + + return ret; +} + +static void icssm_prueth_sw_fdb_spin_unlock(struct fdb_tbl *fdb_tbl) +{ + writeb(0, &fdb_tbl->locks->host_lock); +} + +static u8 icssm_prueth_sw_fdb_hash(const u8 *mac) +{ + return (mac[0] ^ mac[1] ^ mac[2] ^ mac[3] ^ mac[4] ^ mac[5]); +} + +static int +icssm_prueth_sw_fdb_search(struct fdb_mac_tbl_array __iomem *mac_tbl, + struct fdb_index_tbl_entry __iomem *bucket_info, + const u8 *mac) +{ + unsigned int bucket_entries, mac_tbl_idx; + u8 tmp_mac[ETH_ALEN]; + int i; + + mac_tbl_idx = readw(&bucket_info->bucket_idx); + bucket_entries = readw(&bucket_info->bucket_entries); + for (i = 0; i < bucket_entries; i++, mac_tbl_idx++) { + memcpy_fromio(tmp_mac, mac_tbl->mac_tbl_entry[mac_tbl_idx].mac, + ETH_ALEN); + if (ether_addr_equal(mac, tmp_mac)) + return mac_tbl_idx; + } + + return -ENODATA; +} + +static int icssm_prueth_sw_fdb_find_open_slot(struct fdb_tbl *fdb_tbl) +{ + unsigned int i; + u8 flags; + + for (i = 0; i < FDB_MAC_TBL_MAX_ENTRIES; i++) { + flags = readb(&fdb_tbl->mac_tbl_a->mac_tbl_entry[i].flags); + if (!(flags & FLAG_ACTIVE)) + break; + } + + return i; +} + +static int +icssm_prueth_sw_find_fdb_insert(struct fdb_tbl *fdb, struct prueth *prueth, + struct fdb_index_tbl_entry __iomem *bkt_info, + const u8 *mac, const u8 port) +{ + struct fdb_mac_tbl_array __iomem *mac_tbl = fdb->mac_tbl_a; + unsigned int bucket_entries, mac_tbl_idx; + struct fdb_mac_tbl_entry __iomem *e; + u8 mac_from_hw[ETH_ALEN]; + s8 cmp; + int i; + + mac_tbl_idx = readw(&bkt_info->bucket_idx); + bucket_entries = readw(&bkt_info->bucket_entries); + + for (i = 0; i < bucket_entries; i++, mac_tbl_idx++) { + e = &mac_tbl->mac_tbl_entry[mac_tbl_idx]; + memcpy_fromio(mac_from_hw, e->mac, ETH_ALEN); + cmp = memcmp(mac, mac_from_hw, ETH_ALEN); + if (cmp < 0) { + return mac_tbl_idx; + } else if (cmp == 0) { + if (readb(&e->port) != port) { + /* MAC is already in FDB, only port is + * different. So just update the port. + * Note: total_entries and bucket_entries + * remain the same. + */ + writeb(port, &e->port); + } + + /* MAC and port are the same, touch the fdb */ + writew(0, &e->age); + return -EEXIST; + } + } + + return mac_tbl_idx; +} + +static int +icssm_prueth_sw_fdb_empty_slot_left(struct fdb_mac_tbl_array __iomem *mac_tbl, + unsigned int mac_tbl_idx) +{ + u8 flags; + int i; + + for (i = mac_tbl_idx - 1; i > -1; i--) { + flags = readb(&mac_tbl->mac_tbl_entry[i].flags); + if (!(flags & FLAG_ACTIVE)) + break; + } + + return i; +} + +static int +icssm_prueth_sw_fdb_empty_slot_right(struct fdb_mac_tbl_array __iomem *mac_tbl, + unsigned int mac_tbl_idx) +{ + u8 flags; + int i; + + for (i = mac_tbl_idx; i < FDB_MAC_TBL_MAX_ENTRIES; i++) { + flags = readb(&mac_tbl->mac_tbl_entry[i].flags); + if (!(flags & FLAG_ACTIVE)) + return i; + } + + return -1; +} + +static void icssm_prueth_sw_fdb_move_range_left(struct prueth *prueth, + u16 left, u16 right) +{ + struct fdb_mac_tbl_entry entry; + u32 sz = 0; + u16 i; + + sz = sizeof(struct fdb_mac_tbl_entry); + for (i = left; i < right; i++) { + memcpy_fromio(&entry, FDB_MAC_TBL_ENTRY(i + 1), sz); + memcpy_toio(FDB_MAC_TBL_ENTRY(i), &entry, sz); + } +} + +static void icssm_prueth_sw_fdb_move_range_right(struct prueth *prueth, + u16 left, u16 right) +{ + struct fdb_mac_tbl_entry entry; + u32 sz = 0; + u16 i; + + sz = sizeof(struct fdb_mac_tbl_entry); + for (i = right; i > left; i--) { + memcpy_fromio(&entry, FDB_MAC_TBL_ENTRY(i - 1), sz); + memcpy_toio(FDB_MAC_TBL_ENTRY(i), &entry, sz); + } +} + +static void icssm_prueth_sw_fdb_update_index_tbl(struct prueth *prueth, + u16 left, u16 right) +{ + unsigned int hash, hash_prev; + u8 mac[ETH_ALEN]; + unsigned int i; + + /* To ensure we don't improperly update the + * bucket index, initialize with an invalid + * hash in case we are in leftmost slot + */ + hash_prev = 0xff; + + if (left > 0) { + memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(left - 1)->mac, ETH_ALEN); + hash_prev = icssm_prueth_sw_fdb_hash(mac); + } + + /* For each moved element, update the bucket index */ + for (i = left; i <= right; i++) { + memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(i)->mac, ETH_ALEN); + hash = icssm_prueth_sw_fdb_hash(mac); + + /* Only need to update buckets once */ + if (hash != hash_prev) + writew(i, &FDB_IDX_TBL_ENTRY(hash)->bucket_idx); + + hash_prev = hash; + } +} + +static struct fdb_mac_tbl_entry __iomem * +icssm_prueth_sw_find_free_mac(struct prueth *prueth, struct fdb_index_tbl_entry + __iomem *bucket_info, u8 suggested_mac_tbl_idx, + bool *update_indexes, const u8 *mac) +{ + s16 empty_slot_idx = 0, left = 0, right = 0; + unsigned int mti = suggested_mac_tbl_idx; + struct fdb_mac_tbl_array __iomem *mt; + struct fdb_tbl *fdb; + u8 flags; + + fdb = prueth->fdb_tbl; + mt = fdb->mac_tbl_a; + + flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags); + if (!(flags & FLAG_ACTIVE)) { + /* Claim the entry */ + flags |= FLAG_ACTIVE; + writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags); + + return FDB_MAC_TBL_ENTRY(mti); + } + + if (fdb->total_entries == FDB_MAC_TBL_MAX_ENTRIES) + return NULL; + + empty_slot_idx = icssm_prueth_sw_fdb_empty_slot_left(mt, mti); + if (empty_slot_idx == -1) { + /* Nothing available on the left. But table isn't full + * so there must be space to the right, + */ + empty_slot_idx = icssm_prueth_sw_fdb_empty_slot_right(mt, mti); + + /* Shift right */ + left = mti; + right = empty_slot_idx; + icssm_prueth_sw_fdb_move_range_right(prueth, left, right); + + /* Claim the entry */ + flags = readb(&FDB_MAC_TBL_ENTRY(mti)->flags); + flags |= FLAG_ACTIVE; + writeb(flags, &FDB_MAC_TBL_ENTRY(mti)->flags); + + memcpy_toio(FDB_MAC_TBL_ENTRY(mti)->mac, mac, ETH_ALEN); + + /* There is a chance we moved something in a + * different bucket, update index table + */ + icssm_prueth_sw_fdb_update_index_tbl(prueth, left, right); + + return FDB_MAC_TBL_ENTRY(mti); + } + + if (empty_slot_idx == mti - 1) { + /* There is space immediately left of the open slot, + * which means the inserted MAC address + * must be the lowest-valued MAC address in bucket. + * Update bucket pointer accordingly. + */ + writew(empty_slot_idx, &bucket_info->bucket_idx); + + /* Claim the entry */ + flags = readb(&FDB_MAC_TBL_ENTRY(empty_slot_idx)->flags); + flags |= FLAG_ACTIVE; + writeb(flags, &FDB_MAC_TBL_ENTRY(empty_slot_idx)->flags); + + return FDB_MAC_TBL_ENTRY(empty_slot_idx); + } + + /* There is empty space to the left, shift MAC table entries left */ + left = empty_slot_idx; + right = mti - 1; + icssm_prueth_sw_fdb_move_range_left(prueth, left, right); + + /* Claim the entry */ + flags = readb(&FDB_MAC_TBL_ENTRY(mti - 1)->flags); + flags |= FLAG_ACTIVE; + writeb(flags, &FDB_MAC_TBL_ENTRY(mti - 1)->flags); + + memcpy_toio(FDB_MAC_TBL_ENTRY(mti - 1)->mac, mac, ETH_ALEN); + + /* There is a chance we moved something in a + * different bucket, update index table + */ + icssm_prueth_sw_fdb_update_index_tbl(prueth, left, right); + + return FDB_MAC_TBL_ENTRY(mti - 1); +} + +static int icssm_prueth_sw_insert_fdb_entry(struct prueth_emac *emac, + const u8 *mac, u8 is_static) +{ + struct fdb_index_tbl_entry __iomem *bucket_info; + struct fdb_mac_tbl_entry __iomem *mac_info; + struct prueth *prueth = emac->prueth; + unsigned int hash_val, mac_tbl_idx; + struct prueth_emac *other_emac; + enum prueth_port other_port_id; + int total_fdb_entries; + struct fdb_tbl *fdb; + u8 flags; + s16 ret; + int err; + u16 val; + + fdb = prueth->fdb_tbl; + other_port_id = (emac->port_id == PRUETH_PORT_MII0) ? + PRUETH_PORT_MII1 : PRUETH_PORT_MII0; + + other_emac = prueth->emac[other_port_id - 1]; + if (!other_emac) + return -EINVAL; + + err = icssm_prueth_sw_fdb_spin_lock(fdb); + if (err) { + dev_err(prueth->dev, "PRU lock timeout %d\n", err); + return err; + } + + if (fdb->total_entries == FDB_MAC_TBL_MAX_ENTRIES) { + icssm_prueth_sw_fdb_spin_unlock(fdb); + return -ENOMEM; + } + + if (ether_addr_equal(mac, emac->mac_addr) || + (ether_addr_equal(mac, other_emac->mac_addr))) { + icssm_prueth_sw_fdb_spin_unlock(fdb); + /* Don't insert fdb of own mac addr */ + return -EINVAL; + } + + /* Get the bucket that the mac belongs to */ + hash_val = icssm_prueth_sw_fdb_hash(mac); + bucket_info = FDB_IDX_TBL_ENTRY(hash_val); + + if (!readw(&bucket_info->bucket_entries)) { + mac_tbl_idx = icssm_prueth_sw_fdb_find_open_slot(fdb); + writew(mac_tbl_idx, &bucket_info->bucket_idx); + } + + ret = icssm_prueth_sw_find_fdb_insert(fdb, prueth, bucket_info, mac, + emac->port_id - 1); + if (ret < 0) { + icssm_prueth_sw_fdb_spin_unlock(fdb); + /* mac is already in fdb table */ + return 0; + } + + mac_tbl_idx = ret; + + mac_info = icssm_prueth_sw_find_free_mac(prueth, bucket_info, + mac_tbl_idx, NULL, + mac); + if (!mac_info) { + /* Should not happen */ + dev_warn(prueth->dev, "OUT of FDB MEM\n"); + icssm_prueth_sw_fdb_spin_unlock(fdb); + return -ENOMEM; + } + + memcpy_toio(mac_info->mac, mac, ETH_ALEN); + writew(0, &mac_info->age); + writeb(emac->port_id - 1, &mac_info->port); + + flags = readb(&mac_info->flags); + if (is_static) + flags |= FLAG_IS_STATIC; + else + flags &= ~FLAG_IS_STATIC; + + /* bit 1 - active */ + flags |= FLAG_ACTIVE; + writeb(flags, &mac_info->flags); + + val = readw(&bucket_info->bucket_entries); + val++; + writew(val, &bucket_info->bucket_entries); + + fdb->total_entries++; + + total_fdb_entries = fdb->total_entries; + + icssm_prueth_sw_fdb_spin_unlock(fdb); + + dev_dbg(prueth->dev, "added fdb: %pM port=%d total_entries=%u\n", + mac, emac->port_id, total_fdb_entries); + + return 0; +} + +static int icssm_prueth_sw_delete_fdb_entry(struct prueth_emac *emac, + const u8 *mac, u8 is_static) +{ + struct fdb_index_tbl_entry __iomem *bucket_info; + struct fdb_mac_tbl_entry __iomem *mac_info; + struct fdb_mac_tbl_array __iomem *mt; + unsigned int hash_val, mac_tbl_idx; + unsigned int idx, entries; + struct prueth *prueth; + int total_fdb_entries; + s16 ret, left, right; + struct fdb_tbl *fdb; + u8 flags; + int err; + u16 val; + + prueth = emac->prueth; + fdb = prueth->fdb_tbl; + mt = fdb->mac_tbl_a; + + err = icssm_prueth_sw_fdb_spin_lock(fdb); + if (err) { + dev_err(prueth->dev, "PRU lock timeout %d\n", err); + return err; + } + + if (fdb->total_entries == 0) { + icssm_prueth_sw_fdb_spin_unlock(fdb); + return 0; + } + + /* Get the bucket that the mac belongs to */ + hash_val = icssm_prueth_sw_fdb_hash(mac); + bucket_info = FDB_IDX_TBL_ENTRY(hash_val); + + ret = icssm_prueth_sw_fdb_search(mt, bucket_info, mac); + if (ret < 0) { + icssm_prueth_sw_fdb_spin_unlock(fdb); + return ret; + } + + mac_tbl_idx = ret; + mac_info = FDB_MAC_TBL_ENTRY(mac_tbl_idx); + + /* Shift all elements in bucket to the left. No need to + * update index table since only shifting within bucket. + */ + left = mac_tbl_idx; + idx = readw(&bucket_info->bucket_idx); + entries = readw(&bucket_info->bucket_entries); + right = idx + entries - 1; + icssm_prueth_sw_fdb_move_range_left(prueth, left, right); + + /* Remove end of bucket from table */ + mac_info = FDB_MAC_TBL_ENTRY(right); + flags = readb(&mac_info->flags); + /* active = 0 */ + flags &= ~FLAG_ACTIVE; + writeb(flags, &mac_info->flags); + val = readw(&bucket_info->bucket_entries); + val--; + writew(val, &bucket_info->bucket_entries); + fdb->total_entries--; + + total_fdb_entries = fdb->total_entries; + + icssm_prueth_sw_fdb_spin_unlock(fdb); + + dev_dbg(prueth->dev, "del fdb: %pM total_entries=%u\n", + mac, total_fdb_entries); + + return 0; +} + +int icssm_prueth_sw_do_purge_fdb(struct prueth_emac *emac) +{ + struct fdb_index_tbl_entry __iomem *bucket_info; + struct prueth *prueth = emac->prueth; + u8 flags, mac[ETH_ALEN]; + unsigned int hash_val; + struct fdb_tbl *fdb; + int ret, i; + u16 val; + + fdb = prueth->fdb_tbl; + + ret = icssm_prueth_sw_fdb_spin_lock(fdb); + if (ret) { + dev_err(prueth->dev, "PRU lock timeout %d\n", ret); + return ret; + } + + if (fdb->total_entries == 0) { + icssm_prueth_sw_fdb_spin_unlock(fdb); + return 0; + } + + for (i = 0; i < FDB_MAC_TBL_MAX_ENTRIES; i++) { + flags = readb(&fdb->mac_tbl_a->mac_tbl_entry[i].flags); + if ((flags & FLAG_ACTIVE) && !(flags & FLAG_IS_STATIC)) { + /* Get the bucket that the mac belongs to */ + memcpy_fromio(mac, FDB_MAC_TBL_ENTRY(i)->mac, + ETH_ALEN); + hash_val = icssm_prueth_sw_fdb_hash(mac); + bucket_info = FDB_IDX_TBL_ENTRY(hash_val); + flags &= ~FLAG_ACTIVE; + writeb(flags, + &fdb->mac_tbl_a->mac_tbl_entry[i].flags); + val = readw(&bucket_info->bucket_entries); + val--; + writew(val, &bucket_info->bucket_entries); + fdb->total_entries--; + } + } + + icssm_prueth_sw_fdb_spin_unlock(fdb); + return 0; +} + +int icssm_prueth_sw_init_fdb_table(struct prueth *prueth) +{ + if (prueth->emac_configured) + return 0; + + prueth->fdb_tbl = kmalloc(sizeof(*prueth->fdb_tbl), GFP_KERNEL); + if (!prueth->fdb_tbl) + return -ENOMEM; + + icssm_prueth_sw_fdb_tbl_init(prueth); + + return 0; +} + +/** + * icssm_prueth_sw_fdb_add - insert fdb entry + * + * @emac: EMAC data structure + * @fdb: fdb info + * + */ +void icssm_prueth_sw_fdb_add(struct prueth_emac *emac, + struct switchdev_notifier_fdb_info *fdb) +{ + icssm_prueth_sw_insert_fdb_entry(emac, fdb->addr, 1); +} + +/** + * icssm_prueth_sw_fdb_del - delete fdb entry + * + * @emac: EMAC data structure + * @fdb: fdb info + * + */ +void icssm_prueth_sw_fdb_del(struct prueth_emac *emac, + struct switchdev_notifier_fdb_info *fdb) +{ + icssm_prueth_sw_delete_fdb_entry(emac, fdb->addr, 1); +} diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h new file mode 100644 index 000000000000..fd013ecdc707 --- /dev/null +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_switch.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com + */ + +#ifndef __NET_TI_PRUETH_SWITCH_H +#define __NET_TI_PRUETH_SWITCH_H + +#include "icssm_prueth.h" +#include "icssm_prueth_fdb_tbl.h" + +void icssm_prueth_sw_fdb_tbl_init(struct prueth *prueth); +int icssm_prueth_sw_init_fdb_table(struct prueth *prueth); +void icssm_prueth_sw_free_fdb_table(struct prueth *prueth); +int icssm_prueth_sw_do_purge_fdb(struct prueth_emac *emac); +void icssm_prueth_sw_fdb_add(struct prueth_emac *emac, + struct switchdev_notifier_fdb_info *fdb); +void icssm_prueth_sw_fdb_del(struct prueth_emac *emac, + struct switchdev_notifier_fdb_info *fdb); + +#endif /* __NET_TI_PRUETH_SWITCH_H */ diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h index 8b494ffdcde7..4200ccb1b425 100644 --- a/drivers/net/ethernet/ti/icssm/icssm_switch.h +++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h @@ -254,4 +254,30 @@ #define P0_COL_BUFFER_OFFSET 0xEE00 #define P0_Q1_BUFFER_OFFSET 0x0000 +#define V2_1_FDB_TBL_LOC PRUETH_MEM_SHARED_RAM +#define V2_1_FDB_TBL_OFFSET 0x2000 + +#define FDB_INDEX_TBL_MAX_ENTRIES 256 +#define FDB_MAC_TBL_MAX_ENTRIES 256 + +#define FDB_INDEX_TBL_OFFSET V2_1_FDB_TBL_OFFSET +#define FDB_INDEX_TBL_SIZE (FDB_INDEX_TBL_MAX_ENTRIES * \ + sizeof(struct fdb_index_tbl_entry)) + +#define FDB_MAC_TBL_OFFSET (FDB_INDEX_TBL_OFFSET + FDB_INDEX_TBL_SIZE) +#define FDB_MAC_TBL_SIZE (FDB_MAC_TBL_MAX_ENTRIES * \ + sizeof(struct fdb_mac_tbl_entry)) + +#define FDB_PORT1_STP_CFG_OFFSET (FDB_MAC_TBL_OFFSET + FDB_MAC_TBL_SIZE) +#define FDB_PORT_STP_CFG_SIZE sizeof(struct fdb_stp_config) +#define FDB_PORT2_STP_CFG_OFFSET (FDB_PORT1_STP_CFG_OFFSET + \ + FDB_PORT_STP_CFG_SIZE) + +#define FDB_FLOOD_ENABLE_FLAGS_OFFSET (FDB_PORT2_STP_CFG_OFFSET + \ + FDB_PORT_STP_CFG_SIZE) +#define FDB_FLOOD_ENABLE_FLAGS_SIZE sizeof(struct fdb_flood_config) + +#define FDB_LOCKS_OFFSET (FDB_FLOOD_ENABLE_FLAGS_OFFSET + \ + FDB_FLOOD_ENABLE_FLAGS_SIZE) + #endif /* __ICSS_SWITCH_H */