[iwl-net,5/5] ice: Implement VF LLDP TX support for VF

Message ID 20240228155957.408036-6-larysa.zaremba@intel.com
State New
Headers
Series ice: LLDP support for VFs |

Commit Message

Larysa Zaremba Feb. 28, 2024, 3:59 p.m. UTC
  From: Mateusz Pacuszka <mateuszx.pacuszka@intel.com>

Add option to enable transmit LLDP on single trusted VF via a sysfs entry,
for example:

echo '1' > /sys/class/net/<PF_IFNAME>/device/virtfn0/transmit_lldp

Signed-off-by: Mateusz Pacuszka <mateuszx.pacuszka@intel.com>
Co-developed-by: Jakub Buchocki <jakubx.buchocki@intel.com>
Signed-off-by: Jakub Buchocki <jakubx.buchocki@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_lib.c    |   3 +
 drivers/net/ethernet/intel/ice/ice_sriov.c  |   4 +
 drivers/net/ethernet/intel/ice/ice_vf_lib.c | 163 ++++++++++++++++++++
 drivers/net/ethernet/intel/ice/ice_vf_lib.h |  14 ++
 4 files changed, 184 insertions(+)
  

Patch

diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 19f08f2e0139..32b1ed74bfa4 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -2062,6 +2062,9 @@  void ice_dis_sw_lldp(struct ice_pf *pf)
 
 		if (vsi && vsi->rx_lldp_ena)
 			ice_cfg_sw_lldp(vsi, false, false);
+
+		if (vf->transmit_lldp)
+			ice_handle_vf_tx_lldp(vf, false);
 	}
 }
 
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index a94a1c48c3de..0fe07330cc1a 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -832,6 +832,10 @@  static int ice_create_vf_entries(struct ice_pf *pf, u16 num_vfs)
 		vf->vfdev = vfdev;
 		vf->vf_sw_id = pf->first_sw;
 
+		err = ice_init_vf_sysfs(vf);
+		if (err)
+			goto err_free_entries;
+
 		pci_dev_get(vfdev);
 
 		/* set default number of MSI-X */
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index 2de6ef3661cf..244d0ac7c9c4 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -577,6 +577,165 @@  void ice_ena_all_vfs_rx_lldp(struct ice_pf *pf)
 	}
 }
 
+static bool ice_is_transmit_lldp_enabled(struct ice_pf *pf)
+{
+	struct ice_vf *vf;
+	unsigned int bkt;
+
+	ice_for_each_vf(pf, bkt, vf) {
+		if (vf->transmit_lldp)
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * ice_handle_vf_tx_lldp - enable/disable LLDP TX on VF
+ * @vf: VF to configure Tx LLDP for
+ * @ena: Enable or disable Tx LLDP switch rule
+ *
+ * Configure Tx filters for VF to transmit LLDP
+ */
+int ice_handle_vf_tx_lldp(struct ice_vf *vf, bool ena)
+{
+	void (*allow_override)(struct ice_vsi_ctx *ctx);
+	struct ice_vsi *vsi, *main_vsi;
+	struct ice_pf *pf = vf->pf;
+	struct device *dev;
+	bool prev_ena;
+
+	dev = ice_pf_to_dev(pf);
+	vsi = ice_get_vf_vsi(vf);
+	main_vsi = ice_get_main_vsi(pf);
+	if (!vsi || !main_vsi)
+		return -ENOENT;
+
+	if (ena && test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) {
+		dev_err(dev, "Transmit LLDP VF is only allowed when FW LLDP Agent is disabled");
+		return -EPERM;
+	}
+
+	if (ena && ice_is_transmit_lldp_enabled(pf)) {
+		dev_err(dev, "Only a single VF per port is allowed to transmit LLDP packets, ignoring the settings");
+		return -EPERM;
+	}
+
+	allow_override = ena ? ice_vsi_ctx_set_allow_override
+			     : ice_vsi_ctx_clear_allow_override;
+	prev_ena = vsi->info.sec_flags & ICE_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD;
+
+	if (ice_vsi_update_security(vsi, allow_override))
+		return -ENOENT;
+
+	/* If VF can transmit LLDP, then PF cannot and vice versa */
+	allow_override = ena ? ice_vsi_ctx_clear_allow_override
+			     : ice_vsi_ctx_set_allow_override;
+
+	if (ice_vsi_update_security(main_vsi, allow_override)) {
+		allow_override = prev_ena  ? ice_vsi_ctx_set_allow_override
+					   : ice_vsi_ctx_clear_allow_override;
+		ice_vsi_update_security(vsi, allow_override);
+		return -ENOENT;
+	}
+
+	vf->transmit_lldp = ena;
+	return 0;
+}
+
+static ssize_t ice_transmit_lldp_vf_attr_show(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf)
+{
+	struct ice_vf *vf = ice_get_vf_by_dev(dev);
+
+	if (!vf)
+		return -ENOENT;
+
+	return sysfs_emit(buf, "%u\n", vf->transmit_lldp);
+}
+
+static ssize_t ice_transmit_lldp_vf_attr_store(struct device *dev,
+					       struct device_attribute *attr,
+					       const char *buf, size_t count)
+{
+	struct pci_dev *vfdev = container_of(dev, struct pci_dev, dev);
+	struct ice_vf *vf = ice_get_vf_by_dev(dev);
+	struct pci_dev *pdev = vfdev->physfn;
+	struct ice_pf *pf;
+	bool ena;
+	int err;
+
+	if (!vf)
+		return -ENOENT;
+
+	pf = pci_get_drvdata(pdev);
+	if (!pf)
+		return -ENOENT;
+
+	err = kstrtobool(buf, &ena);
+	if (err)
+		return -EINVAL;
+
+	if (ena == vf->transmit_lldp) {
+		dev_dbg(dev, "Transmit LLDP value already set for VF %d",
+			vf->vf_id);
+		return count;
+	}
+
+	err = ice_handle_vf_tx_lldp(vf, ena);
+	if (err)
+		return err;
+
+	return count;
+}
+
+static int ice_init_vf_transmit_lldp_sysfs(struct ice_vf *vf)
+{
+	struct device_attribute tmp = __ATTR(transmit_lldp, 0644,
+					     ice_transmit_lldp_vf_attr_show,
+					     ice_transmit_lldp_vf_attr_store);
+
+	vf->transmit_lldp_attr = tmp;
+
+	return device_create_file(&vf->vfdev->dev, &vf->transmit_lldp_attr);
+}
+
+/**
+ * ice_init_vf_sysfs - Initialize sysfs entries for a VF
+ * @vf: VF to init sysfs for
+ *
+ * Initialize sysfs entries (accessible from the host) for a VF
+ */
+int ice_init_vf_sysfs(struct ice_vf *vf)
+{
+	struct device *dev = ice_pf_to_dev(vf->pf);
+	int err = 0;
+
+	if (!vf->vfdev) {
+		dev_err(dev, "%s: no vfdev", __func__);
+		return -ENOENT;
+	}
+
+	err = ice_init_vf_transmit_lldp_sysfs(vf);
+	if (err)
+		dev_err(dev, "could not init transmit_lldp sysfs entry, err: %d",
+			err);
+
+	return err;
+}
+
+static int ice_vf_apply_tx_lldp(struct ice_vf *vf)
+{
+	if (!vf->transmit_lldp)
+		return 0;
+
+	/* Disable it so it can be applied again. */
+	vf->transmit_lldp = false;
+
+	return ice_handle_vf_tx_lldp(vf, true);
+}
+
 /**
  * ice_vf_rebuild_host_cfg - host admin configuration is persistent across reset
  * @vf: VF to rebuild host configuration on
@@ -607,6 +766,10 @@  static void ice_vf_rebuild_host_cfg(struct ice_vf *vf)
 		dev_err(dev, "failed to rebuild spoofchk configuration for VF %d\n",
 			vf->vf_id);
 
+	if (ice_vf_apply_tx_lldp(vf))
+		dev_err(dev, "failed to rebuild transmit LLDP configuration for VF %d\n",
+			vf->vf_id);
+
 	/* rebuild aggregator node config for main VF VSI */
 	ice_vf_rebuild_aggregator_node_cfg(vsi);
 }
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 81f734f2ae41..63e53591541e 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -104,9 +104,11 @@  struct ice_vf {
 	struct ice_vlan port_vlan_info;	/* Port VLAN ID, QoS, and TPID */
 	struct virtchnl_vlan_caps vlan_v2_caps;
 	struct ice_mbx_vf_info mbx_info;
+	struct device_attribute transmit_lldp_attr;
 	u8 pf_set_mac:1;		/* VF MAC address set by VMM admin */
 	u8 trusted:1;
 	u8 spoofchk:1;
+	u8 transmit_lldp:1;
 	u8 link_forced:1;
 	u8 link_up:1;			/* only valid if VF link is forced */
 	/* VSI indices - actual VSI pointers are maintained in the PF structure
@@ -234,6 +236,8 @@  void ice_reset_all_vfs(struct ice_pf *pf);
 struct ice_vsi *ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi);
 void ice_ena_all_vfs_rx_lldp(struct ice_pf *pf);
 int ice_ena_vf_rx_lldp(struct ice_vf *vf);
+int ice_init_vf_sysfs(struct ice_vf *vf);
+int ice_handle_vf_tx_lldp(struct ice_vf *vf, bool ena);
 #else /* CONFIG_PCI_IOV */
 static inline struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id)
 {
@@ -313,6 +317,16 @@  ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi)
 static inline void ice_ena_all_vfs_rx_lldp(struct ice_pf *pf)
 {
 }
+
+static inline int ice_handle_vf_tx_lldp(struct ice_vf *vf, bool ena)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int ice_init_vf_sysfs(struct ice_vf *vf)
+{
+	return 0;
+}
 #endif /* !CONFIG_PCI_IOV */
 
 #endif /* _ICE_VF_LIB_H_ */