Skip to content

Commit

Permalink
Merge branch 'thunderx-DMAC-filtering'
Browse files Browse the repository at this point in the history
Vadim Lomovtsev says:

====================
net: thunderx: implement DMAC filtering support

By default CN88XX BGX accepts all incoming multicast and broadcast
packets and filtering is disabled. The nic driver doesn't provide
an ability to change such behaviour.

This series is to implement DMAC filtering management for CN88XX
nic driver allowing user to enable/disable filtering and configure
specific MAC addresses to filter traffic.

Changes from v1:
build issues:
 - update code in order to address compiler warnings;
checkpatch.pl reported issues:
 - update code in order to fit 80 symbols length;
 - update commit descriptions in order to fit 80 symbols length;
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Apr 1, 2018
2 parents 5e8b270 + 37c3347 commit 56c03cb
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 30 deletions.
29 changes: 29 additions & 0 deletions drivers/net/ethernet/cavium/thunder/nic.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,22 @@ struct nicvf_drv_stats {

struct cavium_ptp;

struct xcast_addr {
struct list_head list;
u64 addr;
};

struct xcast_addr_list {
struct list_head list;
int count;
};

struct nicvf_work {
struct delayed_work work;
u8 mode;
struct xcast_addr_list *mc;
};

struct nicvf {
struct nicvf *pnicvf;
struct net_device *netdev;
Expand Down Expand Up @@ -313,6 +329,7 @@ struct nicvf {
struct nicvf_pfc pfc;
struct tasklet_struct qs_err_task;
struct work_struct reset_task;
struct nicvf_work rx_mode_work;

/* PTP timestamp */
struct cavium_ptp *ptp_clock;
Expand Down Expand Up @@ -403,6 +420,9 @@ struct nicvf {
#define NIC_MBOX_MSG_PTP_CFG 0x19 /* HW packet timestamp */
#define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */
#define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */
#define NIC_MBOX_MSG_RESET_XCAST 0xF2 /* Reset DCAM filtering mode */
#define NIC_MBOX_MSG_ADD_MCAST 0xF3 /* Add MAC to DCAM filters */
#define NIC_MBOX_MSG_SET_XCAST 0xF4 /* Set MCAST/BCAST RX mode */

struct nic_cfg_msg {
u8 msg;
Expand Down Expand Up @@ -556,6 +576,14 @@ struct set_ptp {
bool enable;
};

struct xcast {
u8 msg;
union {
u8 mode;
u64 mac;
} data;
};

/* 128 bit shared memory between PF and each VF */
union nic_mbx {
struct { u8 msg; } msg;
Expand All @@ -576,6 +604,7 @@ union nic_mbx {
struct reset_stat_cfg reset_stat;
struct pfc pfc;
struct set_ptp ptp;
struct xcast xcast;
};

#define NIC_NODE_ID_MASK 0x03
Expand Down
45 changes: 41 additions & 4 deletions drivers/net/ethernet/cavium/thunder/nic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#define DRV_NAME "nicpf"
#define DRV_VERSION "1.0"

#define NIC_VF_PER_MBX_REG 64

struct hw_info {
u8 bgx_cnt;
u8 chans_per_lmac;
Expand Down Expand Up @@ -1072,6 +1074,40 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
case NIC_MBOX_MSG_PTP_CFG:
nic_config_timestamp(nic, vf, &mbx.ptp);
break;
case NIC_MBOX_MSG_RESET_XCAST:
if (vf >= nic->num_vf_en) {
ret = -1; /* NACK */
break;
}
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
bgx_reset_xcast_mode(nic->node, bgx, lmac,
vf < NIC_VF_PER_MBX_REG ? vf :
vf - NIC_VF_PER_MBX_REG);
break;

case NIC_MBOX_MSG_ADD_MCAST:
if (vf >= nic->num_vf_en) {
ret = -1; /* NACK */
break;
}
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
bgx_set_dmac_cam_filter(nic->node, bgx, lmac,
mbx.xcast.data.mac,
vf < NIC_VF_PER_MBX_REG ? vf :
vf - NIC_VF_PER_MBX_REG);
break;

case NIC_MBOX_MSG_SET_XCAST:
if (vf >= nic->num_vf_en) {
ret = -1; /* NACK */
break;
}
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
bgx_set_xcast_mode(nic->node, bgx, lmac, mbx.xcast.data.mode);
break;
default:
dev_err(&nic->pdev->dev,
"Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
Expand All @@ -1094,7 +1130,7 @@ static irqreturn_t nic_mbx_intr_handler(int irq, void *nic_irq)
struct nicpf *nic = (struct nicpf *)nic_irq;
int mbx;
u64 intr;
u8 vf, vf_per_mbx_reg = 64;
u8 vf;

if (irq == pci_irq_vector(nic->pdev, NIC_PF_INTR_ID_MBOX0))
mbx = 0;
Expand All @@ -1103,12 +1139,13 @@ static irqreturn_t nic_mbx_intr_handler(int irq, void *nic_irq)

intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3));
dev_dbg(&nic->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr);
for (vf = 0; vf < vf_per_mbx_reg; vf++) {
for (vf = 0; vf < NIC_VF_PER_MBX_REG; vf++) {
if (intr & (1ULL << vf)) {
dev_dbg(&nic->pdev->dev, "Intr from VF %d\n",
vf + (mbx * vf_per_mbx_reg));
vf + (mbx * NIC_VF_PER_MBX_REG));

nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg));
nic_handle_mbx_intr(nic, vf +
(mbx * NIC_VF_PER_MBX_REG));
nic_clear_mbx_intr(nic, vf, mbx);
}
}
Expand Down
110 changes: 109 additions & 1 deletion drivers/net/ethernet/cavium/thunder/nicvf_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/bpf_trace.h>
#include <linux/filter.h>
#include <linux/net_tstamp.h>
#include <linux/workqueue.h>

#include "nic_reg.h"
#include "nic.h"
Expand Down Expand Up @@ -67,6 +68,9 @@ module_param(cpi_alg, int, 0444);
MODULE_PARM_DESC(cpi_alg,
"PFC algorithm (0=none, 1=VLAN, 2=VLAN16, 3=IP Diffserv)");

/* workqueue for handling kernel ndo_set_rx_mode() calls */
static struct workqueue_struct *nicvf_rx_mode_wq;

static inline u8 nicvf_netdev_qidx(struct nicvf *nic, u8 qidx)
{
if (nic->sqs_mode)
Expand Down Expand Up @@ -1919,6 +1923,100 @@ static int nicvf_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
}
}

static void nicvf_set_rx_mode_task(struct work_struct *work_arg)
{
struct nicvf_work *vf_work = container_of(work_arg, struct nicvf_work,
work.work);
struct nicvf *nic = container_of(vf_work, struct nicvf, rx_mode_work);
union nic_mbx mbx = {};
struct xcast_addr *xaddr, *next;

if (!vf_work)
return;

/* From the inside of VM code flow we have only 128 bits memory
* available to send message to host's PF, so send all mc addrs
* one by one, starting from flush command in case if kernel
* requests to configure specific MAC filtering
*/

/* flush DMAC filters and reset RX mode */
mbx.xcast.msg = NIC_MBOX_MSG_RESET_XCAST;
nicvf_send_msg_to_pf(nic, &mbx);

if (vf_work->mode & BGX_XCAST_MCAST_FILTER) {
/* once enabling filtering, we need to signal to PF to add
* its' own LMAC to the filter to accept packets for it.
*/
mbx.xcast.msg = NIC_MBOX_MSG_ADD_MCAST;
mbx.xcast.data.mac = 0;
nicvf_send_msg_to_pf(nic, &mbx);
}

/* check if we have any specific MACs to be added to PF DMAC filter */
if (vf_work->mc) {
/* now go through kernel list of MACs and add them one by one */
list_for_each_entry_safe(xaddr, next,
&vf_work->mc->list, list) {
mbx.xcast.msg = NIC_MBOX_MSG_ADD_MCAST;
mbx.xcast.data.mac = xaddr->addr;
nicvf_send_msg_to_pf(nic, &mbx);

/* after receiving ACK from PF release memory */
list_del(&xaddr->list);
kfree(xaddr);
vf_work->mc->count--;
}
kfree(vf_work->mc);
}

/* and finally set rx mode for PF accordingly */
mbx.xcast.msg = NIC_MBOX_MSG_SET_XCAST;
mbx.xcast.data.mode = vf_work->mode;

nicvf_send_msg_to_pf(nic, &mbx);
}

static void nicvf_set_rx_mode(struct net_device *netdev)
{
struct nicvf *nic = netdev_priv(netdev);
struct netdev_hw_addr *ha;
struct xcast_addr_list *mc_list = NULL;
u8 mode = 0;

if (netdev->flags & IFF_PROMISC) {
mode = BGX_XCAST_BCAST_ACCEPT | BGX_XCAST_MCAST_ACCEPT;
} else {
if (netdev->flags & IFF_BROADCAST)
mode |= BGX_XCAST_BCAST_ACCEPT;

if (netdev->flags & IFF_ALLMULTI) {
mode |= BGX_XCAST_MCAST_ACCEPT;
} else if (netdev->flags & IFF_MULTICAST) {
mode |= BGX_XCAST_MCAST_FILTER;
/* here we need to copy mc addrs */
if (netdev_mc_count(netdev)) {
struct xcast_addr *xaddr;

mc_list = kmalloc(sizeof(*mc_list), GFP_ATOMIC);
INIT_LIST_HEAD(&mc_list->list);
netdev_hw_addr_list_for_each(ha, &netdev->mc) {
xaddr = kmalloc(sizeof(*xaddr),
GFP_ATOMIC);
xaddr->addr =
ether_addr_to_u64(ha->addr);
list_add_tail(&xaddr->list,
&mc_list->list);
mc_list->count++;
}
}
}
}
nic->rx_mode_work.mc = mc_list;
nic->rx_mode_work.mode = mode;
queue_delayed_work(nicvf_rx_mode_wq, &nic->rx_mode_work.work, 2 * HZ);
}

static const struct net_device_ops nicvf_netdev_ops = {
.ndo_open = nicvf_open,
.ndo_stop = nicvf_stop,
Expand All @@ -1931,6 +2029,7 @@ static const struct net_device_ops nicvf_netdev_ops = {
.ndo_set_features = nicvf_set_features,
.ndo_bpf = nicvf_xdp,
.ndo_do_ioctl = nicvf_ioctl,
.ndo_set_rx_mode = nicvf_set_rx_mode,
};

static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
Expand Down Expand Up @@ -2071,6 +2170,8 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)

INIT_WORK(&nic->reset_task, nicvf_reset_task);

INIT_DELAYED_WORK(&nic->rx_mode_work.work, nicvf_set_rx_mode_task);

err = register_netdev(netdev);
if (err) {
dev_err(dev, "Failed to register netdevice\n");
Expand Down Expand Up @@ -2109,6 +2210,8 @@ static void nicvf_remove(struct pci_dev *pdev)
nic = netdev_priv(netdev);
pnetdev = nic->pnicvf->netdev;

cancel_delayed_work_sync(&nic->rx_mode_work.work);

/* Check if this Qset is assigned to different VF.
* If yes, clean primary and all secondary Qsets.
*/
Expand Down Expand Up @@ -2140,12 +2243,17 @@ static struct pci_driver nicvf_driver = {
static int __init nicvf_init_module(void)
{
pr_info("%s, ver %s\n", DRV_NAME, DRV_VERSION);

nicvf_rx_mode_wq = alloc_ordered_workqueue("nicvf_generic",
WQ_MEM_RECLAIM);
return pci_register_driver(&nicvf_driver);
}

static void __exit nicvf_cleanup_module(void)
{
if (nicvf_rx_mode_wq) {
destroy_workqueue(nicvf_rx_mode_wq);
nicvf_rx_mode_wq = NULL;
}
pci_unregister_driver(&nicvf_driver);
}

Expand Down
Loading

0 comments on commit 56c03cb

Please sign in to comment.