mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-10 06:34:17 +08:00
staging: fsl-dpaa2/ethsw: add .ndo_fdb_dump callback
Implement the .ndo_fdb_dump callback for the switch net devices. The list of all offloaded FDB entries is retrieved through the dpsw_fdb_dump() firmware call. Filter the entries by the switch port on which the callback was called and for each of them create a new neighbour message. Also remove the requirement from the TODO list. Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com> Link: https://lore.kernel.org/r/1564416712-16946-4-git-send-email-ioana.ciornei@nxp.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b380a4e6e5
commit
de01ac2e49
@ -1,7 +1,6 @@
|
||||
* Add I/O capabilities on switch port netdevices. This will allow control
|
||||
traffic to reach the CPU.
|
||||
* Add ACL to redirect control traffic to CPU.
|
||||
* Add support for displaying learned FDB entries
|
||||
* Add support for multiple FDBs and switch port partitioning
|
||||
* MC firmware uprev; the DPAA2 objects used by the Ethernet Switch driver
|
||||
need to be kept in sync with binary interface changes in MC
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
/* DPSW Version */
|
||||
#define DPSW_VER_MAJOR 8
|
||||
#define DPSW_VER_MINOR 0
|
||||
#define DPSW_VER_MINOR 1
|
||||
|
||||
#define DPSW_CMD_BASE_VERSION 1
|
||||
#define DPSW_CMD_ID_OFFSET 4
|
||||
@ -67,6 +67,7 @@
|
||||
#define DPSW_CMDID_FDB_ADD_MULTICAST DPSW_CMD_ID(0x086)
|
||||
#define DPSW_CMDID_FDB_REMOVE_MULTICAST DPSW_CMD_ID(0x087)
|
||||
#define DPSW_CMDID_FDB_SET_LEARNING_MODE DPSW_CMD_ID(0x088)
|
||||
#define DPSW_CMDID_FDB_DUMP DPSW_CMD_ID(0x08A)
|
||||
|
||||
/* Macros for accessing command fields smaller than 1byte */
|
||||
#define DPSW_MASK(field) \
|
||||
@ -351,6 +352,18 @@ struct dpsw_cmd_fdb_set_learning_mode {
|
||||
u8 mode;
|
||||
};
|
||||
|
||||
struct dpsw_cmd_fdb_dump {
|
||||
__le16 fdb_id;
|
||||
__le16 pad0;
|
||||
__le32 pad1;
|
||||
__le64 iova_addr;
|
||||
__le32 iova_size;
|
||||
};
|
||||
|
||||
struct dpsw_rsp_fdb_dump {
|
||||
__le16 num_entries;
|
||||
};
|
||||
|
||||
struct dpsw_rsp_get_api_version {
|
||||
__le16 version_major;
|
||||
__le16 version_minor;
|
||||
|
@ -980,6 +980,57 @@ int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io,
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpsw_fdb_dump() - Dump the content of FDB table into memory.
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
||||
* @token: Token of DPSW object
|
||||
* @fdb_id: Forwarding Database Identifier
|
||||
* @iova_addr: Data will be stored here as an array of struct fdb_dump_entry
|
||||
* @iova_size: Memory size allocated at iova_addr
|
||||
* @num_entries:Number of entries written at iova_addr
|
||||
*
|
||||
* Return: Completion status. '0' on Success; Error code otherwise.
|
||||
*
|
||||
* The memory allocated at iova_addr must be initialized with zero before
|
||||
* command execution. If the FDB table does not fit into memory MC will stop
|
||||
* after the memory is filled up.
|
||||
* The struct fdb_dump_entry array must be parsed until the end of memory
|
||||
* area or until an entry with mac_addr set to zero is found.
|
||||
*/
|
||||
int dpsw_fdb_dump(struct fsl_mc_io *mc_io,
|
||||
u32 cmd_flags,
|
||||
u16 token,
|
||||
u16 fdb_id,
|
||||
u64 iova_addr,
|
||||
u32 iova_size,
|
||||
u16 *num_entries)
|
||||
{
|
||||
struct dpsw_cmd_fdb_dump *cmd_params;
|
||||
struct dpsw_rsp_fdb_dump *rsp_params;
|
||||
struct fsl_mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_DUMP,
|
||||
cmd_flags,
|
||||
token);
|
||||
cmd_params = (struct dpsw_cmd_fdb_dump *)cmd.params;
|
||||
cmd_params->fdb_id = cpu_to_le16(fdb_id);
|
||||
cmd_params->iova_addr = cpu_to_le64(iova_addr);
|
||||
cmd_params->iova_size = cpu_to_le32(iova_size);
|
||||
|
||||
/* send command to mc */
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rsp_params = (struct dpsw_rsp_fdb_dump *)cmd.params;
|
||||
*num_entries = le16_to_cpu(rsp_params->num_entries);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpsw_fdb_remove_unicast() - removes an entry from MAC lookup table
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
|
@ -465,6 +465,31 @@ int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io,
|
||||
u16 fdb_id,
|
||||
const struct dpsw_fdb_unicast_cfg *cfg);
|
||||
|
||||
#define DPSW_FDB_ENTRY_TYPE_DYNAMIC BIT(0)
|
||||
#define DPSW_FDB_ENTRY_TYPE_UNICAST BIT(1)
|
||||
|
||||
/**
|
||||
* struct fdb_dump_entry - fdb snapshot entry
|
||||
* @mac_addr: MAC address
|
||||
* @type: bit0 - DINAMIC(1)/STATIC(0), bit1 - UNICAST(1)/MULTICAST(0)
|
||||
* @if_info: unicast - egress interface, multicast - number of egress interfaces
|
||||
* @if_mask: multicast - egress interface mask
|
||||
*/
|
||||
struct fdb_dump_entry {
|
||||
u8 mac_addr[6];
|
||||
u8 type;
|
||||
u8 if_info;
|
||||
u8 if_mask[8];
|
||||
};
|
||||
|
||||
int dpsw_fdb_dump(struct fsl_mc_io *mc_io,
|
||||
u32 cmd_flags,
|
||||
u16 token,
|
||||
u16 fdb_id,
|
||||
u64 iova_addr,
|
||||
u32 iova_size,
|
||||
u16 *num_entries);
|
||||
|
||||
/**
|
||||
* struct dpsw_fdb_multicast_cfg - Multi-cast entry configuration
|
||||
* @type: Select static or dynamic entry
|
||||
|
@ -22,7 +22,7 @@ static struct workqueue_struct *ethsw_owq;
|
||||
|
||||
/* Minimal supported DPSW version */
|
||||
#define DPSW_MIN_VER_MAJOR 8
|
||||
#define DPSW_MIN_VER_MINOR 0
|
||||
#define DPSW_MIN_VER_MINOR 1
|
||||
|
||||
#define DEFAULT_VLAN_ID 1
|
||||
|
||||
@ -529,6 +529,138 @@ static int port_get_phys_name(struct net_device *netdev, char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ethsw_dump_ctx {
|
||||
struct net_device *dev;
|
||||
struct sk_buff *skb;
|
||||
struct netlink_callback *cb;
|
||||
int idx;
|
||||
};
|
||||
|
||||
static int ethsw_fdb_do_dump(struct fdb_dump_entry *entry,
|
||||
struct ethsw_dump_ctx *dump)
|
||||
{
|
||||
int is_dynamic = entry->type & DPSW_FDB_ENTRY_DINAMIC;
|
||||
u32 portid = NETLINK_CB(dump->cb->skb).portid;
|
||||
u32 seq = dump->cb->nlh->nlmsg_seq;
|
||||
struct nlmsghdr *nlh;
|
||||
struct ndmsg *ndm;
|
||||
|
||||
if (dump->idx < dump->cb->args[2])
|
||||
goto skip;
|
||||
|
||||
nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
|
||||
sizeof(*ndm), NLM_F_MULTI);
|
||||
if (!nlh)
|
||||
return -EMSGSIZE;
|
||||
|
||||
ndm = nlmsg_data(nlh);
|
||||
ndm->ndm_family = AF_BRIDGE;
|
||||
ndm->ndm_pad1 = 0;
|
||||
ndm->ndm_pad2 = 0;
|
||||
ndm->ndm_flags = NTF_SELF;
|
||||
ndm->ndm_type = 0;
|
||||
ndm->ndm_ifindex = dump->dev->ifindex;
|
||||
ndm->ndm_state = is_dynamic ? NUD_REACHABLE : NUD_NOARP;
|
||||
|
||||
if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, entry->mac_addr))
|
||||
goto nla_put_failure;
|
||||
|
||||
nlmsg_end(dump->skb, nlh);
|
||||
|
||||
skip:
|
||||
dump->idx++;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_cancel(dump->skb, nlh);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int port_fdb_valid_entry(struct fdb_dump_entry *entry,
|
||||
struct ethsw_port_priv *port_priv)
|
||||
{
|
||||
int idx = port_priv->idx;
|
||||
int valid;
|
||||
|
||||
if (entry->type & DPSW_FDB_ENTRY_TYPE_UNICAST)
|
||||
valid = entry->if_info == port_priv->idx;
|
||||
else
|
||||
valid = entry->if_mask[idx / 8] & BIT(idx % 8);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
static int port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
|
||||
struct net_device *net_dev,
|
||||
struct net_device *filter_dev, int *idx)
|
||||
{
|
||||
struct ethsw_port_priv *port_priv = netdev_priv(net_dev);
|
||||
struct ethsw_core *ethsw = port_priv->ethsw_data;
|
||||
struct device *dev = net_dev->dev.parent;
|
||||
struct fdb_dump_entry *fdb_entries;
|
||||
struct fdb_dump_entry fdb_entry;
|
||||
struct ethsw_dump_ctx dump = {
|
||||
.dev = net_dev,
|
||||
.skb = skb,
|
||||
.cb = cb,
|
||||
.idx = *idx,
|
||||
};
|
||||
dma_addr_t fdb_dump_iova;
|
||||
u16 num_fdb_entries;
|
||||
u32 fdb_dump_size;
|
||||
int err = 0, i;
|
||||
u8 *dma_mem;
|
||||
|
||||
fdb_dump_size = ethsw->sw_attr.max_fdb_entries * sizeof(fdb_entry);
|
||||
dma_mem = kzalloc(fdb_dump_size, GFP_KERNEL);
|
||||
if (!dma_mem)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(dma_mem, 0, fdb_dump_size);
|
||||
|
||||
fdb_dump_iova = dma_map_single(dev, dma_mem, fdb_dump_size,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, fdb_dump_iova)) {
|
||||
netdev_err(net_dev, "dma_map_single() failed\n");
|
||||
err = -ENOMEM;
|
||||
goto err_map;
|
||||
}
|
||||
|
||||
err = dpsw_fdb_dump(ethsw->mc_io, 0, ethsw->dpsw_handle, 0,
|
||||
fdb_dump_iova, fdb_dump_size, &num_fdb_entries);
|
||||
if (err) {
|
||||
netdev_err(net_dev, "dpsw_fdb_dump() = %d\n", err);
|
||||
goto err_dump;
|
||||
}
|
||||
|
||||
dma_unmap_single(dev, fdb_dump_iova, fdb_dump_size, DMA_FROM_DEVICE);
|
||||
|
||||
fdb_entries = (struct fdb_dump_entry *)dma_mem;
|
||||
for (i = 0; i < num_fdb_entries; i++) {
|
||||
fdb_entry = fdb_entries[i];
|
||||
|
||||
if (!port_fdb_valid_entry(&fdb_entry, port_priv))
|
||||
continue;
|
||||
|
||||
err = ethsw_fdb_do_dump(&fdb_entry, &dump);
|
||||
if (err)
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
*idx = dump.idx;
|
||||
|
||||
kfree(dma_mem);
|
||||
|
||||
return 0;
|
||||
|
||||
err_dump:
|
||||
dma_unmap_single(dev, fdb_dump_iova, fdb_dump_size, DMA_TO_DEVICE);
|
||||
err_map:
|
||||
kfree(dma_mem);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct net_device_ops ethsw_port_ops = {
|
||||
.ndo_open = port_open,
|
||||
.ndo_stop = port_stop,
|
||||
@ -538,6 +670,7 @@ static const struct net_device_ops ethsw_port_ops = {
|
||||
.ndo_change_mtu = port_change_mtu,
|
||||
.ndo_has_offload_stats = port_has_offload_stats,
|
||||
.ndo_get_offload_stats = port_get_offload_stats,
|
||||
.ndo_fdb_dump = port_fdb_dump,
|
||||
|
||||
.ndo_start_xmit = port_dropframe,
|
||||
.ndo_get_port_parent_id = swdev_get_port_parent_id,
|
||||
|
Loading…
Reference in New Issue
Block a user