aboutsummaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/dummy.c2
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic.h29
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic_main.c45
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_main.c110
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.c201
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.h19
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c6
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c5
-rw-r--r--drivers/net/hyperv/rndis_filter.c16
-rw-r--r--drivers/net/ifb.c2
-rw-r--r--drivers/net/netdevsim/devlink.c12
-rw-r--r--drivers/net/netdevsim/netdev.c6
-rw-r--r--drivers/net/netdevsim/netdevsim.h5
14 files changed, 407 insertions, 55 deletions
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 30b1c8512049..0d15a12a4560 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -219,6 +219,7 @@ static int __init dummy_init_module(void)
{
int i, err = 0;
+ down_write(&pernet_ops_rwsem);
rtnl_lock();
err = __rtnl_link_register(&dummy_link_ops);
if (err < 0)
@@ -233,6 +234,7 @@ static int __init dummy_init_module(void)
out:
rtnl_unlock();
+ up_write(&pernet_ops_rwsem);
return err;
}
diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
index 4cacce5d2b16..5fc46c5a4f36 100644
--- a/drivers/net/ethernet/cavium/thunder/nic.h
+++ b/drivers/net/ethernet/cavium/thunder/nic.h
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
index 7ff66a8194e2..55af04fa03a7 100644
--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -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;
@@ -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);
@@ -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;
@@ -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);
}
}
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index 73fe3881414b..1e9a31fef729 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -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"
@@ -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)
@@ -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,
@@ -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)
@@ -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");
@@ -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.
*/
@@ -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);
}
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
index 91d34ea40e2c..5d08d2aeb172 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -24,9 +24,31 @@
#define DRV_NAME "thunder_bgx"
#define DRV_VERSION "1.0"
+/* RX_DMAC_CTL configuration */
+enum MCAST_MODE {
+ MCAST_MODE_REJECT = 0x0,
+ MCAST_MODE_ACCEPT = 0x1,
+ MCAST_MODE_CAM_FILTER = 0x2,
+ RSVD = 0x3
+};
+
+#define BCAST_ACCEPT BIT(0)
+#define CAM_ACCEPT BIT(3)
+#define MCAST_MODE_MASK 0x3
+#define BGX_MCAST_MODE(x) (x << 1)
+
+struct dmac_map {
+ u64 vf_map;
+ u64 dmac;
+};
+
struct lmac {
struct bgx *bgx;
- int dmac;
+ /* actual number of DMACs configured */
+ u8 dmacs_cfg;
+ /* overal number of possible DMACs could be configured per LMAC */
+ u8 dmacs_count;
+ struct dmac_map *dmacs; /* DMAC:VFs tracking filter array */
u8 mac[ETH_ALEN];
u8 lmac_type;
u8 lane_to_sds;
@@ -223,6 +245,163 @@ void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac)
}
EXPORT_SYMBOL(bgx_set_lmac_mac);
+static void bgx_flush_dmac_cam_filter(struct bgx *bgx, int lmacid)
+{
+ struct lmac *lmac = NULL;
+ u8 idx = 0;
+
+ lmac = &bgx->lmac[lmacid];
+ /* reset CAM filters */
+ for (idx = 0; idx < lmac->dmacs_count; idx++)
+ bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM +
+ ((lmacid * lmac->dmacs_count) + idx) *
+ sizeof(u64), 0);
+}
+
+static void bgx_lmac_remove_filters(struct lmac *lmac, u8 vf_id)
+{
+ int i = 0;
+
+ if (!lmac)
+ return;
+
+ /* We've got reset filters request from some of attached VF, while the
+ * others might want to keep their configuration. So in this case lets
+ * iterate over all of configured filters and decrease number of
+ * referencies. if some addresses get zero refs remove them from list
+ */
+ for (i = lmac->dmacs_cfg - 1; i >= 0; i--) {
+ lmac->dmacs[i].vf_map &= ~BIT_ULL(vf_id);
+ if (!lmac->dmacs[i].vf_map) {
+ lmac->dmacs_cfg--;
+ lmac->dmacs[i].dmac = 0;
+ lmac->dmacs[i].vf_map = 0;
+ }
+ }
+}
+
+static int bgx_lmac_save_filter(struct lmac *lmac, u64 dmac, u8 vf_id)
+{
+ u8 i = 0;
+
+ if (!lmac)
+ return -1;
+
+ /* At the same time we could have several VFs 'attached' to some
+ * particular LMAC, and each VF is represented as network interface
+ * for kernel. So from user perspective it should be possible to
+ * manipulate with its' (VF) receive modes. However from PF
+ * driver perspective we need to keep track of filter configurations
+ * for different VFs to prevent filter values dupes
+ */
+ for (i = 0; i < lmac->dmacs_cfg; i++) {
+ if (lmac->dmacs[i].dmac == dmac) {
+ lmac->dmacs[i].vf_map |= BIT_ULL(vf_id);
+ return -1;
+ }
+ }
+
+ if (!(lmac->dmacs_cfg < lmac->dmacs_count))
+ return -1;
+
+ /* keep it for further tracking */
+ lmac->dmacs[lmac->dmacs_cfg].dmac = dmac;
+ lmac->dmacs[lmac->dmacs_cfg].vf_map = BIT_ULL(vf_id);
+ lmac->dmacs_cfg++;
+ return 0;
+}
+
+static int bgx_set_dmac_cam_filter_mac(struct bgx *bgx, int lmacid,
+ u64 cam_dmac, u8 idx)
+{
+ struct lmac *lmac = NULL;
+ u64 cfg = 0;
+
+ /* skip zero addresses as meaningless */
+ if (!cam_dmac || !bgx)
+ return -1;
+
+ lmac = &bgx->lmac[lmacid];
+
+ /* configure DCAM filtering for designated LMAC */
+ cfg = RX_DMACX_CAM_LMACID(lmacid & LMAC_ID_MASK) |
+ RX_DMACX_CAM_EN | cam_dmac;
+ bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM +
+ ((lmacid * lmac->dmacs_count) + idx) * sizeof(u64), cfg);
+ return 0;
+}
+
+void bgx_set_dmac_cam_filter(int node, int bgx_idx, int lmacid,
+ u64 cam_dmac, u8 vf_id)
+{
+ struct bgx *bgx = get_bgx(node, bgx_idx);
+ struct lmac *lmac = NULL;
+
+ if (!bgx)
+ return;
+
+ lmac = &bgx->lmac[lmacid];
+
+ if (!cam_dmac)
+ cam_dmac = ether_addr_to_u64(lmac->mac);
+
+ /* since we might have several VFs attached to particular LMAC
+ * and kernel could call mcast config for each of them with the
+ * same MAC, check if requested MAC is already in filtering list and
+ * updare/prepare list of MACs to be applied later to HW filters
+ */
+ bgx_lmac_save_filter(lmac, cam_dmac, vf_id);
+}
+EXPORT_SYMBOL(bgx_set_dmac_cam_filter);
+
+void bgx_set_xcast_mode(int node, int bgx_idx, int lmacid, u8 mode)
+{
+ struct bgx *bgx = get_bgx(node, bgx_idx);
+ struct lmac *lmac = NULL;
+ u64 cfg = 0;
+ u8 i = 0;
+
+ if (!bgx)
+ return;
+
+ lmac = &bgx->lmac[lmacid];
+
+ cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_RX_DMAC_CTL);
+ if (mode & BGX_XCAST_BCAST_ACCEPT)
+ cfg |= BCAST_ACCEPT;
+ else
+ cfg &= ~BCAST_ACCEPT;
+
+ /* disable all MCASTs and DMAC filtering */
+ cfg &= ~(CAM_ACCEPT | BGX_MCAST_MODE(MCAST_MODE_MASK));
+
+ /* check requested bits and set filtergin mode appropriately */
+ if (mode & (BGX_XCAST_MCAST_ACCEPT)) {
+ cfg |= (BGX_MCAST_MODE(MCAST_MODE_ACCEPT));
+ } else if (mode & BGX_XCAST_MCAST_FILTER) {
+ cfg |= (BGX_MCAST_MODE(MCAST_MODE_CAM_FILTER) | CAM_ACCEPT);
+ for (i = 0; i < lmac->dmacs_cfg; i++)
+ bgx_set_dmac_cam_filter_mac(bgx, lmacid,
+ lmac->dmacs[i].dmac, i);
+ }
+ bgx_reg_write(bgx, lmacid, BGX_CMRX_RX_DMAC_CTL, cfg);
+}
+EXPORT_SYMBOL(bgx_set_xcast_mode);
+
+void bgx_reset_xcast_mode(int node, int bgx_idx, int lmacid, u8 vf_id)
+{
+ struct bgx *bgx = get_bgx(node, bgx_idx);
+
+ if (!bgx)
+ return;
+
+ bgx_lmac_remove_filters(&bgx->lmac[lmacid], vf_id);
+ bgx_flush_dmac_cam_filter(bgx, lmacid);
+ bgx_set_xcast_mode(node, bgx_idx, lmacid,
+ (BGX_XCAST_BCAST_ACCEPT | BGX_XCAST_MCAST_ACCEPT));
+}
+EXPORT_SYMBOL(bgx_reset_xcast_mode);
+
void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable)
{
struct bgx *bgx = get_bgx(node, bgx_idx);
@@ -468,18 +647,6 @@ u64 bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx)
}
EXPORT_SYMBOL(bgx_get_tx_stats);
-static void bgx_flush_dmac_addrs(struct bgx *bgx, int lmac)
-{
- u64 offset;
-
- while (bgx->lmac[lmac].dmac > 0) {
- offset = ((bgx->lmac[lmac].dmac - 1) * sizeof(u64)) +
- (lmac * MAX_DMAC_PER_LMAC * sizeof(u64));
- bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM + offset, 0);
- bgx->lmac[lmac].dmac--;
- }
-}
-
/* Configure BGX LMAC in internal loopback mode */
void bgx_lmac_internal_loopback(int node, int bgx_idx,
int lmac_idx, bool enable)
@@ -912,6 +1079,11 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_MIN_PKT, 60 + 4);
}
+ /* actual number of filters available to exact LMAC */
+ lmac->dmacs_count = (RX_DMAC_COUNT / bgx->lmac_count);
+ lmac->dmacs = kcalloc(lmac->dmacs_count, sizeof(*lmac->dmacs),
+ GFP_KERNEL);
+
/* Enable lmac */
bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
@@ -998,7 +1170,8 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
cfg &= ~CMR_EN;
bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
- bgx_flush_dmac_addrs(bgx, lmacid);
+ bgx_flush_dmac_cam_filter(bgx, lmacid);
+ kfree(lmac->dmacs);
if ((lmac->lmac_type != BGX_MODE_XFI) &&
(lmac->lmac_type != BGX_MODE_XLAUI) &&
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
index 5a7567d31138..cbdd20b9ee6f 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
@@ -30,6 +30,7 @@
#define DEFAULT_PAUSE_TIME 0xFFFF
#define BGX_ID_MASK 0x3
+#define LMAC_ID_MASK 0x3
#define MAX_DMAC_PER_LMAC_TNS_BYPASS_MODE 2
@@ -57,7 +58,7 @@
#define BGX_CMRX_RX_FIFO_LEN 0x108
#define BGX_CMR_RX_DMACX_CAM 0x200
#define RX_DMACX_CAM_EN BIT_ULL(48)
-#define RX_DMACX_CAM_LMACID(x) (x << 49)
+#define RX_DMACX_CAM_LMACID(x) (((u64)x) << 49)
#define RX_DMAC_COUNT 32
#define BGX_CMR_RX_STREERING 0x300
#define RX_TRAFFIC_STEER_RULE_COUNT 8
@@ -205,17 +206,13 @@
#define LMAC_INTR_LINK_UP BIT(0)
#define LMAC_INTR_LINK_DOWN BIT(1)
-/* RX_DMAC_CTL configuration*/
-enum MCAST_MODE {
- MCAST_MODE_REJECT,
- MCAST_MODE_ACCEPT,
- MCAST_MODE_CAM_FILTER,
- RSVD
-};
-
-#define BCAST_ACCEPT 1
-#define CAM_ACCEPT 1
+#define BGX_XCAST_BCAST_ACCEPT BIT(0)
+#define BGX_XCAST_MCAST_ACCEPT BIT(1)
+#define BGX_XCAST_MCAST_FILTER BIT(2)
+void bgx_set_dmac_cam_filter(int node, int bgx_idx, int lmacid, u64 mac, u8 vf);
+void bgx_reset_xcast_mode(int node, int bgx_idx, int lmacid, u8 vf);
+void bgx_set_xcast_mode(int node, int bgx_idx, int lmacid, u8 mode);
void octeon_mdiobus_force_mod_depencency(void);
void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable);
void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index cac86e9ae0dd..9dcc5765f11f 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -369,7 +369,6 @@ static int hns_mac_port_config_bc_en(struct hns_mac_cb *mac_cb,
{
int ret;
struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
- u8 addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct dsaf_drv_mac_single_dest_entry mac_entry;
/* directy return ok in debug network mode */
@@ -377,7 +376,7 @@ static int hns_mac_port_config_bc_en(struct hns_mac_cb *mac_cb,
return 0;
if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) {
- memcpy(mac_entry.addr, addr, sizeof(mac_entry.addr));
+ eth_broadcast_addr(mac_entry.addr);
mac_entry.in_vlan_id = vlan_id;
mac_entry.in_port_num = mac_cb->mac_id;
mac_entry.port_num = port_num;
@@ -404,7 +403,6 @@ int hns_mac_vm_config_bc_en(struct hns_mac_cb *mac_cb, u32 vmid, bool enable)
int ret;
struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
u8 port_num;
- u8 addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct mac_entry_idx *uc_mac_entry;
struct dsaf_drv_mac_single_dest_entry mac_entry;
@@ -414,7 +412,7 @@ int hns_mac_vm_config_bc_en(struct hns_mac_cb *mac_cb, u32 vmid, bool enable)
uc_mac_entry = &mac_cb->addr_entry_idx[vmid];
if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) {
- memcpy(mac_entry.addr, addr, sizeof(mac_entry.addr));
+ eth_broadcast_addr(mac_entry.addr);
mac_entry.in_vlan_id = uc_mac_entry->vlan_id;
mac_entry.in_port_num = mac_cb->mac_id;
ret = hns_mac_get_inner_port_num(mac_cb, vmid, &port_num);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index a31b4adf6e6a..8c55965a66ac 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -1614,10 +1614,6 @@ static void hns3_remove(struct pci_dev *pdev)
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
hnae3_unregister_ae_dev(ae_dev);
-
- devm_kfree(&pdev->dev, ae_dev);
-
- pci_set_drvdata(pdev, NULL);
}
static struct pci_driver hns3_driver = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index 2d5d4aea3bcb..7cb794094a70 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -1,5 +1,5 @@
/*
- * Amlogic Meson8b and GXBB DWMAC glue layer
+ * Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer
*
* Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*
@@ -318,6 +318,7 @@ err_remove_config_dt:
static const struct of_device_id meson8b_dwmac_match[] = {
{ .compatible = "amlogic,meson8b-dwmac" },
+ { .compatible = "amlogic,meson8m2-dwmac" },
{ .compatible = "amlogic,meson-gxbb-dwmac" },
{ }
};
@@ -335,5 +336,5 @@ static struct platform_driver meson8b_dwmac_driver = {
module_platform_driver(meson8b_dwmac_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
-MODULE_DESCRIPTION("Amlogic Meson8b and GXBB DWMAC glue layer");
+MODULE_DESCRIPTION("Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 4a4952363e8a..e2b68d9328a7 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -365,14 +365,15 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
static int rndis_filter_receive_data(struct net_device *ndev,
struct netvsc_device *nvdev,
- struct rndis_message *msg,
struct vmbus_channel *channel,
- void *data, u32 data_buflen)
+ struct rndis_message *msg,
+ u32 data_buflen)
{
struct rndis_packet *rndis_pkt = &msg->msg.pkt;
const struct ndis_tcp_ip_checksum_info *csum_info;
const struct ndis_pkt_8021q_info *vlan;
u32 data_offset;
+ void *data;
/* Remove the rndis header and pass it back up the stack */
data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
@@ -393,14 +394,15 @@ static int rndis_filter_receive_data(struct net_device *ndev,
vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
+ csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
+
+ data = (void *)msg + data_offset;
+
/*
* Remove the rndis trailer padding from rndis packet message
* rndis_pkt->data_len tell us the real data length, we only copy
* the data packet to the stack, without the rndis trailer padding
*/
- data = (void *)((unsigned long)data + data_offset);
- csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
-
return netvsc_recv_callback(ndev, nvdev, channel,
data, rndis_pkt->data_len,
csum_info, vlan);
@@ -419,8 +421,8 @@ int rndis_filter_receive(struct net_device *ndev,
switch (rndis_msg->ndis_msg_type) {
case RNDIS_MSG_PACKET:
- return rndis_filter_receive_data(ndev, net_dev, rndis_msg,
- channel, data, buflen);
+ return rndis_filter_receive_data(ndev, net_dev, channel,
+ rndis_msg, buflen);
case RNDIS_MSG_INIT_C:
case RNDIS_MSG_QUERY_C:
case RNDIS_MSG_SET_C:
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 0008da7e9d4c..5f2897ec0edc 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -330,6 +330,7 @@ static int __init ifb_init_module(void)
{
int i, err;
+ down_write(&pernet_ops_rwsem);
rtnl_lock();
err = __rtnl_link_register(&ifb_link_ops);
if (err < 0)
@@ -344,6 +345,7 @@ static int __init ifb_init_module(void)
out:
rtnl_unlock();
+ up_write(&pernet_ops_rwsem);
return err;
}
diff --git a/drivers/net/netdevsim/devlink.c b/drivers/net/netdevsim/devlink.c
index bbdcf064ba10..27ae05c5fdaf 100644
--- a/drivers/net/netdevsim/devlink.c
+++ b/drivers/net/netdevsim/devlink.c
@@ -218,22 +218,22 @@ void nsim_devlink_teardown(struct netdevsim *ns)
}
}
-void nsim_devlink_setup(struct netdevsim *ns)
+int nsim_devlink_setup(struct netdevsim *ns)
{
struct net *net = nsim_to_net(ns);
bool *reg_devlink = net_generic(net, nsim_devlink_id);
struct devlink *devlink;
- int err = -ENOMEM;
+ int err;
/* only one device per namespace controls devlink */
if (!*reg_devlink) {
ns->devlink = NULL;
- return;
+ return 0;
}
devlink = devlink_alloc(&nsim_devlink_ops, 0);
if (!devlink)
- return;
+ return -ENOMEM;
err = devlink_register(devlink, &ns->dev);
if (err)
@@ -247,12 +247,14 @@ void nsim_devlink_setup(struct netdevsim *ns)
*reg_devlink = false;
- return;
+ return 0;
err_dl_unregister:
devlink_unregister(devlink);
err_devlink_free:
devlink_free(devlink);
+
+ return err;
}
/* Initialize per network namespace state */
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 8b30ab3ea2c2..ec68f38213d9 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -167,10 +167,14 @@ static int nsim_init(struct net_device *dev)
SET_NETDEV_DEV(dev, &ns->dev);
- nsim_devlink_setup(ns);
+ err = nsim_devlink_setup(ns);
+ if (err)
+ goto err_unreg_dev;
return 0;
+err_unreg_dev:
+ device_unregister(&ns->dev);
err_bpf_uninit:
nsim_bpf_uninit(ns);
err_debugfs_destroy:
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index afb8cf90c0fd..3a8581af3b85 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -117,7 +117,7 @@ enum nsim_resource_id {
NSIM_RESOURCE_IPV6_FIB_RULES,
};
-void nsim_devlink_setup(struct netdevsim *ns);
+int nsim_devlink_setup(struct netdevsim *ns);
void nsim_devlink_teardown(struct netdevsim *ns);
int nsim_devlink_init(void);
@@ -128,8 +128,9 @@ void nsim_fib_exit(void);
u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max);
int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val);
#else
-static inline void nsim_devlink_setup(struct netdevsim *ns)
+static inline int nsim_devlink_setup(struct netdevsim *ns)
{
+ return 0;
}
static inline void nsim_devlink_teardown(struct netdevsim *ns)