mirror of https://gitee.com/openkylin/linux.git
ionic: Add management of rx filters
Set up the infrastructure for managing Rx filters. We can't ask the hardware for what filters it has, so we keep a local list of filters that we've pushed into the HW. Signed-off-by: Shannon Nelson <snelson@pensando.io> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
beead698b1
commit
c1e329ebec
|
@ -4,4 +4,4 @@
|
|||
obj-$(CONFIG_IONIC) := ionic.o
|
||||
|
||||
ionic-y := ionic_main.o ionic_bus_pci.o ionic_devlink.o ionic_dev.o \
|
||||
ionic_debugfs.o ionic_lif.o
|
||||
ionic_debugfs.o ionic_lif.o ionic_rx_filter.o
|
||||
|
|
|
@ -830,6 +830,8 @@ static void ionic_lif_deinit(struct ionic_lif *lif)
|
|||
|
||||
clear_bit(IONIC_LIF_INITED, lif->state);
|
||||
|
||||
ionic_rx_filters_deinit(lif);
|
||||
|
||||
napi_disable(&lif->adminqcq->napi);
|
||||
ionic_lif_qcq_deinit(lif, lif->notifyqcq);
|
||||
ionic_lif_qcq_deinit(lif, lif->adminqcq);
|
||||
|
@ -1009,6 +1011,10 @@ static int ionic_lif_init(struct ionic_lif *lif)
|
|||
if (err)
|
||||
goto err_out_notifyq_deinit;
|
||||
|
||||
err = ionic_rx_filters_init(lif);
|
||||
if (err)
|
||||
goto err_out_notifyq_deinit;
|
||||
|
||||
set_bit(IONIC_LIF_INITED, lif->state);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#define _IONIC_LIF_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include "ionic_rx_filter.h"
|
||||
|
||||
#define IONIC_ADMINQ_LENGTH 16 /* must be a power of two */
|
||||
#define IONIC_NOTIFYQ_LENGTH 64 /* must be a power of two */
|
||||
|
@ -90,6 +91,7 @@ struct ionic_lif {
|
|||
dma_addr_t info_pa;
|
||||
u32 info_sz;
|
||||
|
||||
struct ionic_rx_filters rx_filters;
|
||||
unsigned long *dbid_inuse;
|
||||
unsigned int dbid_count;
|
||||
struct dentry *dentry;
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "ionic.h"
|
||||
#include "ionic_lif.h"
|
||||
#include "ionic_rx_filter.h"
|
||||
|
||||
void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f)
|
||||
{
|
||||
struct device *dev = lif->ionic->dev;
|
||||
|
||||
hlist_del(&f->by_id);
|
||||
hlist_del(&f->by_hash);
|
||||
devm_kfree(dev, f);
|
||||
}
|
||||
|
||||
int ionic_rx_filter_del(struct ionic_lif *lif, struct ionic_rx_filter *f)
|
||||
{
|
||||
struct ionic_admin_ctx ctx = {
|
||||
.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
|
||||
.cmd.rx_filter_del = {
|
||||
.opcode = IONIC_CMD_RX_FILTER_DEL,
|
||||
.filter_id = cpu_to_le32(f->filter_id),
|
||||
},
|
||||
};
|
||||
|
||||
return ionic_adminq_post_wait(lif, &ctx);
|
||||
}
|
||||
|
||||
int ionic_rx_filters_init(struct ionic_lif *lif)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
spin_lock_init(&lif->rx_filters.lock);
|
||||
|
||||
for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
|
||||
INIT_HLIST_HEAD(&lif->rx_filters.by_hash[i]);
|
||||
INIT_HLIST_HEAD(&lif->rx_filters.by_id[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ionic_rx_filters_deinit(struct ionic_lif *lif)
|
||||
{
|
||||
struct ionic_rx_filter *f;
|
||||
struct hlist_head *head;
|
||||
struct hlist_node *tmp;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
|
||||
head = &lif->rx_filters.by_id[i];
|
||||
hlist_for_each_entry_safe(f, tmp, head, by_id)
|
||||
ionic_rx_filter_free(lif, f);
|
||||
}
|
||||
}
|
||||
|
||||
int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
|
||||
u32 hash, struct ionic_admin_ctx *ctx)
|
||||
{
|
||||
struct device *dev = lif->ionic->dev;
|
||||
struct ionic_rx_filter_add_cmd *ac;
|
||||
struct ionic_rx_filter *f;
|
||||
struct hlist_head *head;
|
||||
unsigned int key;
|
||||
|
||||
ac = &ctx->cmd.rx_filter_add;
|
||||
|
||||
switch (le16_to_cpu(ac->match)) {
|
||||
case IONIC_RX_FILTER_MATCH_VLAN:
|
||||
key = le16_to_cpu(ac->vlan.vlan);
|
||||
break;
|
||||
case IONIC_RX_FILTER_MATCH_MAC:
|
||||
key = *(u32 *)ac->mac.addr;
|
||||
break;
|
||||
case IONIC_RX_FILTER_MATCH_MAC_VLAN:
|
||||
key = le16_to_cpu(ac->mac_vlan.vlan);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
f = devm_kzalloc(dev, sizeof(*f), GFP_KERNEL);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
f->flow_id = flow_id;
|
||||
f->filter_id = le32_to_cpu(ctx->comp.rx_filter_add.filter_id);
|
||||
f->rxq_index = rxq_index;
|
||||
memcpy(&f->cmd, ac, sizeof(f->cmd));
|
||||
|
||||
INIT_HLIST_NODE(&f->by_hash);
|
||||
INIT_HLIST_NODE(&f->by_id);
|
||||
|
||||
spin_lock_bh(&lif->rx_filters.lock);
|
||||
|
||||
key = hash_32(key, IONIC_RX_FILTER_HASH_BITS);
|
||||
head = &lif->rx_filters.by_hash[key];
|
||||
hlist_add_head(&f->by_hash, head);
|
||||
|
||||
key = f->filter_id & IONIC_RX_FILTER_HLISTS_MASK;
|
||||
head = &lif->rx_filters.by_id[key];
|
||||
hlist_add_head(&f->by_id, head);
|
||||
|
||||
spin_unlock_bh(&lif->rx_filters.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ionic_rx_filter *ionic_rx_filter_by_vlan(struct ionic_lif *lif, u16 vid)
|
||||
{
|
||||
struct ionic_rx_filter *f;
|
||||
struct hlist_head *head;
|
||||
unsigned int key;
|
||||
|
||||
key = hash_32(vid, IONIC_RX_FILTER_HASH_BITS);
|
||||
head = &lif->rx_filters.by_hash[key];
|
||||
|
||||
hlist_for_each_entry(f, head, by_hash) {
|
||||
if (le16_to_cpu(f->cmd.match) != IONIC_RX_FILTER_MATCH_VLAN)
|
||||
continue;
|
||||
if (le16_to_cpu(f->cmd.vlan.vlan) == vid)
|
||||
return f;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ionic_rx_filter *ionic_rx_filter_by_addr(struct ionic_lif *lif,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct ionic_rx_filter *f;
|
||||
struct hlist_head *head;
|
||||
unsigned int key;
|
||||
|
||||
key = hash_32(*(u32 *)addr, IONIC_RX_FILTER_HASH_BITS);
|
||||
head = &lif->rx_filters.by_hash[key];
|
||||
|
||||
hlist_for_each_entry(f, head, by_hash) {
|
||||
if (le16_to_cpu(f->cmd.match) != IONIC_RX_FILTER_MATCH_MAC)
|
||||
continue;
|
||||
if (memcmp(addr, f->cmd.mac.addr, ETH_ALEN) == 0)
|
||||
return f;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
|
||||
|
||||
#ifndef _IONIC_RX_FILTER_H_
|
||||
#define _IONIC_RX_FILTER_H_
|
||||
|
||||
#define IONIC_RXQ_INDEX_ANY (0xFFFF)
|
||||
struct ionic_rx_filter {
|
||||
u32 flow_id;
|
||||
u32 filter_id;
|
||||
u16 rxq_index;
|
||||
struct ionic_rx_filter_add_cmd cmd;
|
||||
struct hlist_node by_hash;
|
||||
struct hlist_node by_id;
|
||||
};
|
||||
|
||||
#define IONIC_RX_FILTER_HASH_BITS 10
|
||||
#define IONIC_RX_FILTER_HLISTS BIT(IONIC_RX_FILTER_HASH_BITS)
|
||||
#define IONIC_RX_FILTER_HLISTS_MASK (IONIC_RX_FILTER_HLISTS - 1)
|
||||
struct ionic_rx_filters {
|
||||
spinlock_t lock; /* filter list lock */
|
||||
struct hlist_head by_hash[IONIC_RX_FILTER_HLISTS]; /* by skb hash */
|
||||
struct hlist_head by_id[IONIC_RX_FILTER_HLISTS]; /* by filter_id */
|
||||
};
|
||||
|
||||
void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f);
|
||||
int ionic_rx_filter_del(struct ionic_lif *lif, struct ionic_rx_filter *f);
|
||||
int ionic_rx_filters_init(struct ionic_lif *lif);
|
||||
void ionic_rx_filters_deinit(struct ionic_lif *lif);
|
||||
int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
|
||||
u32 hash, struct ionic_admin_ctx *ctx);
|
||||
struct ionic_rx_filter *ionic_rx_filter_by_vlan(struct ionic_lif *lif, u16 vid);
|
||||
struct ionic_rx_filter *ionic_rx_filter_by_addr(struct ionic_lif *lif, const u8 *addr);
|
||||
|
||||
#endif /* _IONIC_RX_FILTER_H_ */
|
Loading…
Reference in New Issue