[PATCH v2 6/6] net/ncsi: Support VLAN mode configuration

From: Jiaqing Zhao
Date: Fri Jun 10 2022 - 13:04:26 EST


NCSI specification defines 4 VLAN modes, currently kernel NCSI driver
only supports the "VLAN + non-VLAN" mode (Mode #2), and there is no
way to detect which modes are supported by the device. This patch adds
support for configuring VLAN mode via the "ncsi,vlan-mode" devicetree
node.

Signed-off-by: Jiaqing Zhao <jiaqing.zhao@xxxxxxxxxxxxxxx>
---
net/ncsi/internal.h | 1 +
net/ncsi/ncsi-manage.c | 41 ++++++++++++++++++++++++++++++++++-------
2 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 7f384f841019..6a988c898a8d 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -334,6 +334,7 @@ struct ncsi_dev_priv {
struct work_struct work; /* For channel management */
struct packet_type ptype; /* NCSI packet Rx handler */
struct list_head node; /* Form NCSI device list */
+ u32 vlan_mode; /* VLAN mode */
#define NCSI_MAX_VLAN_VIDS 15
struct list_head vlan_vids; /* List of active VLAN IDs */

diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 3fb95f29e3e2..a398b0eb72b2 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -10,6 +10,7 @@
#include <linux/skbuff.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <dt-bindings/net/ncsi.h>

#include <net/ncsi.h>
#include <net/net_namespace.h>
@@ -1042,7 +1043,11 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
nd->state = ncsi_dev_state_config_oem_gma;
break;
case ncsi_dev_state_config_oem_gma:
- nd->state = ncsi_dev_state_config_clear_vids;
+ /* Only set up hardware VLAN filters in filtered mode */
+ if (ndp->vlan_mode == NCSI_VLAN_MODE_FILTERED)
+ nd->state = ncsi_dev_state_config_clear_vids;
+ else
+ nd->state = ncsi_dev_state_config_ev;
ret = -1;

#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
@@ -1094,11 +1099,15 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
nd->state = ncsi_dev_state_config_svf;
/* Enable/Disable the VLAN filter */
} else if (nd->state == ncsi_dev_state_config_ev) {
- if (list_empty(&ndp->vlan_vids)) {
- nca.type = NCSI_PKT_CMD_DV;
- } else {
+ if (ndp->vlan_mode == NCSI_VLAN_MODE_FILTERED &&
+ !list_empty(&ndp->vlan_vids)) {
nca.type = NCSI_PKT_CMD_EV;
nca.bytes[3] = NCSI_CAP_VLAN_FILTERED;
+ } else if (ndp->vlan_mode == NCSI_VLAN_MODE_ANY) {
+ nca.type = NCSI_PKT_CMD_EV;
+ nca.bytes[3] = NCSI_CAP_VLAN_ANY;
+ } else {
+ nca.type = NCSI_PKT_CMD_DV;
}
nd->state = ncsi_dev_state_config_sma;
} else if (nd->state == ncsi_dev_state_config_sma) {
@@ -1800,15 +1809,33 @@ struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
ndp->ptype.dev = dev;
dev_add_pack(&ndp->ptype);

+ /* Set default VLAN mode (filtered) */
+ ndp->vlan_mode = NCSI_VLAN_MODE_FILTERED;
+
pdev = to_platform_device(dev->dev.parent);
if (pdev) {
np = pdev->dev.of_node;
- if (np && of_get_property(np, "mlx,multi-host", NULL))
- ndp->mlx_multi_host = true;
+ if (np) {
+ u32 vlan_mode;
+
+ if (!of_property_read_u32(np, "ncsi,vlan-mode", &vlan_mode)) {
+ if (vlan_mode > NCSI_VLAN_MODE_ANY ||
+ vlan_mode == NCSI_VLAN_MODE_ONLY)
+ dev_warn(&pdev->dev, "NCSI: Unsupported VLAN mode %u",
+ vlan_mode);
+ else
+ ndp->vlan_mode = vlan_mode;
+ dev_info(&pdev->dev, "NCSI: Configured VLAN mode %u",
+ ndp->vlan_mode);
+ }
+ if (of_get_property(np, "mlx,multi-host", NULL))
+ ndp->mlx_multi_host = true;
+ }
}

/* Enable hardware VLAN filtering */
- if (dev->netdev_ops->ndo_vlan_rx_add_vid == ncsi_vlan_rx_add_vid &&
+ if (ndp->vlan_mode == NCSI_VLAN_MODE_FILTERED &&
+ dev->netdev_ops->ndo_vlan_rx_add_vid == ncsi_vlan_rx_add_vid &&
dev->netdev_ops->ndo_vlan_rx_kill_vid == ncsi_vlan_rx_kill_vid)
dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;

--
2.34.1