AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/31 03:57 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch series modifies the NXP/Freescale ENETC Ethernet PF and VF drivers (drivers/net/ethernet/freescale/enetc/), adding support for ENETC v4 VF mailbox communications, MAC hash filtering, and link status notifications. These changes are specific to NXP ENETC PCIe hardware not emulated in standard QEMU or virtualized environments like GCE, making the modified code unreachable for fuzzing.",
  "WorthFuzzing": false
}

1/1 2026/08/31 03:57 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 18bc5b00603acfb0667904c6a334a58c9fdee884\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Mon Aug 31 03:57:53 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig\nindex db5c17a446137..f425f82a6213a 100644\n--- a/drivers/net/ethernet/freescale/enetc/Kconfig\n+++ b/drivers/net/ethernet/freescale/enetc/Kconfig\n@@ -69,6 +69,7 @@ config FSL_ENETC_VF\n \tdepends on PCI_MSI\n \tselect FSL_ENETC_CORE\n \tselect FSL_ENETC_MDIO\n+\tselect NXP_NTMP\n \tselect PHYLINK\n \tselect DIMLIB\n \tselect CRC_ITU_T\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c\nindex 80f0082f6c633..fb5df740650e0 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc.c\n+++ b/drivers/net/ethernet/freescale/enetc/enetc.c\n@@ -2935,11 +2935,31 @@ static void enetc_clear_interrupts(struct enetc_ndev_priv *priv)\n static int enetc_phylink_connect(struct net_device *ndev)\n {\n \tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n+\tstruct enetc_si *si = priv-\u003esi;\n \tstruct ethtool_keee edata;\n \tint err;\n \n \tif (!priv-\u003ephylink) {\n \t\t/* phy-less mode */\n+\t\tif (!si-\u003eops-\u003evf_reg_link_status_notifier)\n+\t\t\tgoto carrier_on;\n+\n+\t\t/* For phy-less VFs on ENETC v4, attempt to register a link\n+\t\t * status notifier with the PF via the VSI-to-PSI messaging\n+\t\t * channel. If registration succeeds, the PF will immediately\n+\t\t * send the current link status and broadcast future link\n+\t\t * transitions; carrier state is then managed in\n+\t\t * enetc_vf_msg_handle_link_status(). If registration fails,\n+\t\t * fall back to the LS1028A behaviour and assert carrier\n+\t\t * unconditionally via netif_carrier_on().\n+\t\t */\n+\t\tif (!si-\u003eops-\u003evf_reg_link_status_notifier(si))\n+\t\t\treturn 0;\n+\n+\t\tdev_warn(\u0026ndev-\u003edev,\n+\t\t\t \"Link status notifier registration failed\\n\");\n+\n+carrier_on:\n \t\tnetif_carrier_on(ndev);\n \t\treturn 0;\n \t}\n@@ -3011,6 +3031,7 @@ int enetc_open(struct net_device *ndev)\n {\n \tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n \tstruct enetc_bdr_resource *tx_res, *rx_res;\n+\tstruct enetc_si *si = priv-\u003esi;\n \tbool extended;\n \tint err;\n \n@@ -3051,8 +3072,15 @@ int enetc_open(struct net_device *ndev)\n err_alloc_rx:\n \tenetc_free_tx_resources(tx_res, priv-\u003enum_tx_rings);\n err_alloc_tx:\n-\tif (priv-\u003ephylink)\n+\tif (priv-\u003ephylink) {\n \t\tphylink_disconnect_phy(priv-\u003ephylink);\n+\t} else if (si-\u003eops-\u003evf_unreg_link_status_notifier \u0026\u0026\n+\t\t   test_bit(ENETC_LINK_STATUS_NOTIFIER_REGISTERED,\n+\t\t\t    \u0026priv-\u003eflags)) {\n+\t\tif (si-\u003eops-\u003evf_unreg_link_status_notifier(si))\n+\t\t\tdev_warn(\u0026ndev-\u003edev,\n+\t\t\t\t \"Link status notifier unregistration failed\\n\");\n+\t}\n err_phy_connect:\n \tenetc_free_irqs(priv);\n err_setup_irqs:\n@@ -3093,6 +3121,7 @@ EXPORT_SYMBOL_GPL(enetc_stop);\n int enetc_close(struct net_device *ndev)\n {\n \tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n+\tstruct enetc_si *si = priv-\u003esi;\n \n \tenetc_stop(ndev);\n \n@@ -3100,6 +3129,17 @@ int enetc_close(struct net_device *ndev)\n \t\tphylink_stop(priv-\u003ephylink);\n \t\tphylink_disconnect_phy(priv-\u003ephylink);\n \t} else {\n+\t\tif (!si-\u003eops-\u003evf_unreg_link_status_notifier ||\n+\t\t    !test_bit(ENETC_LINK_STATUS_NOTIFIER_REGISTERED,\n+\t\t\t      \u0026priv-\u003eflags))\n+\t\t\tgoto carrier_off;\n+\n+\t\tif (!si-\u003eops-\u003evf_unreg_link_status_notifier(si))\n+\t\t\tgoto carrier_off;\n+\n+\t\tdev_warn(\u0026ndev-\u003edev,\n+\t\t\t \"Link status notifier unregistration failed\\n\");\n+carrier_off:\n \t\tnetif_carrier_off(ndev);\n \t}\n \n@@ -3794,6 +3834,13 @@ static const struct enetc_drvdata enetc_vf_data = {\n \t.eth_ops = \u0026enetc_vf_ethtool_ops,\n };\n \n+static const struct enetc_drvdata enetc4_vf_data = {\n+\t.sysclk_freq = ENETC_CLK_333M,\n+\t.tx_csum = true,\n+\t.max_frags = ENETC4_MAX_SKB_FRAGS,\n+\t.eth_ops = \u0026enetc_vf_ethtool_ops,\n+};\n+\n static const struct enetc_platform_info enetc_info[] = {\n \t{ .revision = ENETC_REV_1_0,\n \t  .dev_id = ENETC_DEV_ID_PF,\n@@ -3807,6 +3854,10 @@ static const struct enetc_platform_info enetc_info[] = {\n \t  .dev_id = ENETC_DEV_ID_VF,\n \t  .data = \u0026enetc_vf_data,\n \t},\n+\t{ .revision = ENETC_REV_4_1,\n+\t  .dev_id = NXP_ENETC_VF_DEV_ID,\n+\t  .data = \u0026enetc4_vf_data,\n+\t},\n \t{\n \t  .revision = ENETC_REV_4_3,\n \t  .dev_id = NXP_ENETC_PPM_DEV_ID,\n@@ -3816,6 +3867,10 @@ static const struct enetc_platform_info enetc_info[] = {\n \t  .dev_id = NXP_ENETC_PF_DEV_ID,\n \t  .data = \u0026enetc4_pf_data,\n \t},\n+\t{ .revision = ENETC_REV_4_3,\n+\t  .dev_id = NXP_ENETC_VF_DEV_ID,\n+\t  .data = \u0026enetc4_vf_data,\n+\t},\n };\n \n int enetc_get_driver_data(struct enetc_si *si)\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h\nindex d1e9d91300575..52bd502976ee8 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc.h\n+++ b/drivers/net/ethernet/freescale/enetc/enetc.h\n@@ -25,6 +25,7 @@\n #define ENETC_CBD_DATA_MEM_ALIGN 64\n \n #define ENETC_MADDR_HASH_TBL_SZ\t64\n+#define ENETC_INT_NAME_MAX\t(IFNAMSIZ + 8)\n \n enum enetc_mac_addr_type {UC, MC, MADDR_TYPE};\n \n@@ -299,6 +300,10 @@ struct enetc_si_ops {\n \tint (*set_rss_table)(struct enetc_si *si, const u32 *table, int count);\n \tint (*setup_cbdr)(struct enetc_si *si);\n \tvoid (*teardown_cbdr)(struct enetc_si *si);\n+\n+\t/* VSI-specific hooks */\n+\tint (*vf_reg_link_status_notifier)(struct enetc_si *si);\n+\tint (*vf_unreg_link_status_notifier)(struct enetc_si *si);\n };\n \n /* PCI IEP device data */\n@@ -333,6 +338,11 @@ struct enetc_si {\n \n \tstruct dentry *debugfs_root;\n \tstruct enetc_msg_swbd msg; /* Only valid for VSI */\n+\tstruct workqueue_struct *workqueue;\n+\tstruct work_struct msg_task;\n+\tchar msg_int_name[ENETC_INT_NAME_MAX];\n+\n+\tstruct enetc_mac_filter mac_filter[MADDR_TYPE];\n };\n \n #define ENETC_SI_ALIGN\t32\n@@ -374,7 +384,6 @@ static inline bool enetc_is_pseudo_mac(struct enetc_si *si)\n }\n \n #define ENETC_MAX_NUM_TXQS\t8\n-#define ENETC_INT_NAME_MAX\t(IFNAMSIZ + 8)\n \n struct enetc_int_vector {\n \tvoid __iomem *rbier;\n@@ -425,6 +434,7 @@ enum enetc_flags_bit {\n \tENETC_TX_ONESTEP_TSTAMP_IN_PROGRESS = 0,\n \tENETC_TX_DOWN,\n \tENETC_RXBDR_CM,\n+\tENETC_LINK_STATUS_NOTIFIER_REGISTERED,\n };\n \n /* interrupt coalescing modes */\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c\nindex 5029038bf99fa..91af78ba4f742 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c\n+++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c\n@@ -6,24 +6,48 @@\n #include \u003clinux/seq_file.h\u003e\n #include \u003clinux/string_choices.h\u003e\n \n-#include \"enetc_pf.h\"\n+#include \"enetc_pf_common.h\"\n #include \"enetc4_debugfs.h\"\n \n-static void enetc_show_si_mac_hash_filter(struct seq_file *s, int i)\n+static void enetc_vf_state_lock(struct enetc_pf *pf, int vf_id)\n {\n-\tstruct enetc_si *si = s-\u003eprivate;\n-\tstruct enetc_hw *hw = \u0026si-\u003ehw;\n+\tstruct enetc_vf_state *vf_state;\n+\n+\tif (vf_id \u003c 0)\n+\t\treturn;\n+\n+\tvf_state = \u0026pf-\u003evf_state[vf_id];\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+}\n+\n+static void enetc_vf_state_unlock(struct enetc_pf *pf, int vf_id)\n+{\n+\tstruct enetc_vf_state *vf_state;\n+\n+\tif (vf_id \u003c 0)\n+\t\treturn;\n+\n+\tvf_state = \u0026pf-\u003evf_state[vf_id];\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+}\n+\n+static void enetc_show_si_mac_hash_filter(struct seq_file *s, int si_id)\n+{\n+\tstruct enetc_pf *pf = enetc_si_priv(s-\u003eprivate);\n+\tstruct enetc_hw *hw = \u0026pf-\u003esi-\u003ehw;\n \tu32 hash_h, hash_l;\n \n-\thash_l = enetc_port_rd(hw, ENETC4_PSIUMHFR0(i));\n-\thash_h = enetc_port_rd(hw, ENETC4_PSIUMHFR1(i));\n+\tenetc_vf_state_lock(pf, si_id - 1);\n+\thash_l = enetc_port_rd(hw, ENETC4_PSIUMHFR0(si_id));\n+\thash_h = enetc_port_rd(hw, ENETC4_PSIUMHFR1(si_id));\n \tseq_printf(s, \"SI %d unicast MAC hash filter: 0x%08x%08x\\n\",\n-\t\t   i, hash_h, hash_l);\n+\t\t   si_id, hash_h, hash_l);\n \n-\thash_l = enetc_port_rd(hw, ENETC4_PSIMMHFR0(i));\n-\thash_h = enetc_port_rd(hw, ENETC4_PSIMMHFR1(i));\n+\thash_l = enetc_port_rd(hw, ENETC4_PSIMMHFR0(si_id));\n+\thash_h = enetc_port_rd(hw, ENETC4_PSIMMHFR1(si_id));\n \tseq_printf(s, \"SI %d multicast MAC hash filter: 0x%08x%08x\\n\",\n-\t\t   i, hash_h, hash_l);\n+\t\t   si_id, hash_h, hash_l);\n+\tenetc_vf_state_unlock(pf, si_id - 1);\n }\n \n static int enetc_mac_filter_show(struct seq_file *s, void *data)\n@@ -37,7 +61,11 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data)\n \tint err = 0;\n \tint i;\n \n+\t/* Prevent concurrent access from causing PSIPMMR to be modified */\n+\tenetc_pf_msg_lock(pf);\n \tval = enetc_port_rd(hw, ENETC4_PSIPMMR);\n+\tenetc_pf_msg_unlock(pf);\n+\n \tfor (i = 0; i \u003c num_si; i++) {\n \t\tseq_printf(s, \"SI %d Unicast Promiscuous mode: %s\\n\", i,\n \t\t\t   str_enabled_disabled(PSIPMMR_SI_MAC_UP(i) \u0026 val));\n@@ -45,13 +73,12 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data)\n \t\t\t   str_enabled_disabled(PSIPMMR_SI_MAC_MP(i) \u0026 val));\n \t}\n \n+\trtnl_lock();\n \t/* MAC hash filter table */\n \tfor (i = 0; i \u003c num_si; i++)\n \t\tenetc_show_si_mac_hash_filter(s, i);\n \n \tuser = \u0026pf-\u003esi-\u003entmp_user;\n-\trtnl_lock();\n-\n \tif (bitmap_empty(user-\u003emaft_eid_bitmap, user-\u003emaft_num_entries))\n \t\tgoto unlock_rtnl;\n \ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h\nindex 09025e7a2a3ae..e23d8d82d2ba9 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h\n+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h\n@@ -12,6 +12,7 @@\n #define NXP_ENETC_VENDOR_ID\t\t0x1131\n #define NXP_ENETC_PF_DEV_ID\t\t0xe101\n #define NXP_ENETC_PPM_DEV_ID\t\t0xe110\n+#define NXP_ENETC_VF_DEV_ID\t\t0xef00\n \n /**********************Station interface registers************************/\n /* Station interface LSO segmentation flag mask register 0/1 */\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c\nindex 9bb1004548abc..b4d76505bc034 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c\n+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c\n@@ -12,11 +12,6 @@\n \n #define ENETC_SI_MAX_RING_NUM\t8\n \n-#define ENETC_MAC_FILTER_TYPE_UC\tBIT(0)\n-#define ENETC_MAC_FILTER_TYPE_MC\tBIT(1)\n-#define ENETC_MAC_FILTER_TYPE_ALL\t(ENETC_MAC_FILTER_TYPE_UC | \\\n-\t\t\t\t\t ENETC_MAC_FILTER_TYPE_MC)\n-\n static void enetc4_get_port_caps(struct enetc_pf *pf)\n {\n \tstruct enetc_hw *hw = \u0026pf-\u003esi-\u003ehw;\n@@ -137,7 +132,7 @@ static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,\n static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf,\n \t\t\t\t\t struct netdev_hw_addr_list *uc)\n {\n-\tstruct enetc_mac_filter *mac_filter = \u0026pf-\u003emac_filter[UC];\n+\tstruct enetc_mac_filter *mac_filter = \u0026pf-\u003esi-\u003emac_filter[UC];\n \tstruct netdev_hw_addr *ha;\n \tu64 hash;\n \n@@ -172,7 +167,7 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,\n \n \terr = enetc4_pf_add_maft_entries(pf, uc);\n \tif (!err) {\n-\t\tenetc_reset_mac_addr_filter(\u0026pf-\u003emac_filter[UC]);\n+\t\tenetc_reset_mac_addr_filter(\u0026si-\u003emac_filter[UC]);\n \t\tenetc_set_si_uc_hash_filter(si, 0, 0);\n \t}\n \n@@ -182,7 +177,7 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,\n static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf,\n \t\t\t\t\t struct netdev_hw_addr_list *mc)\n {\n-\tstruct enetc_mac_filter *mac_filter = \u0026pf-\u003emac_filter[MC];\n+\tstruct enetc_mac_filter *mac_filter = \u0026pf-\u003esi-\u003emac_filter[MC];\n \tstruct netdev_hw_addr *ha;\n \tu64 hash;\n \n@@ -217,19 +212,43 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type,\n \t\tenetc4_pf_set_mc_hash_filter(pf, mc);\n }\n \n+static void enetc4_pf_vf_flr_handler(struct enetc_pf *pf, int vf_id)\n+{\n+\tstruct enetc_vf_state *vf_state;\n+\tbool uc_promisc, mc_promisc;\n+\n+\tvf_state = \u0026pf-\u003evf_state[vf_id];\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\n+\tuc_promisc = !!(vf_state-\u003eflags \u0026 ENETC_VF_FLAG_UC_PROMISC);\n+\tmc_promisc = !!(vf_state-\u003eflags \u0026 ENETC_VF_FLAG_MC_PROMISC);\n+\n+\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\tenetc_set_si_uc_promisc(pf-\u003esi, vf_id + 1, uc_promisc);\n+\tenetc_set_si_mc_promisc(pf-\u003esi, vf_id + 1, mc_promisc);\n+\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+}\n+\n static const struct enetc_pf_ops enetc4_pf_ops = {\n \t.set_si_primary_mac = enetc4_pf_set_si_primary_mac,\n \t.get_si_primary_mac = enetc4_pf_get_si_primary_mac,\n+\t.vf_flr_handler = enetc4_pf_vf_flr_handler,\n };\n \n static int enetc4_pf_struct_init(struct enetc_si *si)\n {\n \tstruct enetc_pf *pf = enetc_si_priv(si);\n+\tint err;\n \n \tpf-\u003esi = si;\n-\tpf-\u003etotal_vfs = pci_sriov_get_totalvfs(si-\u003epdev);\n \tpf-\u003eops = \u0026enetc4_pf_ops;\n \n+\terr = enetc_init_sriov_resources(pf);\n+\tif (err)\n+\t\treturn err;\n+\n \tenetc4_get_port_caps(pf);\n \tenetc4_get_psi_hw_features(si);\n \n@@ -524,8 +543,10 @@ static int enetc4_pf_set_rx_mode(struct net_device *ndev,\n \t\ttype = ENETC_MAC_FILTER_TYPE_ALL;\n \t}\n \n+\tenetc_pf_msg_lock(pf);\n \tenetc_set_si_uc_promisc(si, 0, uc_promisc);\n \tenetc_set_si_mc_promisc(si, 0, mc_promisc);\n+\tenetc_pf_msg_unlock(pf);\n \n \tif (uc_promisc) {\n \t\tenetc_set_si_uc_hash_filter(si, 0, 0);\n@@ -574,6 +595,9 @@ static const struct net_device_ops enetc4_ndev_ops = {\n \t.ndo_eth_ioctl\t\t= enetc_ioctl,\n \t.ndo_hwtstamp_get\t= enetc_hwtstamp_get,\n \t.ndo_hwtstamp_set\t= enetc_hwtstamp_set,\n+\t.ndo_set_vf_trust\t= enetc_pf_set_vf_trust,\n+\t.ndo_set_vf_mac\t\t= enetc_pf_set_vf_mac,\n+\t.ndo_get_vf_config\t= enetc_pf_get_vf_config,\n };\n \n static struct phylink_pcs *\n@@ -894,6 +918,7 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config,\n \tenetc4_set_rx_pause(pf, rx_pause);\n \tenetc4_mac_tx_enable(pf);\n \tenetc4_mac_rx_enable(pf);\n+\tenetc_pf_notify_vf_link_up(pf);\n }\n \n static void enetc4_pl_mac_link_down(struct phylink_config *config,\n@@ -902,6 +927,7 @@ static void enetc4_pl_mac_link_down(struct phylink_config *config,\n {\n \tstruct enetc_pf *pf = phylink_to_enetc_pf(config);\n \n+\tenetc_pf_notify_vf_link_down(pf);\n \tenetc4_mac_rx_graceful_stop(pf);\n \tenetc4_mac_tx_graceful_stop(pf);\n }\n@@ -1096,6 +1122,9 @@ static void enetc4_pf_remove(struct pci_dev *pdev)\n \tstruct enetc_si *si = pci_get_drvdata(pdev);\n \tstruct enetc_pf *pf = enetc_si_priv(si);\n \n+\tif (pf-\u003enum_vfs)\n+\t\tenetc_sriov_configure(pdev, 0);\n+\n \tenetc_remove_debugfs(si);\n \tenetc4_pf_netdev_destroy(si);\n \tenetc4_pf_free(pf);\n@@ -1113,6 +1142,7 @@ static struct pci_driver enetc4_pf_driver = {\n \t.id_table = enetc4_pf_id_table,\n \t.probe = enetc4_pf_probe,\n \t.remove = enetc4_pf_remove,\n+\t.sriov_configure = enetc_sriov_configure,\n };\n module_pci_driver(enetc4_pf_driver);\n \ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c\nindex 07b7832f24276..7965dfd06f5f6 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c\n@@ -859,6 +859,9 @@ static int enetc_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc,\n \tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n \tint i, j;\n \n+\tif (!is_enetc_rev1(priv-\u003esi))\n+\t\treturn -EOPNOTSUPP;\n+\n \tswitch (rxnfc-\u003ecmd) {\n \tcase ETHTOOL_GRXCLSRLCNT:\n \t\t/* total number of entries */\n@@ -903,6 +906,9 @@ static int enetc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc)\n \tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n \tint err;\n \n+\tif (!is_enetc_rev1(priv-\u003esi))\n+\t\treturn -EOPNOTSUPP;\n+\n \tswitch (rxnfc-\u003ecmd) {\n \tcase ETHTOOL_SRXCLSRLINS:\n \t\tif (rxnfc-\u003efs.location \u003e= priv-\u003esi-\u003enum_fs_entries)\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h\nindex 16da732dc5de8..2c9d9042eb0bb 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h\n@@ -80,6 +80,14 @@ static inline u32 enetc_vsi_set_msize(u32 size)\n #define ENETC_SIMSGSR_SET_MC(val) ((val) \u003c\u003c 16)\n #define ENETC_SIMSGSR_GET_MC(val) ((val) \u003e\u003e 16)\n \n+#define ENETC_PSIMSGSR\t\t0x208\n+/* n is VF index, which is less than 15 */\n+#define  PSIMSGSR_MS(n)\t\tBIT((n) + 1)\n+#define  PSIMSGSR_MC\t\tGENMASK(31, 16)\n+\n+#define ENETC_VSIMSGRR\t\t0x208\n+#define  VSIMSGRR_MC\t\tGENMASK(31, 16)\n+\n /* SI statistics */\n #define ENETC_SIROCT\t0x300\n #define ENETC_SIRFRM\t0x308\n@@ -103,8 +111,26 @@ static inline u32 enetc_vsi_set_msize(u32 size)\n #define ENETC_SICAPR0\t0x900\n #define ENETC_SICAPR1\t0x904\n \n+#define ENETC_VSIIER\t0xa00\n+#define  VSIIER_MRIE\tBIT(9)\n+\n+#define ENETC_VSIIDR\t0xa08\n+#define  VSIIDR_MR\tBIT(9)\n+\n #define ENETC_PSIIER\t0xa00\n #define ENETC_PSIIDR\t0xa08\n+\n+/* VF FLR interrupt mask, n is the active number of VFs.\n+ * It is available for ENETC_PSIIER and ENETC_PSIIDR registers.\n+ */\n+#define ENETC_VFFLR_MASK(n)\t\\\n+\t({ typeof(n) _n = (n); (_n) ? GENMASK(16 + (_n), 17) : 0; })\n+\n+/* VF FLR interrupt bit, n is VF index. It is available\n+ * for ENETC_PSIIER and ENETC_PSIIDR registers.\n+ */\n+#define ENETC_VFFLR_BIT(n)\tBIT(17 + (n))\n+\n #define ENETC_SITXIDR\t0xa18\n #define ENETC_SIRXIDR\t0xa28\n #define ENETC_SIMSIVR\t0xa30\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h\nindex d9677da389892..200651e6ce85a 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h\n@@ -66,8 +66,8 @@\n  * 2) PSI_TX_control: PSIMSGSR[MC] - for PSI to VSI notification messages\n  * (async mode)\n  *\n- * Note that for some GET messages, there is no COOKIE field, and the CLASS\n- * CODE field is expanded to 8 bits.\n+ * Note that for some PSI-to-VSI messages, there is no COOKIE field, and the\n+ * CLASS CODE field is expanded to 8 bits.\n  */\n \n #ifndef __ENETC_MAILBOX_H\n@@ -87,10 +87,26 @@\n /* The fileds of PSI-to-VSI message, the message is only 16-bit */\n #define ENETC_PF_MSG_COOKIE\t\t\tGENMASK(3, 0)\n #define ENETC_PF_MSG_CLASS_CODE\t\t\tGENMASK(7, 4)\n-/* Extend the class code to 8-bit for GET messages without COOKIE */\n+/* Extend the class code to 8-bit for PSI-to-VSI messages without COOKIE\n+ * The class code for the following messages is 8-bit.\n+ * 1. Get IP revision messages\n+ * 2. Link status messages\n+ * 3. Link speed messages\n+ */\n #define ENETC_PF_MSG_CLASS_CODE_U8\t\tGENMASK(7, 0)\n #define ENETC_PF_MSG_CLASS_ID\t\t\tGENMASK(15, 8)\n \n+#define ENETC_MAC_HASH_TABLE_SIZE_64\t\t0\n+#define ENETC_MSG_MAC_HASH_SIZE\t\t\tGENMASK(5, 0)\n+#define ENETC_MSG_MAC_TYPE\t\t\tGENMASK(7, 6)\n+#define  ENETC_MAC_FILTER_TYPE_UC\t\tBIT(0)\n+#define  ENETC_MAC_FILTER_TYPE_MC\t\tBIT(1)\n+#define  ENETC_MAC_FILTER_TYPE_ALL\t\t(ENETC_MAC_FILTER_TYPE_UC | \\\n+\t\t\t\t\t\t ENETC_MAC_FILTER_TYPE_MC)\n+\n+#define ENETC_MSG_MAC_FLUSH_MACS\t\tBIT(0)\n+#define ENETC_MSG_MAC_PROMISC_MODE\t\tBIT(1)\n+\n enum enetc_msg_class_id {\n \t/* Class ID for PSI-to-VSI messages */\n \tENETC_MSG_CLASS_ID_CMD_SUCCESS\t\t= 1,\n@@ -107,20 +123,66 @@ enum enetc_msg_class_id {\n \n \t/* Common Class ID for PSI-to-VSI and VSI-to-PSI messages */\n \tENETC_MSG_CLASS_ID_MAC_FILTER\t\t= 0x20,\n+\tENETC_MSG_CLASS_ID_LINK_STATUS\t\t= 0x80,\n+\tENETC_MSG_CLASS_ID_LINK_SPEED\t\t= 0x81,\n \tENETC_MSG_CLASS_ID_IP_REVISION\t\t= 0xf0,\n };\n \n enum enetc_msg_mac_filter_cmd_id {\n \tENETC_MSG_SET_PRIMARY_MAC,\n+\tENETC_MSG_SET_MAC_HASH_TABLE\t\t= 3,\n+\tENETC_MSG_SET_MAC_PROMISC_MODE\t\t= 5,\n };\n \n enum enetc_msg_ip_revision_cmd_id {\n \tENETC_MSG_GET_IP_MN\t\t\t= 1,\n };\n \n+enum enetc_msg_link_status_cmd_id {\n+\tENETC_MSG_GET_CURRENT_LINK_STATUS,\n+\tENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER,\n+\tENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER,\n+};\n+\n+enum enetc_msg_link_speed_cmd_id {\n+\tENETC_MSG_GET_CURRENT_LINK_SPEED,\n+\t/* The following command IDs are not currently supported */\n+\tENETC_MSG_REGISTER_SPEED_CHANGE_NOTIFIER,\n+\tENETC_MSG_UNREGISTER_SPEED_CHANGE_NOTIFIER,\n+};\n+\n /* Class-specific error return codes of MAC filter */\n enum enetc_mac_filter_class_code {\n \tENETC_MF_CLASS_CODE_INVALID_MAC,\n+\tENETC_MF_CLASS_CODE_INVALID_TYPE\t= 4,\n+\t/* Unicast Filter Is Denied */\n+\tENETC_MF_CLASS_CODE_UCF_DENY\t\t= 5,\n+};\n+\n+/* Class-specific notifications/codes of link status */\n+#define ENETC_CLASS_CODE_LINK_DOWN\t\tBIT(0)\n+#define ENETC_CLASS_CODE_TX_PAUSE_EN\t\tBIT(1)\n+\n+/* Class-specific notifications/codes of link speed */\n+enum enetc_link_speed_class_code {\n+\tENETC_MSG_SPEED_UNKNOWN,\n+\tENETC_MSG_SPEED_10M_HD,\n+\tENETC_MSG_SPEED_10M_FD,\n+\tENETC_MSG_SPEED_100M_HD,\n+\tENETC_MSG_SPEED_100M_FD,\n+\tENETC_MSG_SPEED_1000M,\n+\tENETC_MSG_SPEED_2500M,\n+\tENETC_MSG_SPEED_5G,\n+\t/* Do not add enumeration values for any speed greater than\n+\t * 5Gbps. For any speed greater than 5Gbps, its speed class\n+\t * code should follow the formula below.\n+\t *\n+\t * SPEED = (link_speed - 5000) / 1000 + ENETC_MSG_SPEED_5G\n+\t *\n+\t * The unit of link_speed should be Mbps, the max SPEED\n+\t * should \u003c= ENETC_MSG_SPEED_MAX.\n+\t */\n+\tENETC_MSG_SPEED_MAX = 0xff,\n };\n \n struct enetc_msg_swbd {\n@@ -158,9 +220,45 @@ struct enetc_msg_mac_exact_filter {\n \tstruct enetc_mac_addr mac[];\n };\n \n+/* message format of class_id 0x20 for hash MAC filter.\n+ * cmd_id 0x3: set MAC hash table\n+ */\n+struct enetc_msg_mac_hash_filter {\n+\tstruct enetc_msg_header hdr;\n+\t/* bit 0 ~ 5: ENETC_MSG_MAC_HASH_SIZE\n+\t * bit 6~7: ENETC_MSG_MAC_TYPE\n+\t */\n+\tu8 sz_type;\n+\tu8 resv[3];\n+\tu32 hash_tbl[];\n+};\n+\n+/* message format of class_id 0x20 for MAC promiscuous mode.\n+ * cmd_id 0x5: set MAC promiscuous mode\n+ */\n+struct enetc_msg_mac_promisc_mode {\n+\tstruct enetc_msg_header hdr;\n+\t/* bit 0: ENETC_MSG_MAC_FLUSH_MACS\n+\t * bit 1: ENETC_MSG_MAC_PROMISC_MODE\n+\t * bit 6~7: ENETC_MSG_MAC_TYPE\n+\t */\n+\tu8 config;\n+\tu8 resv[15];\n+};\n+\n /* The generic message format applies to the following messages:\n  * Get IP revision message, class_id 0xf0.\n  * cmd_id 1: get IP minor revision\n+ *\n+ * Link status message, class id 0x80.\n+ * cmd_id 0x0: get the current link status\n+ * cmd_id 0x1: register link status change notification\n+ * cmd_id 0x2: unregister link status change notification\n+ *\n+ * Link speed message, class_id 0x81.\n+ * cmd_id 0x0: get the current link speed.\n+ * cmd_id 0x1: register link speed change notification, not supported yet\n+ * cmd_id 0x2: unregister link speed change notification, not supported yet\n  */\n struct enetc_msg_generic {\n \tstruct enetc_msg_header hdr;\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c\nindex edc1277bb5860..55c23d4a73a86 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c\n@@ -7,24 +7,28 @@\n \t\t\t\t\t   ENETC_MSG_CLASS_ID_CMD_SUCCESS)\n #define ENETC_PF_MSG_NOTSUPP\tFIELD_PREP(ENETC_PF_MSG_CLASS_ID, \\\n \t\t\t\t\t   ENETC_MSG_CLASS_ID_CMD_NOT_SUPPORT)\n-\n-static void enetc_msg_disable_mr_int(struct enetc_pf *pf)\n+#define ENETC_PF_MSG_PERM_DENY\tFIELD_PREP(ENETC_PF_MSG_CLASS_ID, \\\n+\t\t\t\t\t   ENETC_MSG_CLASS_ID_PERMISSION_DENY)\n+#define ENETC_PF_MSG_INV_LEN\tFIELD_PREP(ENETC_PF_MSG_CLASS_ID, \\\n+\t\t\t\t\t   ENETC_MSG_CLASS_ID_INVALID_MSG_LEN)\n+#define ENETC_PF_MSG_MF(code)\t(FIELD_PREP(ENETC_PF_MSG_CLASS_ID, \\\n+\t\t\t\t\t    ENETC_MSG_CLASS_ID_MAC_FILTER) | \\\n+\t\t\t\t FIELD_PREP(ENETC_PF_MSG_CLASS_CODE, (code)))\n+\n+static void enetc_disable_psiier_interrupts(struct enetc_pf *pf)\n {\n \tstruct enetc_hw *hw = \u0026pf-\u003esi-\u003ehw;\n-\tu32 psiier;\n-\n-\tpsiier = enetc_rd(hw, ENETC_PSIIER) \u0026 ~ENETC_PSIMR_MASK(pf-\u003enum_vfs);\n \n-\t/* disable MR int source(s) */\n-\tenetc_wr(hw, ENETC_PSIIER, psiier);\n+\tenetc_wr(hw, ENETC_PSIIER, 0);\n }\n \n-static void enetc_msg_enable_mr_int(struct enetc_pf *pf)\n+static void enetc_enable_psiier_interrupts(struct enetc_pf *pf)\n {\n+\tu32 psiier = ENETC_PSIMR_MASK(pf-\u003enum_vfs);\n \tstruct enetc_hw *hw = \u0026pf-\u003esi-\u003ehw;\n-\tu32 psiier;\n \n-\tpsiier = enetc_rd(hw, ENETC_PSIIER) | ENETC_PSIMR_MASK(pf-\u003enum_vfs);\n+\tif (pf-\u003eops-\u003evf_flr_handler)\n+\t\tpsiier |= ENETC_VFFLR_MASK(pf-\u003enum_vfs);\n \n \tenetc_wr(hw, ENETC_PSIIER, psiier);\n }\n@@ -34,8 +38,8 @@ static irqreturn_t enetc_msg_psi_msix(int irq, void *data)\n \tstruct enetc_si *si = (struct enetc_si *)data;\n \tstruct enetc_pf *pf = enetc_si_priv(si);\n \n-\tenetc_msg_disable_mr_int(pf);\n-\tschedule_work(\u0026pf-\u003emsg_task);\n+\tenetc_disable_psiier_interrupts(pf);\n+\tschedule_work(\u0026si-\u003emsg_task);\n \n \treturn IRQ_HANDLED;\n }\n@@ -61,31 +65,186 @@ static u16 enetc_msg_set_vf_primary_mac_addr(struct enetc_pf *pf, int vf_id,\n \tstruct enetc_vf_state *vf_state = \u0026pf-\u003evf_state[vf_id];\n \tstruct enetc_msg_mac_exact_filter *msg = vf_msg;\n \tstruct device *dev = \u0026pf-\u003esi-\u003epdev-\u003edev;\n+\tu16 pf_msg = ENETC_PF_MSG_SUCCESS;\n \tchar *addr = msg-\u003emac[0].addr;\n \n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\n+\t/* Untrusted VFs cannot set their MAC addresses by the mailbox\n+\t * messages.\n+\t */\n+\tif (!(vf_state-\u003eflags \u0026 ENETC_VF_FLAG_TRUSTED)) {\n+\t\tpf_msg = ENETC_PF_MSG_PERM_DENY;\n+\t\tgoto vf_state_unlock;\n+\t}\n+\n \tif (!is_valid_ether_addr(addr)) {\n \t\tdev_err_ratelimited(dev, \"VF%d attempted to set invalid MAC\\n\",\n \t\t\t\t    vf_id);\n-\t\treturn (FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n-\t\t\t\t   ENETC_MSG_CLASS_ID_MAC_FILTER) |\n-\t\t\tFIELD_PREP(ENETC_PF_MSG_CLASS_CODE,\n-\t\t\t\t   ENETC_MF_CLASS_CODE_INVALID_MAC));\n+\t\tpf_msg = ENETC_PF_MSG_MF(ENETC_MF_CLASS_CODE_INVALID_MAC);\n+\t\tgoto vf_state_unlock;\n \t}\n \n-\tmutex_lock(\u0026vf_state-\u003elock);\n+\t/* PF has higher privileges. If PF has already modified the MAC\n+\t * address for VF through .ndo_set_vf_mac() interface, VF is not\n+\t * allowed to set its MAC address via mailbox messages, even if\n+\t * it is trusted.\n+\t */\n \tif (vf_state-\u003eflags \u0026 ENETC_VF_FLAG_PF_SET_MAC) {\n-\t\tmutex_unlock(\u0026vf_state-\u003elock);\n \t\tdev_err_ratelimited(dev,\n \t\t\t\t    \"VF%d attempted to override PF set MAC\\n\",\n \t\t\t\t    vf_id);\n-\t\treturn FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n-\t\t\t\t  ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);\n+\t\tpf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n+\t\t\t\t    ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);\n+\t\tgoto vf_state_unlock;\n \t}\n \n \tenetc_set_si_hw_addr(pf, vf_id + 1, addr);\n+\n+vf_state_unlock:\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n+\treturn pf_msg;\n+}\n+\n+static u16 enetc_msg_set_vf_mac_hash_filter(struct enetc_pf *pf, int vf_id,\n+\t\t\t\t\t    void *vf_msg)\n+{\n+\tstruct enetc_vf_state *vf_state = \u0026pf-\u003evf_state[vf_id];\n+\tstruct enetc_msg_mac_hash_filter *msg = vf_msg;\n+\tu16 pf_msg = ENETC_PF_MSG_SUCCESS;\n+\tstruct enetc_si *si = pf-\u003esi;\n+\tint si_id = vf_id + 1;\n+\tu64 uc_hash, mc_hash;\n+\tbool trusted;\n+\tint type;\n+\n+\t/* Currently, hardware only supports 64 bits table size */\n+\tif (FIELD_GET(ENETC_MSG_MAC_HASH_SIZE, msg-\u003esz_type) !=\n+\t    ENETC_MAC_HASH_TABLE_SIZE_64)\n+\t\treturn ENETC_PF_MSG_NOTSUPP;\n+\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\n+\t/* For an untrusted VF, unicast MAC hash filtering is not permitted.\n+\t * For multicast, the MAC hash filter is strictly limited to a maximum\n+\t * of 8 bits to satisfy its basic multicast communication requirements\n+\t * while preventing potential network abuse.\n+\t */\n+\ttrusted = !!(vf_state-\u003eflags \u0026 ENETC_VF_FLAG_TRUSTED);\n+\ttype = FIELD_GET(ENETC_MSG_MAC_TYPE, msg-\u003esz_type);\n+\tswitch (type) {\n+\tcase ENETC_MAC_FILTER_TYPE_UC:\n+\t\tif (!trusted) {\n+\t\t\tpf_msg = ENETC_PF_MSG_PERM_DENY;\n+\t\t\tgoto vf_state_unlock;\n+\t\t}\n+\n+\t\tuc_hash = (u64)msg-\u003ehash_tbl[1] \u003c\u003c 32 | msg-\u003ehash_tbl[0];\n+\t\tenetc_set_si_uc_hash_filter(si, si_id, uc_hash);\n+\t\tbreak;\n+\tcase ENETC_MAC_FILTER_TYPE_MC:\n+\t\tmc_hash = (u64)msg-\u003ehash_tbl[1] \u003c\u003c 32 | msg-\u003ehash_tbl[0];\n+\t\tif (!trusted \u0026\u0026\n+\t\t    hweight64(mc_hash) \u003e ENETC_VF_MC_HASH_BITS_MAX) {\n+\t\t\tpf_msg = ENETC_PF_MSG_PERM_DENY;\n+\t\t\tgoto vf_state_unlock;\n+\t\t}\n+\n+\t\tenetc_set_si_mc_hash_filter(si, si_id, mc_hash);\n+\t\tbreak;\n+\tcase ENETC_MAC_FILTER_TYPE_ALL:\n+\t\tif (!msg-\u003ehdr.len) {\n+\t\t\tpf_msg = ENETC_PF_MSG_INV_LEN;\n+\t\t\tgoto vf_state_unlock;\n+\t\t}\n+\n+\t\tuc_hash = (u64)msg-\u003ehash_tbl[1] \u003c\u003c 32 | msg-\u003ehash_tbl[0];\n+\t\tmc_hash = (u64)msg-\u003ehash_tbl[3] \u003c\u003c 32 | msg-\u003ehash_tbl[2];\n+\n+\t\tif (!trusted \u0026\u0026\n+\t\t    (hweight64(mc_hash) \u003c= ENETC_VF_MC_HASH_BITS_MAX)) {\n+\t\t\tenetc_set_si_mc_hash_filter(si, si_id, mc_hash);\n+\t\t\tpf_msg = ENETC_PF_MSG_MF(ENETC_MF_CLASS_CODE_UCF_DENY);\n+\t\t\tgoto vf_state_unlock;\n+\t\t}\n+\n+\t\tif (!trusted) {\n+\t\t\tpf_msg = ENETC_PF_MSG_PERM_DENY;\n+\t\t\tgoto vf_state_unlock;\n+\t\t}\n+\n+\t\tenetc_set_si_uc_hash_filter(si, si_id, uc_hash);\n+\t\tenetc_set_si_mc_hash_filter(si, si_id, mc_hash);\n+\t\tbreak;\n+\tdefault:\n+\t\tpf_msg = ENETC_PF_MSG_MF(ENETC_MF_CLASS_CODE_INVALID_TYPE);\n+\t}\n+\n+vf_state_unlock:\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n+\treturn pf_msg;\n+}\n+\n+static u16 enetc_msg_set_vf_mac_promisc_mode(struct enetc_pf *pf, int vf_id,\n+\t\t\t\t\t     void *vf_msg)\n+{\n+\tstruct enetc_vf_state *vf_state = \u0026pf-\u003evf_state[vf_id];\n+\tstruct enetc_msg_mac_promisc_mode *msg = vf_msg;\n+\tu16 pf_msg = ENETC_PF_MSG_SUCCESS;\n+\tstruct enetc_si *si = pf-\u003esi;\n+\tbool promisc, flush_macs;\n+\tint si_id = vf_id + 1;\n+\tint type;\n+\n+\tflush_macs = !!(msg-\u003econfig \u0026 ENETC_MSG_MAC_FLUSH_MACS);\n+\ttype = FIELD_GET(ENETC_MSG_MAC_TYPE, msg-\u003econfig);\n+\tif (!type)\n+\t\treturn ENETC_PF_MSG_MF(ENETC_MF_CLASS_CODE_INVALID_TYPE);\n+\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\n+\tpromisc = !!(msg-\u003econfig \u0026 ENETC_MSG_MAC_PROMISC_MODE);\n+\tif (promisc \u0026\u0026 !(vf_state-\u003eflags \u0026 ENETC_VF_FLAG_TRUSTED)) {\n+\t\tpf_msg = ENETC_PF_MSG_PERM_DENY;\n+\t\tgoto vf_state_unlock;\n+\t}\n+\n+\tif (type \u0026 ENETC_MAC_FILTER_TYPE_UC) {\n+\t\tif (promisc)\n+\t\t\tvf_state-\u003eflags |= ENETC_VF_FLAG_UC_PROMISC;\n+\t\telse\n+\t\t\tvf_state-\u003eflags \u0026= ~ENETC_VF_FLAG_UC_PROMISC;\n+\t}\n+\n+\tif (type \u0026 ENETC_MAC_FILTER_TYPE_MC) {\n+\t\tif (promisc)\n+\t\t\tvf_state-\u003eflags |= ENETC_VF_FLAG_MC_PROMISC;\n+\t\telse\n+\t\t\tvf_state-\u003eflags \u0026= ~ENETC_VF_FLAG_MC_PROMISC;\n+\t}\n+\n+\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\n+\tif (type \u0026 ENETC_MAC_FILTER_TYPE_UC)\n+\t\tenetc_set_si_uc_promisc(si, si_id, promisc);\n+\n+\tif (type \u0026 ENETC_MAC_FILTER_TYPE_MC)\n+\t\tenetc_set_si_mc_promisc(si, si_id, promisc);\n+\n+\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+\n+\tif ((type \u0026 ENETC_MAC_FILTER_TYPE_UC) \u0026\u0026 flush_macs)\n+\t\tenetc_set_si_uc_hash_filter(si, si_id, 0);\n+\n+\tif ((type \u0026 ENETC_MAC_FILTER_TYPE_MC) \u0026\u0026 flush_macs)\n+\t\tenetc_set_si_mc_hash_filter(si, si_id, 0);\n+\n+vf_state_unlock:\n \tmutex_unlock(\u0026vf_state-\u003elock);\n \n-\treturn ENETC_PF_MSG_SUCCESS;\n+\treturn pf_msg;\n }\n \n static u16 enetc_msg_handle_mac_filter(struct enetc_pf *pf, int vf_id,\n@@ -96,6 +255,10 @@ static u16 enetc_msg_handle_mac_filter(struct enetc_pf *pf, int vf_id,\n \tswitch (msg_hdr-\u003ecmd_id) {\n \tcase ENETC_MSG_SET_PRIMARY_MAC:\n \t\treturn enetc_msg_set_vf_primary_mac_addr(pf, vf_id, vf_msg);\n+\tcase ENETC_MSG_SET_MAC_HASH_TABLE:\n+\t\treturn enetc_msg_set_vf_mac_hash_filter(pf, vf_id, vf_msg);\n+\tcase ENETC_MSG_SET_MAC_PROMISC_MODE:\n+\t\treturn enetc_msg_set_vf_mac_promisc_mode(pf, vf_id, vf_msg);\n \tdefault:\n \t\treturn ENETC_PF_MSG_NOTSUPP;\n \t}\n@@ -116,6 +279,241 @@ static u16 enetc_msg_handle_ip_revision(struct enetc_pf *pf, void *vf_msg)\n \t}\n }\n \n+static void enetc_pf_reply_msg(struct enetc_hw *hw, int vf_id, u16 pf_msg)\n+{\n+\t/* w1c to clear the corresponding VF MR bit */\n+\tenetc_wr(hw, ENETC_PSIIDR, ENETC_PSIMR_BIT(vf_id));\n+\tenetc_wr(hw, ENETC_PSIMSGRR, ENETC_SIMSGSR_SET_MC(pf_msg) |\n+\t\t ENETC_PSIMR_BIT(vf_id));\n+}\n+\n+static u16 enetc_build_link_status_msg(struct enetc_ndev_priv *priv,\n+\t\t\t\t       bool link_up)\n+{\n+\tu8 status = 0;\n+\n+\tif (link_up) {\n+\t\tspin_lock(\u0026priv-\u003esi-\u003egen_lock);\n+\t\tif (test_bit(ENETC_RXBDR_CM, \u0026priv-\u003eflags))\n+\t\t\tstatus |= ENETC_CLASS_CODE_TX_PAUSE_EN;\n+\t\tspin_unlock(\u0026priv-\u003esi-\u003egen_lock);\n+\t} else {\n+\t\tstatus |= ENETC_CLASS_CODE_LINK_DOWN;\n+\t}\n+\n+\treturn FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n+\t\t\t  ENETC_MSG_CLASS_ID_LINK_STATUS) |\n+\t       FIELD_PREP(ENETC_PF_MSG_CLASS_CODE_U8, status);\n+}\n+\n+static void enetc_msg_get_link_status(struct enetc_pf *pf, int vf_id)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(pf-\u003esi-\u003endev);\n+\tu16 pf_msg;\n+\n+\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\tpf_msg = enetc_build_link_status_msg(priv, pf-\u003elink_up);\n+\tenetc_pf_reply_msg(\u0026pf-\u003esi-\u003ehw, vf_id, pf_msg);\n+\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+}\n+\n+static int enetc_pf_send_msg(struct enetc_pf *pf, u32 msg_code, u16 ms_mask)\n+{\n+\tstruct enetc_hw *hw = \u0026pf-\u003esi-\u003ehw;\n+\tu16 old_ms_mask = ms_mask;\n+\tu16 ms_status;\n+\tu32 val;\n+\n+\t/* The MS bit is set, indicating that the corresponding VF has not\n+\t * read the last message, PF cannot send new message to the VF. To\n+\t * avoid sending messages to such a VF, the bit corresponding to VF\n+\t * is cleared from ms_mask. Because the MS bit can only be written\n+\t * as 1, writing a 0 has no effect. Writing a 1 when the bit is\n+\t * already set is undefined.\n+\t */\n+\tms_status = enetc_rd(hw, ENETC_PSIMSGSR) \u0026 0xffff;\n+\tms_mask \u0026= ~ms_status;\n+\tif (!ms_mask)\n+\t\treturn -EIO;\n+\n+\tif (ms_mask != old_ms_mask)\n+\t\tdev_warn_ratelimited(\u0026pf-\u003esi-\u003epdev-\u003edev,\n+\t\t\t\t     \"PF cannot send message to VF(s) 0x%x\\n\",\n+\t\t\t\t     ms_mask ^ old_ms_mask);\n+\n+\tenetc_wr(hw, ENETC_PSIMSGSR,\n+\t\t FIELD_PREP(PSIMSGSR_MC, msg_code) | ms_mask);\n+\n+\treturn read_poll_timeout(enetc_rd, val, !(val \u0026 ms_mask), 1000,\n+\t\t\t\t 200000, false, hw, ENETC_PSIMSGSR);\n+}\n+\n+static void enetc_msg_notify_vf_link_status(struct enetc_pf *pf, u16 ms_mask)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(pf-\u003esi-\u003endev);\n+\tu16 pf_msg;\n+\n+\tpf_msg = enetc_build_link_status_msg(priv, pf-\u003elink_up);\n+\tif (enetc_pf_send_msg(pf, pf_msg, ms_mask))\n+\t\tdev_err_ratelimited(\u0026pf-\u003esi-\u003epdev-\u003edev,\n+\t\t\t\t    \"PF notifies link status failed\\n\");\n+}\n+\n+static void enetc_msg_register_link_status_notifier(struct enetc_pf *pf,\n+\t\t\t\t\t\t    int vf_id)\n+{\n+\tu16 pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n+\t\t\t\tENETC_MSG_CLASS_ID_CMD_SUCCESS);\n+\n+\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\n+\tenetc_pf_reply_msg(\u0026pf-\u003esi-\u003ehw, vf_id, pf_msg);\n+\n+\t/* SR-IOV is being disabled if pf-\u003esriov_enabled is false, so no\n+\t * need to set link_status_ms_mask and notify the link status.\n+\t */\n+\tif (!pf-\u003esriov_enabled)\n+\t\tgoto msg_unlock;\n+\n+\tpf-\u003elink_status_ms_mask |= PSIMSGSR_MS(vf_id);\n+\n+\t/* Notify VF the current link status */\n+\tenetc_msg_notify_vf_link_status(pf, PSIMSGSR_MS(vf_id));\n+\n+msg_unlock:\n+\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+}\n+\n+static void enetc_msg_unregister_link_status_notifier(struct enetc_pf *pf,\n+\t\t\t\t\t\t      int vf_id)\n+{\n+\tu16 pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n+\t\t\t\tENETC_MSG_CLASS_ID_CMD_SUCCESS);\n+\n+\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\n+\tpf-\u003elink_status_ms_mask \u0026= ~PSIMSGSR_MS(vf_id);\n+\tenetc_pf_reply_msg(\u0026pf-\u003esi-\u003ehw, vf_id, pf_msg);\n+\n+\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+}\n+\n+static u16 enetc_msg_handle_link_status(struct enetc_pf *pf, int vf_id,\n+\t\t\t\t\tvoid *vf_msg)\n+{\n+\tstruct enetc_msg_header *msg_hdr = vf_msg;\n+\n+\tswitch (msg_hdr-\u003ecmd_id) {\n+\tcase ENETC_MSG_GET_CURRENT_LINK_STATUS:\n+\t\t/* Currently, this message is intended only for\n+\t\t * DPDK-owned VFs.\n+\t\t */\n+\t\tenetc_msg_get_link_status(pf, vf_id);\n+\t\tbreak;\n+\tcase ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER:\n+\t\tenetc_msg_register_link_status_notifier(pf, vf_id);\n+\t\tbreak;\n+\tcase ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER:\n+\t\tenetc_msg_unregister_link_status_notifier(pf, vf_id);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn ENETC_PF_MSG_NOTSUPP;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static u16 enetc_build_link_speed_msg(int speed, int duplex)\n+{\n+\tu32 speed_code = ENETC_MSG_SPEED_UNKNOWN;\n+\n+\tswitch (speed) {\n+\tcase SPEED_10:\n+\t\tif (duplex == DUPLEX_HALF)\n+\t\t\tspeed_code = ENETC_MSG_SPEED_10M_HD;\n+\t\telse if (duplex == DUPLEX_FULL)\n+\t\t\tspeed_code = ENETC_MSG_SPEED_10M_FD;\n+\t\tbreak;\n+\tcase SPEED_100:\n+\t\tif (duplex == DUPLEX_HALF)\n+\t\t\tspeed_code = ENETC_MSG_SPEED_100M_HD;\n+\t\telse if (duplex == DUPLEX_FULL)\n+\t\t\tspeed_code = ENETC_MSG_SPEED_100M_FD;\n+\t\tbreak;\n+\tcase SPEED_1000:\n+\t\tspeed_code = ENETC_MSG_SPEED_1000M;\n+\t\tbreak;\n+\tcase SPEED_2500:\n+\t\tspeed_code = ENETC_MSG_SPEED_2500M;\n+\t\tbreak;\n+\tcase SPEED_5000:\n+\t\tspeed_code = ENETC_MSG_SPEED_5G;\n+\t\tbreak;\n+\tdefault:\n+\t\tif (speed \u003c SPEED_5000)\n+\t\t\tbreak;\n+\n+\t\tspeed_code = (speed - SPEED_5000) / SPEED_1000 +\n+\t\t\t     ENETC_MSG_SPEED_5G;\n+\t\tif (speed_code \u003e ENETC_MSG_SPEED_MAX)\n+\t\t\tspeed_code = ENETC_MSG_SPEED_UNKNOWN;\n+\t}\n+\n+\treturn FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n+\t\t\t  ENETC_MSG_CLASS_ID_LINK_SPEED) |\n+\t       FIELD_PREP(ENETC_PF_MSG_CLASS_CODE_U8, speed_code);\n+}\n+\n+static u16 enetc_msg_get_link_speed(struct enetc_pf *pf, int vf_id)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(pf-\u003esi-\u003endev);\n+\tstruct enetc_vf_state *vf_state = \u0026pf-\u003evf_state[vf_id];\n+\tstruct ethtool_link_ksettings link_info = {};\n+\n+\t/* A malicious or malfunctioning VM could potentially spam these\n+\t * messages in a tight loop causing global rtnl_lock contention,\n+\t * which may severely starve other processes on the host that\n+\t * require rtnl_lock for routine network configuration, resulting\n+\t * in a system-wide control-plane denial of service. Therefore,\n+\t * we expect the VF query for link speed to be trusted. There's no\n+\t * need to consider the transition from trusted to untrusted here,\n+\t * as this won't cause rtnl_lock() to be called frequently.\n+\t */\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\tif (!(vf_state-\u003eflags \u0026 ENETC_VF_FLAG_TRUSTED)) {\n+\t\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n+\t\treturn ENETC_PF_MSG_PERM_DENY;\n+\t}\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n+\trtnl_lock();\n+\tphylink_ethtool_ksettings_get(priv-\u003ephylink, \u0026link_info);\n+\trtnl_unlock();\n+\n+\treturn enetc_build_link_speed_msg(link_info.base.speed,\n+\t\t\t\t\t  link_info.base.duplex);\n+}\n+\n+static u16 enetc_msg_handle_link_speed(struct enetc_pf *pf, int vf_id,\n+\t\t\t\t       void *vf_msg)\n+{\n+\tstruct enetc_msg_header *msg_hdr = vf_msg;\n+\n+\tswitch (msg_hdr-\u003ecmd_id) {\n+\tcase ENETC_MSG_GET_CURRENT_LINK_SPEED:\n+\t\treturn enetc_msg_get_link_speed(pf, vf_id);\n+\tcase ENETC_MSG_REGISTER_SPEED_CHANGE_NOTIFIER:\n+\tcase ENETC_MSG_UNREGISTER_SPEED_CHANGE_NOTIFIER:\n+\tdefault:\n+\t\treturn ENETC_PF_MSG_NOTSUPP;\n+\t}\n+}\n+\n+/* If *pf_msg is set to 0, it means that PF has responded to VF in\n+ * enetc_msg_handle_rxmsg() through enetc_pf_reply_msg(), which also\n+ * clears the corresponding VF MR bit in PSIIDR.\n+ */\n static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,\n \t\t\t\t   u16 *pf_msg)\n {\n@@ -128,8 +526,7 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,\n \tif (msg_size \u003e ENETC_DEFAULT_MSG_SIZE) {\n \t\tdev_err_ratelimited(dev,\n \t\t\t\t    \"Invalid message size: %u\\n\", msg_size);\n-\t\t*pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n-\t\t\t\t     ENETC_MSG_CLASS_ID_INVALID_MSG_LEN);\n+\t\t*pf_msg = ENETC_PF_MSG_INV_LEN;\n \t\treturn;\n \t}\n \n@@ -147,6 +544,14 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,\n \t}\n \n \tmemcpy(msg, msg_swbd-\u003evaddr, msg_size);\n+\tmsg_hdr = (struct enetc_msg_header *)msg;\n+\n+\t/* Check message length whether is changed */\n+\tif (ENETC_MSG_SIZE(msg_hdr-\u003elen) != msg_size) {\n+\t\t*pf_msg = ENETC_PF_MSG_INV_LEN;\n+\t\tgoto free_msg;\n+\t}\n+\n \tif (!enetc_msg_check_crc16(msg, msg_size)) {\n \t\tdev_err_ratelimited(dev, \"VSI to PSI Message CRC16 error\\n\");\n \t\t*pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,\n@@ -157,7 +562,6 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,\n \n \t/* Default to not supported */\n \t*pf_msg = ENETC_PF_MSG_NOTSUPP;\n-\tmsg_hdr = (struct enetc_msg_header *)msg;\n \n \t/* Currently, asynchronous actions are not supported */\n \tif (FIELD_GET(ENETC_VF_MSG_COOKIE, msg_hdr-\u003ecookie)) {\n@@ -191,6 +595,12 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,\n \tcase ENETC_MSG_CLASS_ID_IP_REVISION:\n \t\t*pf_msg = enetc_msg_handle_ip_revision(pf, msg);\n \t\tbreak;\n+\tcase ENETC_MSG_CLASS_ID_LINK_STATUS:\n+\t\t*pf_msg = enetc_msg_handle_link_status(pf, vf_id, msg);\n+\t\tbreak;\n+\tcase ENETC_MSG_CLASS_ID_LINK_SPEED:\n+\t\t*pf_msg = enetc_msg_handle_link_speed(pf, vf_id, msg);\n+\t\tbreak;\n \tdefault:\n \t\tdev_err_ratelimited(dev,\n \t\t\t\t    \"Unsupported message class ID: 0x%x\\n\",\n@@ -201,21 +611,46 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,\n \tkfree(msg);\n }\n \n-static void enetc_msg_task(struct work_struct *work)\n+static void enetc_vf_flr_handler(struct enetc_pf *pf)\n {\n-\tstruct enetc_pf *pf = container_of(work, struct enetc_pf, msg_task);\n-\tu32 mr_mask = ENETC_PSIMR_MASK(pf-\u003enum_vfs);\n+\tu32 flr_mask = ENETC_VFFLR_MASK(pf-\u003enum_vfs);\n \tstruct enetc_hw *hw = \u0026pf-\u003esi-\u003ehw;\n-\tu32 mr_status;\n+\tu32 flr_status;\n+\n+\tif (!pf-\u003eops-\u003evf_flr_handler)\n+\t\treturn;\n+\n+\tflr_status = enetc_rd(hw, ENETC_PSIIDR) \u0026 flr_mask;\n+\tif (!flr_status)\n+\t\treturn;\n+\n+\tfor (int i = 0; i \u003c pf-\u003enum_vfs; i++) {\n+\t\tif (!(ENETC_VFFLR_BIT(i) \u0026 flr_status))\n+\t\t\tcontinue;\n+\n+\t\t/* Clear FLR interrupt status, W1C */\n+\t\tenetc_wr(hw, ENETC_PSIIDR, ENETC_VFFLR_BIT(i));\n+\t\tpf-\u003eops-\u003evf_flr_handler(pf, i);\n+\t}\n+}\n+\n+static void enetc_msg_task(struct work_struct *work)\n+{\n+\tstruct enetc_si *si = container_of(work, struct enetc_si, msg_task);\n+\tstruct enetc_pf *pf = enetc_si_priv(si);\n+\tstruct enetc_hw *hw = \u0026si-\u003ehw;\n+\tu32 mr_status, mr_mask;\n \tint i;\n \n+\tenetc_vf_flr_handler(pf);\n+\n+\tmr_mask = ENETC_PSIMR_MASK(pf-\u003enum_vfs);\n \tmr_status = (enetc_rd(hw, ENETC_PSIMSGRR) \u0026 mr_mask) |\n \t\t    (enetc_rd(hw, ENETC_PSIIDR) \u0026 mr_mask);\n \tif (!mr_status)\n \t\tgoto out;\n \n \tfor (i = 0; i \u003c pf-\u003enum_vfs; i++) {\n-\t\tu32 psimsgrr;\n \t\tu16 msg_code;\n \n \t\tif (!(ENETC_PSIMR_BIT(i) \u0026 mr_status))\n@@ -223,16 +658,18 @@ static void enetc_msg_task(struct work_struct *work)\n \n \t\tenetc_msg_handle_rxmsg(pf, i, \u0026msg_code);\n \n-\t\t/* w1c to clear the corresponding VF MR bit */\n-\t\tenetc_wr(hw, ENETC_PSIIDR, ENETC_PSIMR_BIT(i));\n+\t\t/* If msg_code is 0, it means that PF has responded to VF\n+\t\t * in enetc_msg_handle_rxmsg() through enetc_pf_reply_msg(),\n+\t\t * which also clears the corresponding VF MR bit in PSIIDR.\n+\t\t */\n+\t\tif (!msg_code)\n+\t\t\tcontinue;\n \n-\t\tpsimsgrr = ENETC_SIMSGSR_SET_MC(msg_code);\n-\t\tpsimsgrr |= ENETC_PSIMR_BIT(i); /* w1c */\n-\t\tenetc_wr(hw, ENETC_PSIMSGRR, psimsgrr);\n+\t\tenetc_pf_reply_msg(hw, i, msg_code);\n \t}\n \n out:\n-\tenetc_msg_enable_mr_int(pf);\n+\tenetc_enable_psiier_interrupts(pf);\n }\n \n /* Init */\n@@ -291,13 +728,13 @@ static int enetc_msg_psi_init(struct enetc_pf *pf)\n \t}\n \n \t/* initialize PSI mailbox */\n-\tINIT_WORK(\u0026pf-\u003emsg_task, enetc_msg_task);\n+\tINIT_WORK(\u0026si-\u003emsg_task, enetc_msg_task);\n \n \t/* register message passing interrupt handler */\n-\tsnprintf(pf-\u003emsg_int_name, sizeof(pf-\u003emsg_int_name), \"%s-vfmsg\",\n+\tsnprintf(si-\u003emsg_int_name, sizeof(si-\u003emsg_int_name), \"%s-vfmsg\",\n \t\t si-\u003endev-\u003ename);\n \tvector = pci_irq_vector(si-\u003epdev, ENETC_SI_INT_IDX);\n-\terr = request_irq(vector, enetc_msg_psi_msix, 0, pf-\u003emsg_int_name, si);\n+\terr = request_irq(vector, enetc_msg_psi_msix, 0, si-\u003emsg_int_name, si);\n \tif (err) {\n \t\tdev_err(\u0026si-\u003epdev-\u003edev,\n \t\t\t\"PSI messaging: request_irq() failed!\\n\");\n@@ -307,8 +744,8 @@ static int enetc_msg_psi_init(struct enetc_pf *pf)\n \t/* set one IRQ entry for PSI message receive notification (SI int) */\n \tenetc_wr(\u0026si-\u003ehw, ENETC_SIMSIVR, ENETC_SI_INT_IDX);\n \n-\t/* enable MR interrupts */\n-\tenetc_msg_enable_mr_int(pf);\n+\t/* enable PSIIER interrupts */\n+\tenetc_enable_psiier_interrupts(pf);\n \n \treturn 0;\n \n@@ -319,24 +756,59 @@ static int enetc_msg_psi_init(struct enetc_pf *pf)\n \treturn err;\n }\n \n+static void enetc_msg_clear_vf_config(struct enetc_pf *pf, int vf_id)\n+{\n+\tstruct enetc_vf_state *vf_state = \u0026pf-\u003evf_state[vf_id];\n+\tstruct enetc_si *si = pf-\u003esi;\n+\tint si_id = vf_id + 1;\n+\n+\t/* For ENETC v1, we only support setting the VF's MAC address via\n+\t * VSI-to-PSI messages, so there is no configuration to clear.\n+\t */\n+\tif (is_enetc_rev1(si))\n+\t\treturn;\n+\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\n+\t/* VF may set these flags by mailbox messages, so need to clear these\n+\t * flags when enetc_msg_psi_free() is called. PF-set flags (TRUSTED,\n+\t * PF_SET_MAC) are not cleared, because these flags are unrelated to\n+\t * whether SR-IOV is enabled or disabled.\n+\t */\n+\tvf_state-\u003eflags \u0026= ~(ENETC_VF_FLAG_UC_PROMISC |\n+\t\t\t     ENETC_VF_FLAG_MC_PROMISC);\n+\n+\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\tenetc_set_si_uc_promisc(si, si_id, false);\n+\tenetc_set_si_mc_promisc(si, si_id, false);\n+\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+\n+\tenetc_set_si_uc_hash_filter(si, si_id, 0);\n+\tenetc_set_si_mc_hash_filter(si, si_id, 0);\n+\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+}\n+\n static void enetc_msg_psi_free(struct enetc_pf *pf)\n {\n \tstruct enetc_si *si = pf-\u003esi;\n \tint i;\n \n-\t/* disable MR interrupts */\n-\tenetc_msg_disable_mr_int(pf);\n+\t/* disable PSIIER interrupts */\n+\tenetc_disable_psiier_interrupts(pf);\n \n \t/* de-register message passing interrupt handler */\n \tfree_irq(pci_irq_vector(si-\u003epdev, ENETC_SI_INT_IDX), si);\n \n-\tcancel_work_sync(\u0026pf-\u003emsg_task);\n+\tcancel_work_sync(\u0026si-\u003emsg_task);\n \n-\t/* MR interrupts may be re-enabled by workqueue */\n-\tenetc_msg_disable_mr_int(pf);\n+\t/* PSIIER interrupts may be re-enabled by workqueue */\n+\tenetc_disable_psiier_interrupts(pf);\n \n-\tfor (i = 0; i \u003c pf-\u003enum_vfs; i++)\n+\tfor (i = 0; i \u003c pf-\u003enum_vfs; i++) {\n \t\tenetc_msg_free_mbx(si, i);\n+\t\tenetc_msg_clear_vf_config(pf, i);\n+\t}\n }\n \n int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)\n@@ -346,6 +818,11 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)\n \tint err;\n \n \tif (!num_vfs) {\n+\t\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\t\tpf-\u003esriov_enabled = false;\n+\t\tpf-\u003elink_status_ms_mask = 0;\n+\t\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+\n \t\tpci_disable_sriov(pdev);\n \t\tenetc_msg_psi_free(pf);\n \t\tpf-\u003enum_vfs = 0;\n@@ -358,16 +835,31 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)\n \t\t\tgoto err_msg_psi;\n \t\t}\n \n+\t\t/* As PCI SR-IOV is not enabled at the moment, there is no\n+\t\t * concurrent access to sriov_enabled. So no need to use\n+\t\t * msg_lock to protect sriov_enabled.\n+\t\t */\n+\t\tpf-\u003esriov_enabled = true;\n \t\terr = pci_enable_sriov(pdev, num_vfs);\n \t\tif (err) {\n \t\t\tdev_err(\u0026pdev-\u003edev, \"pci_enable_sriov err %d\\n\", err);\n \t\t\tgoto err_en_sriov;\n \t\t}\n+\n \t}\n \n \treturn num_vfs;\n \n err_en_sriov:\n+\t/* If pci_enable_sriov() fails after partially creating VFs, a VF\n+\t * driver that successfully bound to one of the created VFs could\n+\t * have sent a registration message, setting its bit in\n+\t * link_status_ms_mask.\n+\t */\n+\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\tpf-\u003esriov_enabled = false;\n+\tpf-\u003elink_status_ms_mask = 0;\n+\tmutex_unlock(\u0026pf-\u003emsg_lock);\n \tenetc_msg_psi_free(pf);\n err_msg_psi:\n \tpf-\u003enum_vfs = 0;\n@@ -375,3 +867,34 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)\n \treturn err;\n }\n EXPORT_SYMBOL_GPL(enetc_sriov_configure);\n+\n+static void enetc_pf_notify_vf_link_status(struct enetc_pf *pf,\n+\t\t\t\t\t   bool link_up)\n+{\n+\t/* pf-\u003emsg_lock is initialized when pf-\u003etotal_vfs is not 0 */\n+\tif (!pf-\u003etotal_vfs)\n+\t\treturn;\n+\n+\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\n+\tpf-\u003elink_up = link_up;\n+\tif (!pf-\u003elink_status_ms_mask)\n+\t\tgoto msg_unlock;\n+\n+\tenetc_msg_notify_vf_link_status(pf, pf-\u003elink_status_ms_mask);\n+\n+msg_unlock:\n+\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+}\n+\n+void enetc_pf_notify_vf_link_up(struct enetc_pf *pf)\n+{\n+\tenetc_pf_notify_vf_link_status(pf, true);\n+}\n+EXPORT_SYMBOL_GPL(enetc_pf_notify_vf_link_up);\n+\n+void enetc_pf_notify_vf_link_down(struct enetc_pf *pf)\n+{\n+\tenetc_pf_notify_vf_link_status(pf, false);\n+}\n+EXPORT_SYMBOL_GPL(enetc_pf_notify_vf_link_down);\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c\nindex 55c07c528f223..d77a07cece28b 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c\n@@ -60,10 +60,9 @@ static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,\n \tfilter-\u003emac_addr_cnt++;\n }\n \n-static void enetc_sync_mac_filters(struct enetc_pf *pf)\n+static void enetc_sync_mac_filters(struct enetc_si *si)\n {\n-\tstruct enetc_mac_filter *f = pf-\u003emac_filter;\n-\tstruct enetc_si *si = pf-\u003esi;\n+\tstruct enetc_mac_filter *f = si-\u003emac_filter;\n \tint i, pos;\n \n \tpos = EMETC_MAC_ADDR_FILT_RES;\n@@ -115,9 +114,9 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)\n static void enetc_pf_set_rx_mode(struct net_device *ndev)\n {\n \tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n-\tstruct enetc_pf *pf = enetc_si_priv(priv-\u003esi);\n \tbool uprom = false, mprom = false;\n \tstruct enetc_mac_filter *filter;\n+\tstruct enetc_si *si = priv-\u003esi;\n \tstruct netdev_hw_addr *ha;\n \tbool em;\n \n@@ -133,7 +132,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)\n \t/* first 2 filter entries belong to PF */\n \tif (!uprom) {\n \t\t/* Update unicast filters */\n-\t\tfilter = \u0026pf-\u003emac_filter[UC];\n+\t\tfilter = \u0026si-\u003emac_filter[UC];\n \t\tenetc_reset_mac_addr_filter(filter);\n \n \t\tem = (netdev_uc_count(ndev) == 1);\n@@ -149,7 +148,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)\n \n \tif (!mprom) {\n \t\t/* Update multicast filters */\n-\t\tfilter = \u0026pf-\u003emac_filter[MC];\n+\t\tfilter = \u0026si-\u003emac_filter[MC];\n \t\tenetc_reset_mac_addr_filter(filter);\n \n \t\tnetdev_for_each_mc_addr(ha, ndev) {\n@@ -162,10 +161,10 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)\n \n \tif (!uprom || !mprom)\n \t\t/* update PF entries */\n-\t\tenetc_sync_mac_filters(pf);\n+\t\tenetc_sync_mac_filters(si);\n \n-\tenetc_set_si_uc_promisc(priv-\u003esi, 0, uprom);\n-\tenetc_set_si_mc_promisc(priv-\u003esi, 0, mprom);\n+\tenetc_set_si_uc_promisc(si, 0, uprom);\n+\tenetc_set_si_mc_promisc(si, 0, mprom);\n }\n \n static void enetc_set_loopback(struct net_device *ndev, bool en)\n@@ -191,33 +190,12 @@ static void enetc_set_loopback(struct net_device *ndev, bool en)\n \t}\n }\n \n-static int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)\n-{\n-\tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n-\tstruct enetc_pf *pf = enetc_si_priv(priv-\u003esi);\n-\tstruct enetc_vf_state *vf_state;\n-\n-\tif (vf \u003e= pf-\u003etotal_vfs)\n-\t\treturn -EINVAL;\n-\n-\tif (!is_valid_ether_addr(mac))\n-\t\treturn -EADDRNOTAVAIL;\n-\n-\tvf_state = \u0026pf-\u003evf_state[vf];\n-\n-\tmutex_lock(\u0026vf_state-\u003elock);\n-\tvf_state-\u003eflags |= ENETC_VF_FLAG_PF_SET_MAC;\n-\tenetc_pf_set_primary_mac_addr(\u0026priv-\u003esi-\u003ehw, vf + 1, mac);\n-\tmutex_unlock(\u0026vf_state-\u003elock);\n-\n-\treturn 0;\n-}\n-\n static int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,\n \t\t\t\tu8 qos, __be16 proto)\n {\n \tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n \tstruct enetc_pf *pf = enetc_si_priv(priv-\u003esi);\n+\tstruct enetc_vf_state *vf_state;\n \n \tif (priv-\u003esi-\u003eerrata \u0026 ENETC_ERR_VLAN_ISOL)\n \t\treturn -EOPNOTSUPP;\n@@ -230,6 +208,17 @@ static int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,\n \t\treturn -EPROTONOSUPPORT;\n \n \tenetc_set_isol_vlan(\u0026priv-\u003esi-\u003ehw, vf + 1, vlan, qos);\n+\n+\tvf_state = \u0026pf-\u003evf_state[vf];\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\t/* Currently only C-tags is supported, so tpid is always 0,\n+\t * which indicates ETH_P_8021Q.\n+\t */\n+\tvf_state-\u003etpid = 0;\n+\tvf_state-\u003eqos = qos;\n+\tvf_state-\u003evid = vlan;\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n \treturn 0;\n }\n \n@@ -237,6 +226,7 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)\n {\n \tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n \tstruct enetc_pf *pf = enetc_si_priv(priv-\u003esi);\n+\tstruct enetc_vf_state *vf_state;\n \tu32 cfgr;\n \n \tif (vf \u003e= pf-\u003etotal_vfs)\n@@ -246,6 +236,16 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)\n \tcfgr = (cfgr \u0026 ~ENETC_PSICFGR0_ASE) | (en ? ENETC_PSICFGR0_ASE : 0);\n \tenetc_port_wr(\u0026priv-\u003esi-\u003ehw, ENETC_PSICFGR0(vf + 1), cfgr);\n \n+\tvf_state = \u0026pf-\u003evf_state[vf];\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\n+\tif (en)\n+\t\tvf_state-\u003eflags |= ENETC_VF_FLAG_SPOOFCHK;\n+\telse\n+\t\tvf_state-\u003eflags \u0026= ~ENETC_VF_FLAG_SPOOFCHK;\n+\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n \treturn 0;\n }\n \n@@ -488,6 +488,7 @@ static const struct net_device_ops enetc_ndev_ops = {\n \t.ndo_set_rx_mode\t= enetc_pf_set_rx_mode,\n \t.ndo_vlan_rx_add_vid\t= enetc_vlan_rx_add_vid,\n \t.ndo_vlan_rx_kill_vid\t= enetc_vlan_rx_del_vid,\n+\t.ndo_set_vf_trust\t= enetc_pf_set_vf_trust,\n \t.ndo_set_vf_mac\t\t= enetc_pf_set_vf_mac,\n \t.ndo_set_vf_vlan\t= enetc_pf_set_vf_vlan,\n \t.ndo_set_vf_spoofchk\t= enetc_pf_set_vf_spoofchk,\n@@ -498,6 +499,7 @@ static const struct net_device_ops enetc_ndev_ops = {\n \t.ndo_xdp_xmit\t\t= enetc_xdp_xmit,\n \t.ndo_hwtstamp_get\t= enetc_hwtstamp_get,\n \t.ndo_hwtstamp_set\t= enetc_hwtstamp_set,\n+\t.ndo_get_vf_config\t= enetc_pf_get_vf_config,\n };\n \n static struct phylink_pcs *\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h\nindex 56d23a8a11a06..25e869d54365c 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h\n@@ -6,14 +6,22 @@\n \n #define ENETC_PF_NUM_RINGS\t8\n #define ENETC_VLAN_HT_SIZE\t64\n+#define ENETC_VF_MC_HASH_BITS_MAX\t8 /* For untrusted VFs */\n \n enum enetc_vf_flags {\n \tENETC_VF_FLAG_PF_SET_MAC\t= BIT(0),\n+\tENETC_VF_FLAG_TRUSTED\t\t= BIT(1),\n+\tENETC_VF_FLAG_UC_PROMISC\t= BIT(2),\n+\tENETC_VF_FLAG_MC_PROMISC\t= BIT(3),\n+\tENETC_VF_FLAG_SPOOFCHK\t\t= BIT(4),\n };\n \n struct enetc_vf_state {\n \tstruct mutex lock; /* Prevent concurrent access */\n \tenum enetc_vf_flags flags;\n+\tu8 tpid; /* SI-based VLAN TPID (0: 0x8100, 1: 0x88a8) */\n+\tu8 qos; /* SI-based VLAN QOS (priority) bits */\n+\tu16 vid; /* SI-based VLAN ID */\n };\n \n struct enetc_port_caps {\n@@ -30,6 +38,7 @@ struct enetc_pf_ops {\n \tstruct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus);\n \tvoid (*destroy_pcs)(struct phylink_pcs *pcs);\n \tint (*enable_psfp)(struct enetc_ndev_priv *priv);\n+\tvoid (*vf_flr_handler)(struct enetc_pf *pf, int vf_id);\n };\n \n struct enetc_pf {\n@@ -37,12 +46,7 @@ struct enetc_pf {\n \tint num_vfs; /* number of active VFs, after sriov_init */\n \tint total_vfs; /* max number of VFs, set for PF at probe */\n \tstruct enetc_vf_state *vf_state;\n-\n-\tstruct enetc_mac_filter mac_filter[MADDR_TYPE];\n-\n \tstruct enetc_msg_swbd *rxmsg;\n-\tstruct work_struct msg_task;\n-\tchar msg_int_name[ENETC_INT_NAME_MAX];\n \n \tDECLARE_BITMAP(vlan_ht_filter, ENETC_VLAN_HT_SIZE);\n \tDECLARE_BITMAP(active_vlans, VLAN_N_VID);\n@@ -56,6 +60,12 @@ struct enetc_pf {\n \n \tstruct enetc_port_caps caps;\n \tconst struct enetc_pf_ops *ops;\n+\n+\t/* Message lock, prevent concurrent access */\n+\tstruct mutex msg_lock;\n+\tbool sriov_enabled;\n+\tbool link_up;\n+\tu16 link_status_ms_mask;\n };\n \n #define phylink_to_enetc_pf(config) \\\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c\nindex d32a195a04c97..264294a0cc236 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c\n@@ -151,26 +151,44 @@ void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash)\n }\n EXPORT_SYMBOL_GPL(enetc_set_si_uc_hash_filter);\n \n-void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash)\n+static void enetc_get_psimmhfr_offsets(struct enetc_si *si, int si_id,\n+\t\t\t\t       int *psimmhfr0, int *psimmhfr1)\n {\n-\tint psimmhfr0_off, psimmhfr1_off;\n-\tstruct enetc_hw *hw = \u0026si-\u003ehw;\n-\n \tif (is_enetc_rev1(si)) {\n \t\tbool err = si-\u003eerrata \u0026 ENETC_ERR_UCMCSWP;\n \n-\t\tpsimmhfr0_off = ENETC_PSIMMHFR0(si_id, err);\n-\t\tpsimmhfr1_off = ENETC_PSIMMHFR1(si_id);\n+\t\t*psimmhfr0 = ENETC_PSIMMHFR0(si_id, err);\n+\t\t*psimmhfr1 = ENETC_PSIMMHFR1(si_id);\n \t} else {\n-\t\tpsimmhfr0_off = ENETC4_PSIMMHFR0(si_id);\n-\t\tpsimmhfr1_off = ENETC4_PSIMMHFR1(si_id);\n+\t\t*psimmhfr0 = ENETC4_PSIMMHFR0(si_id);\n+\t\t*psimmhfr1 = ENETC4_PSIMMHFR1(si_id);\n \t}\n+}\n+\n+void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash)\n+{\n+\tint psimmhfr0_off, psimmhfr1_off;\n+\tstruct enetc_hw *hw = \u0026si-\u003ehw;\n \n+\tenetc_get_psimmhfr_offsets(si, si_id, \u0026psimmhfr0_off, \u0026psimmhfr1_off);\n \tenetc_port_wr(hw, psimmhfr0_off, lower_32_bits(hash));\n \tenetc_port_wr(hw, psimmhfr1_off, upper_32_bits(hash));\n }\n EXPORT_SYMBOL_GPL(enetc_set_si_mc_hash_filter);\n \n+static u64 enetc_get_si_mc_hash_filter(struct enetc_si *si, int si_id)\n+{\n+\tint psimmhfr0_off, psimmhfr1_off;\n+\tstruct enetc_hw *hw = \u0026si-\u003ehw;\n+\tu32 hash_h, hash_l;\n+\n+\tenetc_get_psimmhfr_offsets(si, si_id, \u0026psimmhfr0_off, \u0026psimmhfr1_off);\n+\thash_l = enetc_port_rd(hw, psimmhfr0_off);\n+\thash_h = enetc_port_rd(hw, psimmhfr1_off);\n+\n+\treturn ((u64)hash_h \u003c\u003c 32) | hash_l;\n+}\n+\n void enetc_set_si_vlan_promisc(struct enetc_si *si, int si_id, bool promisc)\n {\n \tstruct enetc_hw *hw = \u0026si-\u003ehw;\n@@ -582,9 +600,120 @@ int enetc_init_sriov_resources(struct enetc_pf *pf)\n \tfor (int i = 0; i \u003c pf-\u003etotal_vfs; i++)\n \t\tmutex_init(\u0026pf-\u003evf_state[i].lock);\n \n+\tmutex_init(\u0026pf-\u003emsg_lock);\n+\n \treturn 0;\n }\n EXPORT_SYMBOL_GPL(enetc_init_sriov_resources);\n \n+int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n+\tstruct enetc_pf *pf = enetc_si_priv(priv-\u003esi);\n+\tstruct enetc_vf_state *vf_state;\n+\tstruct enetc_si *si = priv-\u003esi;\n+\tint si_id = vf + 1;\n+\n+\tif (vf \u003e= pf-\u003etotal_vfs)\n+\t\treturn -EINVAL;\n+\n+\tvf_state = \u0026pf-\u003evf_state[vf];\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\n+\tif (setting) {\n+\t\tvf_state-\u003eflags |= ENETC_VF_FLAG_TRUSTED;\n+\t} else {\n+\t\tu64 hash;\n+\n+\t\tvf_state-\u003eflags \u0026= ~(ENETC_VF_FLAG_TRUSTED |\n+\t\t\t\t     ENETC_VF_FLAG_UC_PROMISC |\n+\t\t\t\t     ENETC_VF_FLAG_MC_PROMISC);\n+\n+\t\t/* For ENETC v1, we only support setting the VF's MAC address\n+\t\t * via VSI-to-PSI messages. Unicast and multicast promiscuous\n+\t\t * mode and hash filters are not supported, so there is no need\n+\t\t * to clear these configurations.\n+\t\t */\n+\t\tif (is_enetc_rev1(si))\n+\t\t\tgoto vf_state_unlock;\n+\n+\t\t/* Disable unicast and multicast promiscuous modes */\n+\t\tmutex_lock(\u0026pf-\u003emsg_lock);\n+\t\tenetc_set_si_uc_promisc(si, si_id, false);\n+\t\tenetc_set_si_mc_promisc(si, si_id, false);\n+\t\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+\n+\t\t/* Clear unicast hash filter */\n+\t\tenetc_set_si_uc_hash_filter(si, si_id, 0);\n+\n+\t\t/* Clear multicast hash filter if its set bits exceed\n+\t\t * ENETC_VF_MC_HASH_BITS_MAX.\n+\t\t */\n+\t\thash = enetc_get_si_mc_hash_filter(si, si_id);\n+\t\tif (hweight64(hash) \u003e ENETC_VF_MC_HASH_BITS_MAX)\n+\t\t\tenetc_set_si_mc_hash_filter(si, si_id, 0);\n+\t}\n+\n+vf_state_unlock:\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(enetc_pf_set_vf_trust);\n+\n+int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n+\tstruct enetc_pf *pf = enetc_si_priv(priv-\u003esi);\n+\tstruct enetc_vf_state *vf_state;\n+\n+\tif (vf \u003e= pf-\u003etotal_vfs)\n+\t\treturn -EINVAL;\n+\n+\tif (!is_valid_ether_addr(mac))\n+\t\treturn -EADDRNOTAVAIL;\n+\n+\tvf_state = \u0026pf-\u003evf_state[vf];\n+\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\tvf_state-\u003eflags |= ENETC_VF_FLAG_PF_SET_MAC;\n+\tenetc_set_si_hw_addr(pf, vf + 1, mac);\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(enetc_pf_set_vf_mac);\n+\n+int enetc_pf_get_vf_config(struct net_device *ndev, int vf,\n+\t\t\t   struct ifla_vf_info *ivi)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n+\tstruct enetc_pf *pf = enetc_si_priv(priv-\u003esi);\n+\tstruct enetc_vf_state *vf_state;\n+\n+\tif (vf \u003e= pf-\u003etotal_vfs)\n+\t\treturn -EINVAL;\n+\n+\tvf_state = \u0026pf-\u003evf_state[vf];\n+\tmutex_lock(\u0026vf_state-\u003elock);\n+\n+\tivi-\u003evf = vf;\n+\tivi-\u003espoofchk = !!(vf_state-\u003eflags \u0026 ENETC_VF_FLAG_SPOOFCHK);\n+\tivi-\u003etrusted = !!(vf_state-\u003eflags \u0026 ENETC_VF_FLAG_TRUSTED);\n+\tenetc_get_si_hw_addr(pf, vf + 1, ivi-\u003emac);\n+\n+\tif (vf_state-\u003evid) {\n+\t\tivi-\u003evlan = vf_state-\u003evid;\n+\t\tivi-\u003eqos = vf_state-\u003eqos;\n+\t\tivi-\u003evlan_proto = vf_state-\u003etpid ? htons(ETH_P_8021AD) :\n+\t\t\t\t\t\t   htons(ETH_P_8021Q);\n+\t}\n+\n+\tmutex_unlock(\u0026vf_state-\u003elock);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(enetc_pf_get_vf_config);\n+\n MODULE_DESCRIPTION(\"NXP ENETC PF common functionality driver\");\n MODULE_LICENSE(\"Dual BSD/GPL\");\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h\nindex 8243ce0de57f6..f36f45450733f 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h\n@@ -22,17 +22,43 @@ void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc);\n void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash);\n void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash);\n void enetc_set_si_vlan_promisc(struct enetc_si *si, int si_id, bool promisc);\n+int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting);\n+int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac);\n+int enetc_pf_get_vf_config(struct net_device *ndev, int vf,\n+\t\t\t   struct ifla_vf_info *ivi);\n \n static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)\n {\n \treturn enetc_global_rd(hw, ENETC_G_EIPBRR0) \u0026 EIPBRR0_REVISION;\n }\n \n+static inline void enetc_pf_msg_lock(struct enetc_pf *pf)\n+{\n+\tif (pf-\u003etotal_vfs)\n+\t\tmutex_lock(\u0026pf-\u003emsg_lock);\n+}\n+\n+static inline void enetc_pf_msg_unlock(struct enetc_pf *pf)\n+{\n+\tif (pf-\u003etotal_vfs)\n+\t\tmutex_unlock(\u0026pf-\u003emsg_lock);\n+}\n+\n #if IS_ENABLED(CONFIG_PCI_IOV)\n int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs);\n+void enetc_pf_notify_vf_link_up(struct enetc_pf *pf);\n+void enetc_pf_notify_vf_link_down(struct enetc_pf *pf);\n #else\n static inline int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)\n {\n \treturn 0;\n }\n+\n+static inline void enetc_pf_notify_vf_link_up(struct enetc_pf *pf)\n+{\n+}\n+\n+static inline void enetc_pf_notify_vf_link_down(struct enetc_pf *pf)\n+{\n+}\n #endif\ndiff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c\nindex 7dcb4a0246f52..a4d0089ef1a93 100644\n--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c\n+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c\n@@ -107,8 +107,12 @@ static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg)\n \t\tcase ENETC_MSG_CLASS_ID_CMD_TIMEOUT:\n \t\t\terr = -ETIME;\n \t\t\tbreak;\n-\t\tcase ENETC_MSG_CLASS_ID_INVALID_MSG_LEN:\n \t\tcase ENETC_MSG_CLASS_ID_MAC_FILTER:\n+\t\t\tif (FIELD_GET(ENETC_PF_MSG_CLASS_CODE, pf_msg) ==\n+\t\t\t    ENETC_MF_CLASS_CODE_UCF_DENY)\n+\t\t\t\treturn -EACCES;\n+\t\t\tfallthrough;\n+\t\tcase ENETC_MSG_CLASS_ID_INVALID_MSG_LEN:\n \t\t\terr = -EINVAL;\n \t\t\tbreak;\n \t\tcase ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED:\n@@ -131,6 +135,52 @@ static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg)\n \treturn err;\n }\n \n+static int enetc_msg_link_status_notifier(struct enetc_si *si, bool reg)\n+{\n+\tstruct device *dev = \u0026si-\u003epdev-\u003edev;\n+\tstruct enetc_msg_swbd msg_swbd;\n+\tu8 cmd_id;\n+\n+\tmsg_swbd.size = ALIGN(sizeof(struct enetc_msg_generic),\n+\t\t\t      ENETC_MSG_ALIGN);\n+\tmsg_swbd.vaddr = dma_alloc_coherent(dev, msg_swbd.size,\n+\t\t\t\t\t    \u0026msg_swbd.dma, GFP_KERNEL);\n+\tif (!msg_swbd.vaddr)\n+\t\treturn -ENOMEM;\n+\n+\tcmd_id = reg ? ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER :\n+\t\t       ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER;\n+\tenetc_msg_fill_common_hdr(\u0026msg_swbd, ENETC_MSG_CLASS_ID_LINK_STATUS,\n+\t\t\t\t  cmd_id, 0, 0);\n+\n+\treturn enetc_msg_vsi_send(si, \u0026msg_swbd);\n+}\n+\n+static int enetc_vf_reg_link_status_notifier(struct enetc_si *si)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(si-\u003endev);\n+\tint err;\n+\n+\terr = enetc_msg_link_status_notifier(si, true);\n+\tif (!err)\n+\t\tset_bit(ENETC_LINK_STATUS_NOTIFIER_REGISTERED, \u0026priv-\u003eflags);\n+\n+\treturn err;\n+}\n+\n+static int enetc_vf_unreg_link_status_notifier(struct enetc_si *si)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(si-\u003endev);\n+\tint err;\n+\n+\terr = enetc_msg_link_status_notifier(si, false);\n+\tif (!err)\n+\t\tclear_bit(ENETC_LINK_STATUS_NOTIFIER_REGISTERED,\n+\t\t\t  \u0026priv-\u003eflags);\n+\n+\treturn err;\n+}\n+\n static int enetc_msg_vsi_set_primary_mac_addr(struct enetc_ndev_priv *priv,\n \t\t\t\t\t      struct sockaddr *saddr)\n {\n@@ -209,6 +259,142 @@ static int enetc_vf_setup_tc(struct net_device *ndev, enum tc_setup_type type,\n \t}\n }\n \n+static int enetc_vf_set_mac_promisc(struct enetc_si *si, int type, bool en)\n+{\n+\tstruct enetc_msg_mac_promisc_mode *msg;\n+\tstruct device *dev = \u0026si-\u003epdev-\u003edev;\n+\tstruct enetc_msg_swbd msg_swbd;\n+\n+\tif (!(type \u0026 ENETC_MAC_FILTER_TYPE_ALL))\n+\t\treturn -EINVAL;\n+\n+\tmsg_swbd.size = ALIGN(sizeof(*msg), ENETC_MSG_ALIGN);\n+\tmsg_swbd.vaddr = dma_alloc_coherent(dev, msg_swbd.size,\n+\t\t\t\t\t    \u0026msg_swbd.dma, GFP_KERNEL);\n+\tif (!msg_swbd.vaddr)\n+\t\treturn -ENOMEM;\n+\n+\tmsg = (struct enetc_msg_mac_promisc_mode *)msg_swbd.vaddr;\n+\tmsg-\u003econfig = FIELD_PREP(ENETC_MSG_MAC_TYPE,\n+\t\t\t\t type \u0026 ENETC_MAC_FILTER_TYPE_ALL);\n+\tmsg-\u003econfig |= FIELD_PREP(ENETC_MSG_MAC_PROMISC_MODE, en);\n+\tmsg-\u003econfig |= FIELD_PREP(ENETC_MSG_MAC_FLUSH_MACS, en);\n+\tenetc_msg_fill_common_hdr(\u0026msg_swbd, ENETC_MSG_CLASS_ID_MAC_FILTER,\n+\t\t\t\t  ENETC_MSG_SET_MAC_PROMISC_MODE, 0, 0);\n+\n+\treturn enetc_msg_vsi_send(si, \u0026msg_swbd);\n+}\n+\n+static int enetc_vf_set_mac_hash_filter(struct enetc_si *si,\n+\t\t\t\t\tstruct netdev_hw_addr_list *uc,\n+\t\t\t\t\tstruct netdev_hw_addr_list *mc)\n+{\n+\tstruct enetc_msg_mac_hash_filter *msg;\n+\tstruct enetc_mac_filter *mac_filter;\n+\tstruct device *dev = \u0026si-\u003epdev-\u003edev;\n+\tstruct net_device *ndev = si-\u003endev;\n+\tstruct enetc_msg_swbd msg_swbd;\n+\tstruct netdev_hw_addr *ha;\n+\tu32 msg_size, tbl_cnt;\n+\tint mac_filter_type;\n+\tint i = 0;\n+\n+\tif (ndev-\u003eflags \u0026 IFF_PROMISC)\n+\t\treturn 0;\n+\n+\tif (ndev-\u003eflags \u0026 IFF_ALLMULTI) {\n+\t\ttbl_cnt = 2;\n+\t\tmac_filter_type = ENETC_MAC_FILTER_TYPE_UC;\n+\t} else {\n+\t\ttbl_cnt = 4;\n+\t\tmac_filter_type = ENETC_MAC_FILTER_TYPE_ALL;\n+\t}\n+\n+\tmsg_size = struct_size(msg, hash_tbl, tbl_cnt);\n+\tmsg_swbd.size = ALIGN(msg_size, ENETC_MSG_ALIGN);\n+\tmsg_swbd.vaddr = dma_alloc_coherent(dev, msg_swbd.size,\n+\t\t\t\t\t    \u0026msg_swbd.dma, GFP_KERNEL);\n+\tif (!msg_swbd.vaddr)\n+\t\treturn -ENOMEM;\n+\n+\tmsg = (struct enetc_msg_mac_hash_filter *)msg_swbd.vaddr;\n+\tmsg-\u003esz_type = FIELD_PREP(ENETC_MSG_MAC_TYPE, mac_filter_type);\n+\tmsg-\u003esz_type |= FIELD_PREP(ENETC_MSG_MAC_HASH_SIZE,\n+\t\t\t\t   ENETC_MAC_HASH_TABLE_SIZE_64);\n+\n+\tif (mac_filter_type \u0026 ENETC_MAC_FILTER_TYPE_UC) {\n+\t\tmac_filter = \u0026si-\u003emac_filter[UC];\n+\t\tenetc_reset_mac_addr_filter(mac_filter);\n+\t\tnetdev_hw_addr_list_for_each(ha, uc)\n+\t\t\tenetc_add_mac_addr_ht_filter(mac_filter, ha-\u003eaddr);\n+\n+\t\tbitmap_to_arr32(\u0026msg-\u003ehash_tbl[i], mac_filter-\u003emac_hash_table,\n+\t\t\t\tENETC_MADDR_HASH_TBL_SZ);\n+\t\ti += 2;\n+\t}\n+\n+\tif (mac_filter_type \u0026 ENETC_MAC_FILTER_TYPE_MC) {\n+\t\tmac_filter = \u0026si-\u003emac_filter[MC];\n+\t\tenetc_reset_mac_addr_filter(mac_filter);\n+\t\tnetdev_hw_addr_list_for_each(ha, mc)\n+\t\t\tenetc_add_mac_addr_ht_filter(mac_filter, ha-\u003eaddr);\n+\n+\t\tbitmap_to_arr32(\u0026msg-\u003ehash_tbl[i], mac_filter-\u003emac_hash_table,\n+\t\t\t\tENETC_MADDR_HASH_TBL_SZ);\n+\t}\n+\n+\tenetc_msg_fill_common_hdr(\u0026msg_swbd, ENETC_MSG_CLASS_ID_MAC_FILTER,\n+\t\t\t\t  ENETC_MSG_SET_MAC_HASH_TABLE, 0, 0);\n+\n+\treturn enetc_msg_vsi_send(si, \u0026msg_swbd);\n+}\n+\n+static int enetc_vf_set_rx_mode(struct net_device *ndev,\n+\t\t\t\tstruct netdev_hw_addr_list *uc,\n+\t\t\t\tstruct netdev_hw_addr_list *mc)\n+{\n+\tstruct enetc_ndev_priv *priv = netdev_priv(ndev);\n+\tstruct enetc_si *si = priv-\u003esi;\n+\tint err;\n+\n+\t/* For ENETC v1, we cannot return -EOPNOTSUPP or any other error,\n+\t * otherwise ndev-\u003erx_mode_retry_timer will try to set rx_mode\n+\t * multiple times, which is pointless.\n+\t */\n+\tif (is_enetc_rev1(si))\n+\t\treturn 0;\n+\n+\tif (ndev-\u003eflags \u0026 IFF_PROMISC) {\n+\t\terr = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_ALL,\n+\t\t\t\t\t       true);\n+\t} else if (ndev-\u003eflags \u0026 IFF_ALLMULTI) {\n+\t\terr = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_UC,\n+\t\t\t\t\t       false);\n+\t\tif (err)\n+\t\t\tgoto out;\n+\n+\t\terr = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_MC,\n+\t\t\t\t\t       true);\n+\t} else {\n+\t\terr = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_ALL,\n+\t\t\t\t\t       false);\n+\t}\n+\n+\tif (err)\n+\t\tgoto out;\n+\n+\terr = enetc_vf_set_mac_hash_filter(si, uc, mc);\n+\n+out:\n+\t/* If the error code is -EOPNOTSUPP or -EACCES or -EPERM, return 0\n+\t * directly to avoid meaningless retries.\n+\t */\n+\tif (err == -EOPNOTSUPP || err == -EACCES || err == -EPERM)\n+\t\treturn 0;\n+\n+\treturn err;\n+}\n+\n /* Probing/ Init */\n static const struct net_device_ops enetc_ndev_ops = {\n \t.ndo_open\t\t= enetc_open,\n@@ -221,6 +407,7 @@ static const struct net_device_ops enetc_ndev_ops = {\n \t.ndo_setup_tc\t\t= enetc_vf_setup_tc,\n \t.ndo_hwtstamp_get\t= enetc_hwtstamp_get,\n \t.ndo_hwtstamp_set\t= enetc_hwtstamp_set,\n+\t.ndo_set_rx_mode_async\t= enetc_vf_set_rx_mode,\n };\n \n static void enetc_vf_get_revision(struct enetc_si *si)\n@@ -276,15 +463,146 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,\n \tndev-\u003evlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |\n \t\t\t      NETIF_F_TSO | NETIF_F_TSO6;\n \n+\tif (!is_enetc_rev1(si))\n+\t\tndev-\u003epriv_flags |= IFF_UNICAST_FLT;\n+\n \tif (si-\u003enum_rss) {\n \t\tndev-\u003ehw_features |= NETIF_F_RXHASH;\n \t\tndev-\u003efeatures |= NETIF_F_RXHASH;\n \t}\n \n+\tif (si-\u003edrvdata-\u003etx_csum)\n+\t\tpriv-\u003eactive_offloads |= ENETC_F_TXCSUM;\n+\n+\tif (si-\u003ehw_features \u0026 ENETC_SI_F_LSO)\n+\t\tpriv-\u003eactive_offloads |= ENETC_F_LSO;\n+\n \t/* pick up primary MAC address from SI */\n \tenetc_load_primary_mac_addr(\u0026si-\u003ehw, ndev);\n }\n \n+static void enetc_vf_enable_mr_int(struct enetc_si *si)\n+{\n+\tif (is_enetc_rev1(si))\n+\t\treturn;\n+\n+\tenetc_wr(\u0026si-\u003ehw, ENETC_VSIIER, VSIIER_MRIE);\n+}\n+\n+static void enetc_vf_disable_mr_int(struct enetc_si *si)\n+{\n+\tif (is_enetc_rev1(si))\n+\t\treturn;\n+\n+\tenetc_wr(\u0026si-\u003ehw, ENETC_VSIIER, 0);\n+}\n+\n+static void enetc_vf_msg_handle_link_status(struct enetc_si *si, u8 status)\n+{\n+\tbool tx_pause = !!(status \u0026 ENETC_CLASS_CODE_TX_PAUSE_EN);\n+\tbool link_down = !!(status \u0026 ENETC_CLASS_CODE_LINK_DOWN);\n+\tstruct enetc_ndev_priv *priv = netdev_priv(si-\u003endev);\n+\tstruct net_device *ndev = si-\u003endev;\n+\n+\trtnl_lock();\n+\tif (!netif_running(ndev))\n+\t\tgoto unlock_rtnl;\n+\n+\tif (link_down) {\n+\t\tif (netif_carrier_ok(ndev)) {\n+\t\t\tnetif_carrier_off(ndev);\n+\t\t\tnetdev_info(ndev, \"Link is Down\\n\");\n+\t\t}\n+\n+\t\tgoto unlock_rtnl;\n+\t}\n+\n+\t/* Link is up */\n+\tenetc_set_congestion_mode(priv, tx_pause);\n+\n+\tif (!netif_carrier_ok(ndev)) {\n+\t\tnetif_carrier_on(ndev);\n+\t\tnetdev_info(ndev, \"Link is Up, tx pause %s\\n\",\n+\t\t\t    tx_pause ? \"on\" : \"off\");\n+\t}\n+\n+unlock_rtnl:\n+\trtnl_unlock();\n+}\n+\n+static void enetc_vf_msg_task(struct work_struct *work)\n+{\n+\tstruct enetc_si *si = container_of(work, struct enetc_si, msg_task);\n+\tstruct enetc_hw *hw = \u0026si-\u003ehw;\n+\tu8 class_id, class_code;\n+\tu16 pf_msg;\n+\n+\t/* W1C to clear the message received interrupt event */\n+\tenetc_wr(hw, ENETC_VSIIDR, VSIIDR_MR);\n+\n+\t/* Reading VSIMSGRR retrieves the message data and acknowledges to\n+\t * the PF that the message was received and another message can be\n+\t * sent.\n+\t */\n+\tpf_msg = FIELD_GET(VSIMSGRR_MC, enetc_rd(hw, ENETC_VSIMSGRR));\n+\tclass_id = FIELD_GET(ENETC_PF_MSG_CLASS_ID, pf_msg);\n+\n+\tswitch (class_id) {\n+\tcase ENETC_MSG_CLASS_ID_LINK_STATUS:\n+\t\tclass_code = FIELD_GET(ENETC_PF_MSG_CLASS_CODE_U8, pf_msg);\n+\t\tenetc_vf_msg_handle_link_status(si, class_code);\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_err(\u0026si-\u003epdev-\u003edev,\n+\t\t\t\"Unsupported Message Class ID (0x%02x) from PF\\n\",\n+\t\t\tclass_id);\n+\t}\n+\n+\tenetc_vf_enable_mr_int(si);\n+}\n+\n+static irqreturn_t enetc_vf_msg_msix_handler(int irq, void *data)\n+{\n+\tstruct enetc_si *si = (struct enetc_si *)data;\n+\n+\tenetc_vf_disable_mr_int(si);\n+\tqueue_work(si-\u003eworkqueue, \u0026si-\u003emsg_task);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static int enetc_vf_register_msg_msix(struct enetc_si *si)\n+{\n+\tint irq, err;\n+\n+\tif (is_enetc_rev1(si))\n+\t\treturn 0;\n+\n+\tsnprintf(si-\u003emsg_int_name, sizeof(si-\u003emsg_int_name), \"%s-pfmsg\",\n+\t\t pci_name(si-\u003epdev));\n+\tirq = pci_irq_vector(si-\u003epdev, ENETC_SI_INT_IDX);\n+\terr = request_irq(irq, enetc_vf_msg_msix_handler, 0,\n+\t\t\t  si-\u003emsg_int_name, si);\n+\tif (err) {\n+\t\tdev_err(\u0026si-\u003epdev-\u003edev,\n+\t\t\t\"VF messaging: request_irq() failed!\\n\");\n+\t\treturn err;\n+\t}\n+\n+\t/* set one IRQ entry for PSI-to-VSI messaging */\n+\tenetc_wr(\u0026si-\u003ehw, ENETC_SIMSIVR, ENETC_SI_INT_IDX);\n+\n+\treturn 0;\n+}\n+\n+static void enetc_vf_free_msg_msix(struct enetc_si *si)\n+{\n+\tif (is_enetc_rev1(si))\n+\t\treturn;\n+\n+\tfree_irq(pci_irq_vector(si-\u003epdev, ENETC_SI_INT_IDX), si);\n+}\n+\n static const struct enetc_si_ops enetc_vsi_ops = {\n \t.get_rss_table = enetc_get_rss_table,\n \t.set_rss_table = enetc_set_rss_table,\n@@ -292,6 +610,43 @@ static const struct enetc_si_ops enetc_vsi_ops = {\n \t.teardown_cbdr = enetc_teardown_cbdr,\n };\n \n+static const struct enetc_si_ops enetc4_vsi_ops = {\n+\t.get_rss_table = enetc4_get_rss_table,\n+\t.set_rss_table = enetc4_set_rss_table,\n+\t.setup_cbdr = enetc4_setup_cbdr,\n+\t.teardown_cbdr = enetc4_teardown_cbdr,\n+\t.vf_reg_link_status_notifier = enetc_vf_reg_link_status_notifier,\n+\t.vf_unreg_link_status_notifier = enetc_vf_unreg_link_status_notifier,\n+};\n+\n+static int enetc_vf_wq_task_init(struct enetc_si *si)\n+{\n+\tif (is_enetc_rev1(si))\n+\t\treturn 0;\n+\n+\tsi-\u003eworkqueue = alloc_ordered_workqueue(\"enetc-%s-wq\", WQ_MEM_RECLAIM,\n+\t\t\t\t\t\tpci_name(si-\u003epdev));\n+\tif (!si-\u003eworkqueue)\n+\t\treturn -ENOMEM;\n+\n+\tINIT_WORK(\u0026si-\u003emsg_task, enetc_vf_msg_task);\n+\n+\treturn 0;\n+}\n+\n+static void enetc_vf_wq_task_destroy(struct enetc_si *si)\n+{\n+\tif (!si-\u003eworkqueue)\n+\t\treturn;\n+\n+\tdisable_work_sync(\u0026si-\u003emsg_task);\n+\n+\t/* The MR interrupt may be re-enabled by si-\u003emsg_task */\n+\tenetc_vf_disable_mr_int(si);\n+\n+\tdestroy_workqueue(si-\u003eworkqueue);\n+}\n+\n static int enetc_vf_probe(struct pci_dev *pdev,\n \t\t\t  const struct pci_device_id *ent)\n {\n@@ -307,7 +662,11 @@ static int enetc_vf_probe(struct pci_dev *pdev,\n \n \tsi = pci_get_drvdata(pdev);\n \tenetc_vf_get_revision(si);\n-\tsi-\u003eops = \u0026enetc_vsi_ops;\n+\tif (is_enetc_rev1(si))\n+\t\tsi-\u003eops = \u0026enetc_vsi_ops;\n+\telse\n+\t\tsi-\u003eops = \u0026enetc4_vsi_ops;\n+\n \terr = enetc_get_driver_data(si);\n \tif (err) {\n \t\tdev_err_probe(\u0026pdev-\u003edev, err,\n@@ -359,15 +718,33 @@ static int enetc_vf_probe(struct pci_dev *pdev,\n \t\tgoto err_alloc_msix;\n \t}\n \n+\terr = enetc_vf_wq_task_init(si);\n+\tif (err) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"Failed to init workqueue\\n\");\n+\t\tgoto err_wq_init;\n+\t}\n+\n+\terr = enetc_vf_register_msg_msix(si);\n+\tif (err) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"Failed to register msg irq\\n\");\n+\t\tgoto err_register_msg_msix;\n+\t}\n+\n \terr = register_netdev(ndev);\n \tif (err)\n \t\tgoto err_reg_netdev;\n \n+\t/* Enable message received interrupt */\n+\tenetc_vf_enable_mr_int(si);\n \tnetif_carrier_off(ndev);\n \n \treturn 0;\n \n err_reg_netdev:\n+\tenetc_vf_free_msg_msix(si);\n+err_register_msg_msix:\n+\tenetc_vf_wq_task_destroy(si);\n+err_wq_init:\n \tenetc_free_msix(priv);\n err_config_si:\n err_alloc_msix:\n@@ -393,8 +770,11 @@ static void enetc_vf_remove(struct pci_dev *pdev)\n \tstruct enetc_msg_swbd msg;\n \n \tpriv = netdev_priv(si-\u003endev);\n+\tenetc_vf_disable_mr_int(si);\n \tunregister_netdev(si-\u003endev);\n \n+\tenetc_vf_free_msg_msix(si);\n+\tenetc_vf_wq_task_destroy(si);\n \tenetc_free_msix(priv);\n \n \tenetc_free_si_resources(priv);\n@@ -409,6 +789,7 @@ static void enetc_vf_remove(struct pci_dev *pdev)\n \n static const struct pci_device_id enetc_vf_id_table[] = {\n \t{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_VF) },\n+\t{ PCI_DEVICE(NXP_ENETC_VENDOR_ID, NXP_ENETC_VF_DEV_ID) },\n \t{ 0, } /* End of table. */\n };\n MODULE_DEVICE_TABLE(pci, enetc_vf_id_table);\n"
}

2/1 2026/08/31 03:57 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch series modifies the NXP/Freescale ENETC Ethernet PF and VF drivers (drivers/net/ethernet/freescale/enetc/), adding support for ENETC v4 VF mailbox communications, MAC hash filtering, and link status notifications. These changes are specific to NXP ENETC PCIe hardware not emulated in standard QEMU or virtualized environments like GCE, making the modified code unreachable for fuzzing.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
  even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs
   output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit 18bc5b00603acfb0667904c6a334a58c9fdee884
Author: syz-cluster <triage@syzkaller.com>
Date:   Mon Aug 31 03:57:53 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index db5c17a446137..f425f82a6213a 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -69,6 +69,7 @@ config FSL_ENETC_VF
 	depends on PCI_MSI
 	select FSL_ENETC_CORE
 	select FSL_ENETC_MDIO
+	select NXP_NTMP
 	select PHYLINK
 	select DIMLIB
 	select CRC_ITU_T
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 80f0082f6c633..fb5df740650e0 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -2935,11 +2935,31 @@ static void enetc_clear_interrupts(struct enetc_ndev_priv *priv)
 static int enetc_phylink_connect(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_si *si = priv->si;
 	struct ethtool_keee edata;
 	int err;
 
 	if (!priv->phylink) {
 		/* phy-less mode */
+		if (!si->ops->vf_reg_link_status_notifier)
+			goto carrier_on;
+
+		/* For phy-less VFs on ENETC v4, attempt to register a link
+		 * status notifier with the PF via the VSI-to-PSI messaging
+		 * channel. If registration succeeds, the PF will immediately
+		 * send the current link status and broadcast future link
+		 * transitions; carrier state is then managed in
+		 * enetc_vf_msg_handle_link_status(). If registration fails,
+		 * fall back to the LS1028A behaviour and assert carrier
+		 * unconditionally via netif_carrier_on().
+		 */
+		if (!si->ops->vf_reg_link_status_notifier(si))
+			return 0;
+
+		dev_warn(&ndev->dev,
+			 "Link status notifier registration failed\n");
+
+carrier_on:
 		netif_carrier_on(ndev);
 		return 0;
 	}
@@ -3011,6 +3031,7 @@ int enetc_open(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct enetc_bdr_resource *tx_res, *rx_res;
+	struct enetc_si *si = priv->si;
 	bool extended;
 	int err;
 
@@ -3051,8 +3072,15 @@ int enetc_open(struct net_device *ndev)
 err_alloc_rx:
 	enetc_free_tx_resources(tx_res, priv->num_tx_rings);
 err_alloc_tx:
-	if (priv->phylink)
+	if (priv->phylink) {
 		phylink_disconnect_phy(priv->phylink);
+	} else if (si->ops->vf_unreg_link_status_notifier &&
+		   test_bit(ENETC_LINK_STATUS_NOTIFIER_REGISTERED,
+			    &priv->flags)) {
+		if (si->ops->vf_unreg_link_status_notifier(si))
+			dev_warn(&ndev->dev,
+				 "Link status notifier unregistration failed\n");
+	}
 err_phy_connect:
 	enetc_free_irqs(priv);
 err_setup_irqs:
@@ -3093,6 +3121,7 @@ EXPORT_SYMBOL_GPL(enetc_stop);
 int enetc_close(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_si *si = priv->si;
 
 	enetc_stop(ndev);
 
@@ -3100,6 +3129,17 @@ int enetc_close(struct net_device *ndev)
 		phylink_stop(priv->phylink);
 		phylink_disconnect_phy(priv->phylink);
 	} else {
+		if (!si->ops->vf_unreg_link_status_notifier ||
+		    !test_bit(ENETC_LINK_STATUS_NOTIFIER_REGISTERED,
+			      &priv->flags))
+			goto carrier_off;
+
+		if (!si->ops->vf_unreg_link_status_notifier(si))
+			goto carrier_off;
+
+		dev_warn(&ndev->dev,
+			 "Link status notifier unregistration failed\n");
+carrier_off:
 		netif_carrier_off(ndev);
 	}
 
@@ -3794,6 +3834,13 @@ static const struct enetc_drvdata enetc_vf_data = {
 	.eth_ops = &enetc_vf_ethtool_ops,
 };
 
+static const struct enetc_drvdata enetc4_vf_data = {
+	.sysclk_freq = ENETC_CLK_333M,
+	.tx_csum = true,
+	.max_frags = ENETC4_MAX_SKB_FRAGS,
+	.eth_ops = &enetc_vf_ethtool_ops,
+};
+
 static const struct enetc_platform_info enetc_info[] = {
 	{ .revision = ENETC_REV_1_0,
 	  .dev_id = ENETC_DEV_ID_PF,
@@ -3807,6 +3854,10 @@ static const struct enetc_platform_info enetc_info[] = {
 	  .dev_id = ENETC_DEV_ID_VF,
 	  .data = &enetc_vf_data,
 	},
+	{ .revision = ENETC_REV_4_1,
+	  .dev_id = NXP_ENETC_VF_DEV_ID,
+	  .data = &enetc4_vf_data,
+	},
 	{
 	  .revision = ENETC_REV_4_3,
 	  .dev_id = NXP_ENETC_PPM_DEV_ID,
@@ -3816,6 +3867,10 @@ static const struct enetc_platform_info enetc_info[] = {
 	  .dev_id = NXP_ENETC_PF_DEV_ID,
 	  .data = &enetc4_pf_data,
 	},
+	{ .revision = ENETC_REV_4_3,
+	  .dev_id = NXP_ENETC_VF_DEV_ID,
+	  .data = &enetc4_vf_data,
+	},
 };
 
 int enetc_get_driver_data(struct enetc_si *si)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index d1e9d91300575..52bd502976ee8 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -25,6 +25,7 @@
 #define ENETC_CBD_DATA_MEM_ALIGN 64
 
 #define ENETC_MADDR_HASH_TBL_SZ	64
+#define ENETC_INT_NAME_MAX	(IFNAMSIZ + 8)
 
 enum enetc_mac_addr_type {UC, MC, MADDR_TYPE};
 
@@ -299,6 +300,10 @@ struct enetc_si_ops {
 	int (*set_rss_table)(struct enetc_si *si, const u32 *table, int count);
 	int (*setup_cbdr)(struct enetc_si *si);
 	void (*teardown_cbdr)(struct enetc_si *si);
+
+	/* VSI-specific hooks */
+	int (*vf_reg_link_status_notifier)(struct enetc_si *si);
+	int (*vf_unreg_link_status_notifier)(struct enetc_si *si);
 };
 
 /* PCI IEP device data */
@@ -333,6 +338,11 @@ struct enetc_si {
 
 	struct dentry *debugfs_root;
 	struct enetc_msg_swbd msg; /* Only valid for VSI */
+	struct workqueue_struct *workqueue;
+	struct work_struct msg_task;
+	char msg_int_name[ENETC_INT_NAME_MAX];
+
+	struct enetc_mac_filter mac_filter[MADDR_TYPE];
 };
 
 #define ENETC_SI_ALIGN	32
@@ -374,7 +384,6 @@ static inline bool enetc_is_pseudo_mac(struct enetc_si *si)
 }
 
 #define ENETC_MAX_NUM_TXQS	8
-#define ENETC_INT_NAME_MAX	(IFNAMSIZ + 8)
 
 struct enetc_int_vector {
 	void __iomem *rbier;
@@ -425,6 +434,7 @@ enum enetc_flags_bit {
 	ENETC_TX_ONESTEP_TSTAMP_IN_PROGRESS = 0,
 	ENETC_TX_DOWN,
 	ENETC_RXBDR_CM,
+	ENETC_LINK_STATUS_NOTIFIER_REGISTERED,
 };
 
 /* interrupt coalescing modes */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
index 5029038bf99fa..91af78ba4f742 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
@@ -6,24 +6,48 @@
 #include <linux/seq_file.h>
 #include <linux/string_choices.h>
 
-#include "enetc_pf.h"
+#include "enetc_pf_common.h"
 #include "enetc4_debugfs.h"
 
-static void enetc_show_si_mac_hash_filter(struct seq_file *s, int i)
+static void enetc_vf_state_lock(struct enetc_pf *pf, int vf_id)
 {
-	struct enetc_si *si = s->private;
-	struct enetc_hw *hw = &si->hw;
+	struct enetc_vf_state *vf_state;
+
+	if (vf_id < 0)
+		return;
+
+	vf_state = &pf->vf_state[vf_id];
+	mutex_lock(&vf_state->lock);
+}
+
+static void enetc_vf_state_unlock(struct enetc_pf *pf, int vf_id)
+{
+	struct enetc_vf_state *vf_state;
+
+	if (vf_id < 0)
+		return;
+
+	vf_state = &pf->vf_state[vf_id];
+	mutex_unlock(&vf_state->lock);
+}
+
+static void enetc_show_si_mac_hash_filter(struct seq_file *s, int si_id)
+{
+	struct enetc_pf *pf = enetc_si_priv(s->private);
+	struct enetc_hw *hw = &pf->si->hw;
 	u32 hash_h, hash_l;
 
-	hash_l = enetc_port_rd(hw, ENETC4_PSIUMHFR0(i));
-	hash_h = enetc_port_rd(hw, ENETC4_PSIUMHFR1(i));
+	enetc_vf_state_lock(pf, si_id - 1);
+	hash_l = enetc_port_rd(hw, ENETC4_PSIUMHFR0(si_id));
+	hash_h = enetc_port_rd(hw, ENETC4_PSIUMHFR1(si_id));
 	seq_printf(s, "SI %d unicast MAC hash filter: 0x%08x%08x\n",
-		   i, hash_h, hash_l);
+		   si_id, hash_h, hash_l);
 
-	hash_l = enetc_port_rd(hw, ENETC4_PSIMMHFR0(i));
-	hash_h = enetc_port_rd(hw, ENETC4_PSIMMHFR1(i));
+	hash_l = enetc_port_rd(hw, ENETC4_PSIMMHFR0(si_id));
+	hash_h = enetc_port_rd(hw, ENETC4_PSIMMHFR1(si_id));
 	seq_printf(s, "SI %d multicast MAC hash filter: 0x%08x%08x\n",
-		   i, hash_h, hash_l);
+		   si_id, hash_h, hash_l);
+	enetc_vf_state_unlock(pf, si_id - 1);
 }
 
 static int enetc_mac_filter_show(struct seq_file *s, void *data)
@@ -37,7 +61,11 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data)
 	int err = 0;
 	int i;
 
+	/* Prevent concurrent access from causing PSIPMMR to be modified */
+	enetc_pf_msg_lock(pf);
 	val = enetc_port_rd(hw, ENETC4_PSIPMMR);
+	enetc_pf_msg_unlock(pf);
+
 	for (i = 0; i < num_si; i++) {
 		seq_printf(s, "SI %d Unicast Promiscuous mode: %s\n", i,
 			   str_enabled_disabled(PSIPMMR_SI_MAC_UP(i) & val));
@@ -45,13 +73,12 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data)
 			   str_enabled_disabled(PSIPMMR_SI_MAC_MP(i) & val));
 	}
 
+	rtnl_lock();
 	/* MAC hash filter table */
 	for (i = 0; i < num_si; i++)
 		enetc_show_si_mac_hash_filter(s, i);
 
 	user = &pf->si->ntmp_user;
-	rtnl_lock();
-
 	if (bitmap_empty(user->maft_eid_bitmap, user->maft_num_entries))
 		goto unlock_rtnl;
 
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index 09025e7a2a3ae..e23d8d82d2ba9 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -12,6 +12,7 @@
 #define NXP_ENETC_VENDOR_ID		0x1131
 #define NXP_ENETC_PF_DEV_ID		0xe101
 #define NXP_ENETC_PPM_DEV_ID		0xe110
+#define NXP_ENETC_VF_DEV_ID		0xef00
 
 /**********************Station interface registers************************/
 /* Station interface LSO segmentation flag mask register 0/1 */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 9bb1004548abc..b4d76505bc034 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -12,11 +12,6 @@
 
 #define ENETC_SI_MAX_RING_NUM	8
 
-#define ENETC_MAC_FILTER_TYPE_UC	BIT(0)
-#define ENETC_MAC_FILTER_TYPE_MC	BIT(1)
-#define ENETC_MAC_FILTER_TYPE_ALL	(ENETC_MAC_FILTER_TYPE_UC | \
-					 ENETC_MAC_FILTER_TYPE_MC)
-
 static void enetc4_get_port_caps(struct enetc_pf *pf)
 {
 	struct enetc_hw *hw = &pf->si->hw;
@@ -137,7 +132,7 @@ static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
 static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf,
 					 struct netdev_hw_addr_list *uc)
 {
-	struct enetc_mac_filter *mac_filter = &pf->mac_filter[UC];
+	struct enetc_mac_filter *mac_filter = &pf->si->mac_filter[UC];
 	struct netdev_hw_addr *ha;
 	u64 hash;
 
@@ -172,7 +167,7 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
 
 	err = enetc4_pf_add_maft_entries(pf, uc);
 	if (!err) {
-		enetc_reset_mac_addr_filter(&pf->mac_filter[UC]);
+		enetc_reset_mac_addr_filter(&si->mac_filter[UC]);
 		enetc_set_si_uc_hash_filter(si, 0, 0);
 	}
 
@@ -182,7 +177,7 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
 static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf,
 					 struct netdev_hw_addr_list *mc)
 {
-	struct enetc_mac_filter *mac_filter = &pf->mac_filter[MC];
+	struct enetc_mac_filter *mac_filter = &pf->si->mac_filter[MC];
 	struct netdev_hw_addr *ha;
 	u64 hash;
 
@@ -217,19 +212,43 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type,
 		enetc4_pf_set_mc_hash_filter(pf, mc);
 }
 
+static void enetc4_pf_vf_flr_handler(struct enetc_pf *pf, int vf_id)
+{
+	struct enetc_vf_state *vf_state;
+	bool uc_promisc, mc_promisc;
+
+	vf_state = &pf->vf_state[vf_id];
+	mutex_lock(&vf_state->lock);
+
+	uc_promisc = !!(vf_state->flags & ENETC_VF_FLAG_UC_PROMISC);
+	mc_promisc = !!(vf_state->flags & ENETC_VF_FLAG_MC_PROMISC);
+
+	mutex_lock(&pf->msg_lock);
+	enetc_set_si_uc_promisc(pf->si, vf_id + 1, uc_promisc);
+	enetc_set_si_mc_promisc(pf->si, vf_id + 1, mc_promisc);
+	mutex_unlock(&pf->msg_lock);
+
+	mutex_unlock(&vf_state->lock);
+}
+
 static const struct enetc_pf_ops enetc4_pf_ops = {
 	.set_si_primary_mac = enetc4_pf_set_si_primary_mac,
 	.get_si_primary_mac = enetc4_pf_get_si_primary_mac,
+	.vf_flr_handler = enetc4_pf_vf_flr_handler,
 };
 
 static int enetc4_pf_struct_init(struct enetc_si *si)
 {
 	struct enetc_pf *pf = enetc_si_priv(si);
+	int err;
 
 	pf->si = si;
-	pf->total_vfs = pci_sriov_get_totalvfs(si->pdev);
 	pf->ops = &enetc4_pf_ops;
 
+	err = enetc_init_sriov_resources(pf);
+	if (err)
+		return err;
+
 	enetc4_get_port_caps(pf);
 	enetc4_get_psi_hw_features(si);
 
@@ -524,8 +543,10 @@ static int enetc4_pf_set_rx_mode(struct net_device *ndev,
 		type = ENETC_MAC_FILTER_TYPE_ALL;
 	}
 
+	enetc_pf_msg_lock(pf);
 	enetc_set_si_uc_promisc(si, 0, uc_promisc);
 	enetc_set_si_mc_promisc(si, 0, mc_promisc);
+	enetc_pf_msg_unlock(pf);
 
 	if (uc_promisc) {
 		enetc_set_si_uc_hash_filter(si, 0, 0);
@@ -574,6 +595,9 @@ static const struct net_device_ops enetc4_ndev_ops = {
 	.ndo_eth_ioctl		= enetc_ioctl,
 	.ndo_hwtstamp_get	= enetc_hwtstamp_get,
 	.ndo_hwtstamp_set	= enetc_hwtstamp_set,
+	.ndo_set_vf_trust	= enetc_pf_set_vf_trust,
+	.ndo_set_vf_mac		= enetc_pf_set_vf_mac,
+	.ndo_get_vf_config	= enetc_pf_get_vf_config,
 };
 
 static struct phylink_pcs *
@@ -894,6 +918,7 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config,
 	enetc4_set_rx_pause(pf, rx_pause);
 	enetc4_mac_tx_enable(pf);
 	enetc4_mac_rx_enable(pf);
+	enetc_pf_notify_vf_link_up(pf);
 }
 
 static void enetc4_pl_mac_link_down(struct phylink_config *config,
@@ -902,6 +927,7 @@ static void enetc4_pl_mac_link_down(struct phylink_config *config,
 {
 	struct enetc_pf *pf = phylink_to_enetc_pf(config);
 
+	enetc_pf_notify_vf_link_down(pf);
 	enetc4_mac_rx_graceful_stop(pf);
 	enetc4_mac_tx_graceful_stop(pf);
 }
@@ -1096,6 +1122,9 @@ static void enetc4_pf_remove(struct pci_dev *pdev)
 	struct enetc_si *si = pci_get_drvdata(pdev);
 	struct enetc_pf *pf = enetc_si_priv(si);
 
+	if (pf->num_vfs)
+		enetc_sriov_configure(pdev, 0);
+
 	enetc_remove_debugfs(si);
 	enetc4_pf_netdev_destroy(si);
 	enetc4_pf_free(pf);
@@ -1113,6 +1142,7 @@ static struct pci_driver enetc4_pf_driver = {
 	.id_table = enetc4_pf_id_table,
 	.probe = enetc4_pf_probe,
 	.remove = enetc4_pf_remove,
+	.sriov_configure = enetc_sriov_configure,
 };
 module_pci_driver(enetc4_pf_driver);
 
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index 07b7832f24276..7965dfd06f5f6 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -859,6 +859,9 @@ static int enetc_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc,
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	int i, j;
 
+	if (!is_enetc_rev1(priv->si))
+		return -EOPNOTSUPP;
+
 	switch (rxnfc->cmd) {
 	case ETHTOOL_GRXCLSRLCNT:
 		/* total number of entries */
@@ -903,6 +906,9 @@ static int enetc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc)
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	int err;
 
+	if (!is_enetc_rev1(priv->si))
+		return -EOPNOTSUPP;
+
 	switch (rxnfc->cmd) {
 	case ETHTOOL_SRXCLSRLINS:
 		if (rxnfc->fs.location >= priv->si->num_fs_entries)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 16da732dc5de8..2c9d9042eb0bb 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -80,6 +80,14 @@ static inline u32 enetc_vsi_set_msize(u32 size)
 #define ENETC_SIMSGSR_SET_MC(val) ((val) << 16)
 #define ENETC_SIMSGSR_GET_MC(val) ((val) >> 16)
 
+#define ENETC_PSIMSGSR		0x208
+/* n is VF index, which is less than 15 */
+#define  PSIMSGSR_MS(n)		BIT((n) + 1)
+#define  PSIMSGSR_MC		GENMASK(31, 16)
+
+#define ENETC_VSIMSGRR		0x208
+#define  VSIMSGRR_MC		GENMASK(31, 16)
+
 /* SI statistics */
 #define ENETC_SIROCT	0x300
 #define ENETC_SIRFRM	0x308
@@ -103,8 +111,26 @@ static inline u32 enetc_vsi_set_msize(u32 size)
 #define ENETC_SICAPR0	0x900
 #define ENETC_SICAPR1	0x904
 
+#define ENETC_VSIIER	0xa00
+#define  VSIIER_MRIE	BIT(9)
+
+#define ENETC_VSIIDR	0xa08
+#define  VSIIDR_MR	BIT(9)
+
 #define ENETC_PSIIER	0xa00
 #define ENETC_PSIIDR	0xa08
+
+/* VF FLR interrupt mask, n is the active number of VFs.
+ * It is available for ENETC_PSIIER and ENETC_PSIIDR registers.
+ */
+#define ENETC_VFFLR_MASK(n)	\
+	({ typeof(n) _n = (n); (_n) ? GENMASK(16 + (_n), 17) : 0; })
+
+/* VF FLR interrupt bit, n is VF index. It is available
+ * for ENETC_PSIIER and ENETC_PSIIDR registers.
+ */
+#define ENETC_VFFLR_BIT(n)	BIT(17 + (n))
+
 #define ENETC_SITXIDR	0xa18
 #define ENETC_SIRXIDR	0xa28
 #define ENETC_SIMSIVR	0xa30
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
index d9677da389892..200651e6ce85a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_mailbox.h
@@ -66,8 +66,8 @@
  * 2) PSI_TX_control: PSIMSGSR[MC] - for PSI to VSI notification messages
  * (async mode)
  *
- * Note that for some GET messages, there is no COOKIE field, and the CLASS
- * CODE field is expanded to 8 bits.
+ * Note that for some PSI-to-VSI messages, there is no COOKIE field, and the
+ * CLASS CODE field is expanded to 8 bits.
  */
 
 #ifndef __ENETC_MAILBOX_H
@@ -87,10 +87,26 @@
 /* The fileds of PSI-to-VSI message, the message is only 16-bit */
 #define ENETC_PF_MSG_COOKIE			GENMASK(3, 0)
 #define ENETC_PF_MSG_CLASS_CODE			GENMASK(7, 4)
-/* Extend the class code to 8-bit for GET messages without COOKIE */
+/* Extend the class code to 8-bit for PSI-to-VSI messages without COOKIE
+ * The class code for the following messages is 8-bit.
+ * 1. Get IP revision messages
+ * 2. Link status messages
+ * 3. Link speed messages
+ */
 #define ENETC_PF_MSG_CLASS_CODE_U8		GENMASK(7, 0)
 #define ENETC_PF_MSG_CLASS_ID			GENMASK(15, 8)
 
+#define ENETC_MAC_HASH_TABLE_SIZE_64		0
+#define ENETC_MSG_MAC_HASH_SIZE			GENMASK(5, 0)
+#define ENETC_MSG_MAC_TYPE			GENMASK(7, 6)
+#define  ENETC_MAC_FILTER_TYPE_UC		BIT(0)
+#define  ENETC_MAC_FILTER_TYPE_MC		BIT(1)
+#define  ENETC_MAC_FILTER_TYPE_ALL		(ENETC_MAC_FILTER_TYPE_UC | \
+						 ENETC_MAC_FILTER_TYPE_MC)
+
+#define ENETC_MSG_MAC_FLUSH_MACS		BIT(0)
+#define ENETC_MSG_MAC_PROMISC_MODE		BIT(1)
+
 enum enetc_msg_class_id {
 	/* Class ID for PSI-to-VSI messages */
 	ENETC_MSG_CLASS_ID_CMD_SUCCESS		= 1,
@@ -107,20 +123,66 @@ enum enetc_msg_class_id {
 
 	/* Common Class ID for PSI-to-VSI and VSI-to-PSI messages */
 	ENETC_MSG_CLASS_ID_MAC_FILTER		= 0x20,
+	ENETC_MSG_CLASS_ID_LINK_STATUS		= 0x80,
+	ENETC_MSG_CLASS_ID_LINK_SPEED		= 0x81,
 	ENETC_MSG_CLASS_ID_IP_REVISION		= 0xf0,
 };
 
 enum enetc_msg_mac_filter_cmd_id {
 	ENETC_MSG_SET_PRIMARY_MAC,
+	ENETC_MSG_SET_MAC_HASH_TABLE		= 3,
+	ENETC_MSG_SET_MAC_PROMISC_MODE		= 5,
 };
 
 enum enetc_msg_ip_revision_cmd_id {
 	ENETC_MSG_GET_IP_MN			= 1,
 };
 
+enum enetc_msg_link_status_cmd_id {
+	ENETC_MSG_GET_CURRENT_LINK_STATUS,
+	ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER,
+	ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER,
+};
+
+enum enetc_msg_link_speed_cmd_id {
+	ENETC_MSG_GET_CURRENT_LINK_SPEED,
+	/* The following command IDs are not currently supported */
+	ENETC_MSG_REGISTER_SPEED_CHANGE_NOTIFIER,
+	ENETC_MSG_UNREGISTER_SPEED_CHANGE_NOTIFIER,
+};
+
 /* Class-specific error return codes of MAC filter */
 enum enetc_mac_filter_class_code {
 	ENETC_MF_CLASS_CODE_INVALID_MAC,
+	ENETC_MF_CLASS_CODE_INVALID_TYPE	= 4,
+	/* Unicast Filter Is Denied */
+	ENETC_MF_CLASS_CODE_UCF_DENY		= 5,
+};
+
+/* Class-specific notifications/codes of link status */
+#define ENETC_CLASS_CODE_LINK_DOWN		BIT(0)
+#define ENETC_CLASS_CODE_TX_PAUSE_EN		BIT(1)
+
+/* Class-specific notifications/codes of link speed */
+enum enetc_link_speed_class_code {
+	ENETC_MSG_SPEED_UNKNOWN,
+	ENETC_MSG_SPEED_10M_HD,
+	ENETC_MSG_SPEED_10M_FD,
+	ENETC_MSG_SPEED_100M_HD,
+	ENETC_MSG_SPEED_100M_FD,
+	ENETC_MSG_SPEED_1000M,
+	ENETC_MSG_SPEED_2500M,
+	ENETC_MSG_SPEED_5G,
+	/* Do not add enumeration values for any speed greater than
+	 * 5Gbps. For any speed greater than 5Gbps, its speed class
+	 * code should follow the formula below.
+	 *
+	 * SPEED = (link_speed - 5000) / 1000 + ENETC_MSG_SPEED_5G
+	 *
+	 * The unit of link_speed should be Mbps, the max SPEED
+	 * should <= ENETC_MSG_SPEED_MAX.
+	 */
+	ENETC_MSG_SPEED_MAX = 0xff,
 };
 
 struct enetc_msg_swbd {
@@ -158,9 +220,45 @@ struct enetc_msg_mac_exact_filter {
 	struct enetc_mac_addr mac[];
 };
 
+/* message format of class_id 0x20 for hash MAC filter.
+ * cmd_id 0x3: set MAC hash table
+ */
+struct enetc_msg_mac_hash_filter {
+	struct enetc_msg_header hdr;
+	/* bit 0 ~ 5: ENETC_MSG_MAC_HASH_SIZE
+	 * bit 6~7: ENETC_MSG_MAC_TYPE
+	 */
+	u8 sz_type;
+	u8 resv[3];
+	u32 hash_tbl[];
+};
+
+/* message format of class_id 0x20 for MAC promiscuous mode.
+ * cmd_id 0x5: set MAC promiscuous mode
+ */
+struct enetc_msg_mac_promisc_mode {
+	struct enetc_msg_header hdr;
+	/* bit 0: ENETC_MSG_MAC_FLUSH_MACS
+	 * bit 1: ENETC_MSG_MAC_PROMISC_MODE
+	 * bit 6~7: ENETC_MSG_MAC_TYPE
+	 */
+	u8 config;
+	u8 resv[15];
+};
+
 /* The generic message format applies to the following messages:
  * Get IP revision message, class_id 0xf0.
  * cmd_id 1: get IP minor revision
+ *
+ * Link status message, class id 0x80.
+ * cmd_id 0x0: get the current link status
+ * cmd_id 0x1: register link status change notification
+ * cmd_id 0x2: unregister link status change notification
+ *
+ * Link speed message, class_id 0x81.
+ * cmd_id 0x0: get the current link speed.
+ * cmd_id 0x1: register link speed change notification, not supported yet
+ * cmd_id 0x2: unregister link speed change notification, not supported yet
  */
 struct enetc_msg_generic {
 	struct enetc_msg_header hdr;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_msg.c b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
index edc1277bb5860..55c23d4a73a86 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_msg.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_msg.c
@@ -7,24 +7,28 @@
 					   ENETC_MSG_CLASS_ID_CMD_SUCCESS)
 #define ENETC_PF_MSG_NOTSUPP	FIELD_PREP(ENETC_PF_MSG_CLASS_ID, \
 					   ENETC_MSG_CLASS_ID_CMD_NOT_SUPPORT)
-
-static void enetc_msg_disable_mr_int(struct enetc_pf *pf)
+#define ENETC_PF_MSG_PERM_DENY	FIELD_PREP(ENETC_PF_MSG_CLASS_ID, \
+					   ENETC_MSG_CLASS_ID_PERMISSION_DENY)
+#define ENETC_PF_MSG_INV_LEN	FIELD_PREP(ENETC_PF_MSG_CLASS_ID, \
+					   ENETC_MSG_CLASS_ID_INVALID_MSG_LEN)
+#define ENETC_PF_MSG_MF(code)	(FIELD_PREP(ENETC_PF_MSG_CLASS_ID, \
+					    ENETC_MSG_CLASS_ID_MAC_FILTER) | \
+				 FIELD_PREP(ENETC_PF_MSG_CLASS_CODE, (code)))
+
+static void enetc_disable_psiier_interrupts(struct enetc_pf *pf)
 {
 	struct enetc_hw *hw = &pf->si->hw;
-	u32 psiier;
-
-	psiier = enetc_rd(hw, ENETC_PSIIER) & ~ENETC_PSIMR_MASK(pf->num_vfs);
 
-	/* disable MR int source(s) */
-	enetc_wr(hw, ENETC_PSIIER, psiier);
+	enetc_wr(hw, ENETC_PSIIER, 0);
 }
 
-static void enetc_msg_enable_mr_int(struct enetc_pf *pf)
+static void enetc_enable_psiier_interrupts(struct enetc_pf *pf)
 {
+	u32 psiier = ENETC_PSIMR_MASK(pf->num_vfs);
 	struct enetc_hw *hw = &pf->si->hw;
-	u32 psiier;
 
-	psiier = enetc_rd(hw, ENETC_PSIIER) | ENETC_PSIMR_MASK(pf->num_vfs);
+	if (pf->ops->vf_flr_handler)
+		psiier |= ENETC_VFFLR_MASK(pf->num_vfs);
 
 	enetc_wr(hw, ENETC_PSIIER, psiier);
 }
@@ -34,8 +38,8 @@ static irqreturn_t enetc_msg_psi_msix(int irq, void *data)
 	struct enetc_si *si = (struct enetc_si *)data;
 	struct enetc_pf *pf = enetc_si_priv(si);
 
-	enetc_msg_disable_mr_int(pf);
-	schedule_work(&pf->msg_task);
+	enetc_disable_psiier_interrupts(pf);
+	schedule_work(&si->msg_task);
 
 	return IRQ_HANDLED;
 }
@@ -61,31 +65,186 @@ static u16 enetc_msg_set_vf_primary_mac_addr(struct enetc_pf *pf, int vf_id,
 	struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
 	struct enetc_msg_mac_exact_filter *msg = vf_msg;
 	struct device *dev = &pf->si->pdev->dev;
+	u16 pf_msg = ENETC_PF_MSG_SUCCESS;
 	char *addr = msg->mac[0].addr;
 
+	mutex_lock(&vf_state->lock);
+
+	/* Untrusted VFs cannot set their MAC addresses by the mailbox
+	 * messages.
+	 */
+	if (!(vf_state->flags & ENETC_VF_FLAG_TRUSTED)) {
+		pf_msg = ENETC_PF_MSG_PERM_DENY;
+		goto vf_state_unlock;
+	}
+
 	if (!is_valid_ether_addr(addr)) {
 		dev_err_ratelimited(dev, "VF%d attempted to set invalid MAC\n",
 				    vf_id);
-		return (FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
-				   ENETC_MSG_CLASS_ID_MAC_FILTER) |
-			FIELD_PREP(ENETC_PF_MSG_CLASS_CODE,
-				   ENETC_MF_CLASS_CODE_INVALID_MAC));
+		pf_msg = ENETC_PF_MSG_MF(ENETC_MF_CLASS_CODE_INVALID_MAC);
+		goto vf_state_unlock;
 	}
 
-	mutex_lock(&vf_state->lock);
+	/* PF has higher privileges. If PF has already modified the MAC
+	 * address for VF through .ndo_set_vf_mac() interface, VF is not
+	 * allowed to set its MAC address via mailbox messages, even if
+	 * it is trusted.
+	 */
 	if (vf_state->flags & ENETC_VF_FLAG_PF_SET_MAC) {
-		mutex_unlock(&vf_state->lock);
 		dev_err_ratelimited(dev,
 				    "VF%d attempted to override PF set MAC\n",
 				    vf_id);
-		return FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
-				  ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);
+		pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+				    ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED);
+		goto vf_state_unlock;
 	}
 
 	enetc_set_si_hw_addr(pf, vf_id + 1, addr);
+
+vf_state_unlock:
+	mutex_unlock(&vf_state->lock);
+
+	return pf_msg;
+}
+
+static u16 enetc_msg_set_vf_mac_hash_filter(struct enetc_pf *pf, int vf_id,
+					    void *vf_msg)
+{
+	struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
+	struct enetc_msg_mac_hash_filter *msg = vf_msg;
+	u16 pf_msg = ENETC_PF_MSG_SUCCESS;
+	struct enetc_si *si = pf->si;
+	int si_id = vf_id + 1;
+	u64 uc_hash, mc_hash;
+	bool trusted;
+	int type;
+
+	/* Currently, hardware only supports 64 bits table size */
+	if (FIELD_GET(ENETC_MSG_MAC_HASH_SIZE, msg->sz_type) !=
+	    ENETC_MAC_HASH_TABLE_SIZE_64)
+		return ENETC_PF_MSG_NOTSUPP;
+
+	mutex_lock(&vf_state->lock);
+
+	/* For an untrusted VF, unicast MAC hash filtering is not permitted.
+	 * For multicast, the MAC hash filter is strictly limited to a maximum
+	 * of 8 bits to satisfy its basic multicast communication requirements
+	 * while preventing potential network abuse.
+	 */
+	trusted = !!(vf_state->flags & ENETC_VF_FLAG_TRUSTED);
+	type = FIELD_GET(ENETC_MSG_MAC_TYPE, msg->sz_type);
+	switch (type) {
+	case ENETC_MAC_FILTER_TYPE_UC:
+		if (!trusted) {
+			pf_msg = ENETC_PF_MSG_PERM_DENY;
+			goto vf_state_unlock;
+		}
+
+		uc_hash = (u64)msg->hash_tbl[1] << 32 | msg->hash_tbl[0];
+		enetc_set_si_uc_hash_filter(si, si_id, uc_hash);
+		break;
+	case ENETC_MAC_FILTER_TYPE_MC:
+		mc_hash = (u64)msg->hash_tbl[1] << 32 | msg->hash_tbl[0];
+		if (!trusted &&
+		    hweight64(mc_hash) > ENETC_VF_MC_HASH_BITS_MAX) {
+			pf_msg = ENETC_PF_MSG_PERM_DENY;
+			goto vf_state_unlock;
+		}
+
+		enetc_set_si_mc_hash_filter(si, si_id, mc_hash);
+		break;
+	case ENETC_MAC_FILTER_TYPE_ALL:
+		if (!msg->hdr.len) {
+			pf_msg = ENETC_PF_MSG_INV_LEN;
+			goto vf_state_unlock;
+		}
+
+		uc_hash = (u64)msg->hash_tbl[1] << 32 | msg->hash_tbl[0];
+		mc_hash = (u64)msg->hash_tbl[3] << 32 | msg->hash_tbl[2];
+
+		if (!trusted &&
+		    (hweight64(mc_hash) <= ENETC_VF_MC_HASH_BITS_MAX)) {
+			enetc_set_si_mc_hash_filter(si, si_id, mc_hash);
+			pf_msg = ENETC_PF_MSG_MF(ENETC_MF_CLASS_CODE_UCF_DENY);
+			goto vf_state_unlock;
+		}
+
+		if (!trusted) {
+			pf_msg = ENETC_PF_MSG_PERM_DENY;
+			goto vf_state_unlock;
+		}
+
+		enetc_set_si_uc_hash_filter(si, si_id, uc_hash);
+		enetc_set_si_mc_hash_filter(si, si_id, mc_hash);
+		break;
+	default:
+		pf_msg = ENETC_PF_MSG_MF(ENETC_MF_CLASS_CODE_INVALID_TYPE);
+	}
+
+vf_state_unlock:
+	mutex_unlock(&vf_state->lock);
+
+	return pf_msg;
+}
+
+static u16 enetc_msg_set_vf_mac_promisc_mode(struct enetc_pf *pf, int vf_id,
+					     void *vf_msg)
+{
+	struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
+	struct enetc_msg_mac_promisc_mode *msg = vf_msg;
+	u16 pf_msg = ENETC_PF_MSG_SUCCESS;
+	struct enetc_si *si = pf->si;
+	bool promisc, flush_macs;
+	int si_id = vf_id + 1;
+	int type;
+
+	flush_macs = !!(msg->config & ENETC_MSG_MAC_FLUSH_MACS);
+	type = FIELD_GET(ENETC_MSG_MAC_TYPE, msg->config);
+	if (!type)
+		return ENETC_PF_MSG_MF(ENETC_MF_CLASS_CODE_INVALID_TYPE);
+
+	mutex_lock(&vf_state->lock);
+
+	promisc = !!(msg->config & ENETC_MSG_MAC_PROMISC_MODE);
+	if (promisc && !(vf_state->flags & ENETC_VF_FLAG_TRUSTED)) {
+		pf_msg = ENETC_PF_MSG_PERM_DENY;
+		goto vf_state_unlock;
+	}
+
+	if (type & ENETC_MAC_FILTER_TYPE_UC) {
+		if (promisc)
+			vf_state->flags |= ENETC_VF_FLAG_UC_PROMISC;
+		else
+			vf_state->flags &= ~ENETC_VF_FLAG_UC_PROMISC;
+	}
+
+	if (type & ENETC_MAC_FILTER_TYPE_MC) {
+		if (promisc)
+			vf_state->flags |= ENETC_VF_FLAG_MC_PROMISC;
+		else
+			vf_state->flags &= ~ENETC_VF_FLAG_MC_PROMISC;
+	}
+
+	mutex_lock(&pf->msg_lock);
+
+	if (type & ENETC_MAC_FILTER_TYPE_UC)
+		enetc_set_si_uc_promisc(si, si_id, promisc);
+
+	if (type & ENETC_MAC_FILTER_TYPE_MC)
+		enetc_set_si_mc_promisc(si, si_id, promisc);
+
+	mutex_unlock(&pf->msg_lock);
+
+	if ((type & ENETC_MAC_FILTER_TYPE_UC) && flush_macs)
+		enetc_set_si_uc_hash_filter(si, si_id, 0);
+
+	if ((type & ENETC_MAC_FILTER_TYPE_MC) && flush_macs)
+		enetc_set_si_mc_hash_filter(si, si_id, 0);
+
+vf_state_unlock:
 	mutex_unlock(&vf_state->lock);
 
-	return ENETC_PF_MSG_SUCCESS;
+	return pf_msg;
 }
 
 static u16 enetc_msg_handle_mac_filter(struct enetc_pf *pf, int vf_id,
@@ -96,6 +255,10 @@ static u16 enetc_msg_handle_mac_filter(struct enetc_pf *pf, int vf_id,
 	switch (msg_hdr->cmd_id) {
 	case ENETC_MSG_SET_PRIMARY_MAC:
 		return enetc_msg_set_vf_primary_mac_addr(pf, vf_id, vf_msg);
+	case ENETC_MSG_SET_MAC_HASH_TABLE:
+		return enetc_msg_set_vf_mac_hash_filter(pf, vf_id, vf_msg);
+	case ENETC_MSG_SET_MAC_PROMISC_MODE:
+		return enetc_msg_set_vf_mac_promisc_mode(pf, vf_id, vf_msg);
 	default:
 		return ENETC_PF_MSG_NOTSUPP;
 	}
@@ -116,6 +279,241 @@ static u16 enetc_msg_handle_ip_revision(struct enetc_pf *pf, void *vf_msg)
 	}
 }
 
+static void enetc_pf_reply_msg(struct enetc_hw *hw, int vf_id, u16 pf_msg)
+{
+	/* w1c to clear the corresponding VF MR bit */
+	enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIMR_BIT(vf_id));
+	enetc_wr(hw, ENETC_PSIMSGRR, ENETC_SIMSGSR_SET_MC(pf_msg) |
+		 ENETC_PSIMR_BIT(vf_id));
+}
+
+static u16 enetc_build_link_status_msg(struct enetc_ndev_priv *priv,
+				       bool link_up)
+{
+	u8 status = 0;
+
+	if (link_up) {
+		spin_lock(&priv->si->gen_lock);
+		if (test_bit(ENETC_RXBDR_CM, &priv->flags))
+			status |= ENETC_CLASS_CODE_TX_PAUSE_EN;
+		spin_unlock(&priv->si->gen_lock);
+	} else {
+		status |= ENETC_CLASS_CODE_LINK_DOWN;
+	}
+
+	return FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+			  ENETC_MSG_CLASS_ID_LINK_STATUS) |
+	       FIELD_PREP(ENETC_PF_MSG_CLASS_CODE_U8, status);
+}
+
+static void enetc_msg_get_link_status(struct enetc_pf *pf, int vf_id)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev);
+	u16 pf_msg;
+
+	mutex_lock(&pf->msg_lock);
+	pf_msg = enetc_build_link_status_msg(priv, pf->link_up);
+	enetc_pf_reply_msg(&pf->si->hw, vf_id, pf_msg);
+	mutex_unlock(&pf->msg_lock);
+}
+
+static int enetc_pf_send_msg(struct enetc_pf *pf, u32 msg_code, u16 ms_mask)
+{
+	struct enetc_hw *hw = &pf->si->hw;
+	u16 old_ms_mask = ms_mask;
+	u16 ms_status;
+	u32 val;
+
+	/* The MS bit is set, indicating that the corresponding VF has not
+	 * read the last message, PF cannot send new message to the VF. To
+	 * avoid sending messages to such a VF, the bit corresponding to VF
+	 * is cleared from ms_mask. Because the MS bit can only be written
+	 * as 1, writing a 0 has no effect. Writing a 1 when the bit is
+	 * already set is undefined.
+	 */
+	ms_status = enetc_rd(hw, ENETC_PSIMSGSR) & 0xffff;
+	ms_mask &= ~ms_status;
+	if (!ms_mask)
+		return -EIO;
+
+	if (ms_mask != old_ms_mask)
+		dev_warn_ratelimited(&pf->si->pdev->dev,
+				     "PF cannot send message to VF(s) 0x%x\n",
+				     ms_mask ^ old_ms_mask);
+
+	enetc_wr(hw, ENETC_PSIMSGSR,
+		 FIELD_PREP(PSIMSGSR_MC, msg_code) | ms_mask);
+
+	return read_poll_timeout(enetc_rd, val, !(val & ms_mask), 1000,
+				 200000, false, hw, ENETC_PSIMSGSR);
+}
+
+static void enetc_msg_notify_vf_link_status(struct enetc_pf *pf, u16 ms_mask)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev);
+	u16 pf_msg;
+
+	pf_msg = enetc_build_link_status_msg(priv, pf->link_up);
+	if (enetc_pf_send_msg(pf, pf_msg, ms_mask))
+		dev_err_ratelimited(&pf->si->pdev->dev,
+				    "PF notifies link status failed\n");
+}
+
+static void enetc_msg_register_link_status_notifier(struct enetc_pf *pf,
+						    int vf_id)
+{
+	u16 pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+				ENETC_MSG_CLASS_ID_CMD_SUCCESS);
+
+	mutex_lock(&pf->msg_lock);
+
+	enetc_pf_reply_msg(&pf->si->hw, vf_id, pf_msg);
+
+	/* SR-IOV is being disabled if pf->sriov_enabled is false, so no
+	 * need to set link_status_ms_mask and notify the link status.
+	 */
+	if (!pf->sriov_enabled)
+		goto msg_unlock;
+
+	pf->link_status_ms_mask |= PSIMSGSR_MS(vf_id);
+
+	/* Notify VF the current link status */
+	enetc_msg_notify_vf_link_status(pf, PSIMSGSR_MS(vf_id));
+
+msg_unlock:
+	mutex_unlock(&pf->msg_lock);
+}
+
+static void enetc_msg_unregister_link_status_notifier(struct enetc_pf *pf,
+						      int vf_id)
+{
+	u16 pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+				ENETC_MSG_CLASS_ID_CMD_SUCCESS);
+
+	mutex_lock(&pf->msg_lock);
+
+	pf->link_status_ms_mask &= ~PSIMSGSR_MS(vf_id);
+	enetc_pf_reply_msg(&pf->si->hw, vf_id, pf_msg);
+
+	mutex_unlock(&pf->msg_lock);
+}
+
+static u16 enetc_msg_handle_link_status(struct enetc_pf *pf, int vf_id,
+					void *vf_msg)
+{
+	struct enetc_msg_header *msg_hdr = vf_msg;
+
+	switch (msg_hdr->cmd_id) {
+	case ENETC_MSG_GET_CURRENT_LINK_STATUS:
+		/* Currently, this message is intended only for
+		 * DPDK-owned VFs.
+		 */
+		enetc_msg_get_link_status(pf, vf_id);
+		break;
+	case ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER:
+		enetc_msg_register_link_status_notifier(pf, vf_id);
+		break;
+	case ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER:
+		enetc_msg_unregister_link_status_notifier(pf, vf_id);
+		break;
+	default:
+		return ENETC_PF_MSG_NOTSUPP;
+	}
+
+	return 0;
+}
+
+static u16 enetc_build_link_speed_msg(int speed, int duplex)
+{
+	u32 speed_code = ENETC_MSG_SPEED_UNKNOWN;
+
+	switch (speed) {
+	case SPEED_10:
+		if (duplex == DUPLEX_HALF)
+			speed_code = ENETC_MSG_SPEED_10M_HD;
+		else if (duplex == DUPLEX_FULL)
+			speed_code = ENETC_MSG_SPEED_10M_FD;
+		break;
+	case SPEED_100:
+		if (duplex == DUPLEX_HALF)
+			speed_code = ENETC_MSG_SPEED_100M_HD;
+		else if (duplex == DUPLEX_FULL)
+			speed_code = ENETC_MSG_SPEED_100M_FD;
+		break;
+	case SPEED_1000:
+		speed_code = ENETC_MSG_SPEED_1000M;
+		break;
+	case SPEED_2500:
+		speed_code = ENETC_MSG_SPEED_2500M;
+		break;
+	case SPEED_5000:
+		speed_code = ENETC_MSG_SPEED_5G;
+		break;
+	default:
+		if (speed < SPEED_5000)
+			break;
+
+		speed_code = (speed - SPEED_5000) / SPEED_1000 +
+			     ENETC_MSG_SPEED_5G;
+		if (speed_code > ENETC_MSG_SPEED_MAX)
+			speed_code = ENETC_MSG_SPEED_UNKNOWN;
+	}
+
+	return FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
+			  ENETC_MSG_CLASS_ID_LINK_SPEED) |
+	       FIELD_PREP(ENETC_PF_MSG_CLASS_CODE_U8, speed_code);
+}
+
+static u16 enetc_msg_get_link_speed(struct enetc_pf *pf, int vf_id)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev);
+	struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
+	struct ethtool_link_ksettings link_info = {};
+
+	/* A malicious or malfunctioning VM could potentially spam these
+	 * messages in a tight loop causing global rtnl_lock contention,
+	 * which may severely starve other processes on the host that
+	 * require rtnl_lock for routine network configuration, resulting
+	 * in a system-wide control-plane denial of service. Therefore,
+	 * we expect the VF query for link speed to be trusted. There's no
+	 * need to consider the transition from trusted to untrusted here,
+	 * as this won't cause rtnl_lock() to be called frequently.
+	 */
+	mutex_lock(&vf_state->lock);
+	if (!(vf_state->flags & ENETC_VF_FLAG_TRUSTED)) {
+		mutex_unlock(&vf_state->lock);
+
+		return ENETC_PF_MSG_PERM_DENY;
+	}
+	mutex_unlock(&vf_state->lock);
+
+	rtnl_lock();
+	phylink_ethtool_ksettings_get(priv->phylink, &link_info);
+	rtnl_unlock();
+
+	return enetc_build_link_speed_msg(link_info.base.speed,
+					  link_info.base.duplex);
+}
+
+static u16 enetc_msg_handle_link_speed(struct enetc_pf *pf, int vf_id,
+				       void *vf_msg)
+{
+	struct enetc_msg_header *msg_hdr = vf_msg;
+
+	switch (msg_hdr->cmd_id) {
+	case ENETC_MSG_GET_CURRENT_LINK_SPEED:
+		return enetc_msg_get_link_speed(pf, vf_id);
+	case ENETC_MSG_REGISTER_SPEED_CHANGE_NOTIFIER:
+	case ENETC_MSG_UNREGISTER_SPEED_CHANGE_NOTIFIER:
+	default:
+		return ENETC_PF_MSG_NOTSUPP;
+	}
+}
+
+/* If *pf_msg is set to 0, it means that PF has responded to VF in
+ * enetc_msg_handle_rxmsg() through enetc_pf_reply_msg(), which also
+ * clears the corresponding VF MR bit in PSIIDR.
+ */
 static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
 				   u16 *pf_msg)
 {
@@ -128,8 +526,7 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
 	if (msg_size > ENETC_DEFAULT_MSG_SIZE) {
 		dev_err_ratelimited(dev,
 				    "Invalid message size: %u\n", msg_size);
-		*pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
-				     ENETC_MSG_CLASS_ID_INVALID_MSG_LEN);
+		*pf_msg = ENETC_PF_MSG_INV_LEN;
 		return;
 	}
 
@@ -147,6 +544,14 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
 	}
 
 	memcpy(msg, msg_swbd->vaddr, msg_size);
+	msg_hdr = (struct enetc_msg_header *)msg;
+
+	/* Check message length whether is changed */
+	if (ENETC_MSG_SIZE(msg_hdr->len) != msg_size) {
+		*pf_msg = ENETC_PF_MSG_INV_LEN;
+		goto free_msg;
+	}
+
 	if (!enetc_msg_check_crc16(msg, msg_size)) {
 		dev_err_ratelimited(dev, "VSI to PSI Message CRC16 error\n");
 		*pf_msg = FIELD_PREP(ENETC_PF_MSG_CLASS_ID,
@@ -157,7 +562,6 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
 
 	/* Default to not supported */
 	*pf_msg = ENETC_PF_MSG_NOTSUPP;
-	msg_hdr = (struct enetc_msg_header *)msg;
 
 	/* Currently, asynchronous actions are not supported */
 	if (FIELD_GET(ENETC_VF_MSG_COOKIE, msg_hdr->cookie)) {
@@ -191,6 +595,12 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
 	case ENETC_MSG_CLASS_ID_IP_REVISION:
 		*pf_msg = enetc_msg_handle_ip_revision(pf, msg);
 		break;
+	case ENETC_MSG_CLASS_ID_LINK_STATUS:
+		*pf_msg = enetc_msg_handle_link_status(pf, vf_id, msg);
+		break;
+	case ENETC_MSG_CLASS_ID_LINK_SPEED:
+		*pf_msg = enetc_msg_handle_link_speed(pf, vf_id, msg);
+		break;
 	default:
 		dev_err_ratelimited(dev,
 				    "Unsupported message class ID: 0x%x\n",
@@ -201,21 +611,46 @@ static void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int vf_id,
 	kfree(msg);
 }
 
-static void enetc_msg_task(struct work_struct *work)
+static void enetc_vf_flr_handler(struct enetc_pf *pf)
 {
-	struct enetc_pf *pf = container_of(work, struct enetc_pf, msg_task);
-	u32 mr_mask = ENETC_PSIMR_MASK(pf->num_vfs);
+	u32 flr_mask = ENETC_VFFLR_MASK(pf->num_vfs);
 	struct enetc_hw *hw = &pf->si->hw;
-	u32 mr_status;
+	u32 flr_status;
+
+	if (!pf->ops->vf_flr_handler)
+		return;
+
+	flr_status = enetc_rd(hw, ENETC_PSIIDR) & flr_mask;
+	if (!flr_status)
+		return;
+
+	for (int i = 0; i < pf->num_vfs; i++) {
+		if (!(ENETC_VFFLR_BIT(i) & flr_status))
+			continue;
+
+		/* Clear FLR interrupt status, W1C */
+		enetc_wr(hw, ENETC_PSIIDR, ENETC_VFFLR_BIT(i));
+		pf->ops->vf_flr_handler(pf, i);
+	}
+}
+
+static void enetc_msg_task(struct work_struct *work)
+{
+	struct enetc_si *si = container_of(work, struct enetc_si, msg_task);
+	struct enetc_pf *pf = enetc_si_priv(si);
+	struct enetc_hw *hw = &si->hw;
+	u32 mr_status, mr_mask;
 	int i;
 
+	enetc_vf_flr_handler(pf);
+
+	mr_mask = ENETC_PSIMR_MASK(pf->num_vfs);
 	mr_status = (enetc_rd(hw, ENETC_PSIMSGRR) & mr_mask) |
 		    (enetc_rd(hw, ENETC_PSIIDR) & mr_mask);
 	if (!mr_status)
 		goto out;
 
 	for (i = 0; i < pf->num_vfs; i++) {
-		u32 psimsgrr;
 		u16 msg_code;
 
 		if (!(ENETC_PSIMR_BIT(i) & mr_status))
@@ -223,16 +658,18 @@ static void enetc_msg_task(struct work_struct *work)
 
 		enetc_msg_handle_rxmsg(pf, i, &msg_code);
 
-		/* w1c to clear the corresponding VF MR bit */
-		enetc_wr(hw, ENETC_PSIIDR, ENETC_PSIMR_BIT(i));
+		/* If msg_code is 0, it means that PF has responded to VF
+		 * in enetc_msg_handle_rxmsg() through enetc_pf_reply_msg(),
+		 * which also clears the corresponding VF MR bit in PSIIDR.
+		 */
+		if (!msg_code)
+			continue;
 
-		psimsgrr = ENETC_SIMSGSR_SET_MC(msg_code);
-		psimsgrr |= ENETC_PSIMR_BIT(i); /* w1c */
-		enetc_wr(hw, ENETC_PSIMSGRR, psimsgrr);
+		enetc_pf_reply_msg(hw, i, msg_code);
 	}
 
 out:
-	enetc_msg_enable_mr_int(pf);
+	enetc_enable_psiier_interrupts(pf);
 }
 
 /* Init */
@@ -291,13 +728,13 @@ static int enetc_msg_psi_init(struct enetc_pf *pf)
 	}
 
 	/* initialize PSI mailbox */
-	INIT_WORK(&pf->msg_task, enetc_msg_task);
+	INIT_WORK(&si->msg_task, enetc_msg_task);
 
 	/* register message passing interrupt handler */
-	snprintf(pf->msg_int_name, sizeof(pf->msg_int_name), "%s-vfmsg",
+	snprintf(si->msg_int_name, sizeof(si->msg_int_name), "%s-vfmsg",
 		 si->ndev->name);
 	vector = pci_irq_vector(si->pdev, ENETC_SI_INT_IDX);
-	err = request_irq(vector, enetc_msg_psi_msix, 0, pf->msg_int_name, si);
+	err = request_irq(vector, enetc_msg_psi_msix, 0, si->msg_int_name, si);
 	if (err) {
 		dev_err(&si->pdev->dev,
 			"PSI messaging: request_irq() failed!\n");
@@ -307,8 +744,8 @@ static int enetc_msg_psi_init(struct enetc_pf *pf)
 	/* set one IRQ entry for PSI message receive notification (SI int) */
 	enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX);
 
-	/* enable MR interrupts */
-	enetc_msg_enable_mr_int(pf);
+	/* enable PSIIER interrupts */
+	enetc_enable_psiier_interrupts(pf);
 
 	return 0;
 
@@ -319,24 +756,59 @@ static int enetc_msg_psi_init(struct enetc_pf *pf)
 	return err;
 }
 
+static void enetc_msg_clear_vf_config(struct enetc_pf *pf, int vf_id)
+{
+	struct enetc_vf_state *vf_state = &pf->vf_state[vf_id];
+	struct enetc_si *si = pf->si;
+	int si_id = vf_id + 1;
+
+	/* For ENETC v1, we only support setting the VF's MAC address via
+	 * VSI-to-PSI messages, so there is no configuration to clear.
+	 */
+	if (is_enetc_rev1(si))
+		return;
+
+	mutex_lock(&vf_state->lock);
+
+	/* VF may set these flags by mailbox messages, so need to clear these
+	 * flags when enetc_msg_psi_free() is called. PF-set flags (TRUSTED,
+	 * PF_SET_MAC) are not cleared, because these flags are unrelated to
+	 * whether SR-IOV is enabled or disabled.
+	 */
+	vf_state->flags &= ~(ENETC_VF_FLAG_UC_PROMISC |
+			     ENETC_VF_FLAG_MC_PROMISC);
+
+	mutex_lock(&pf->msg_lock);
+	enetc_set_si_uc_promisc(si, si_id, false);
+	enetc_set_si_mc_promisc(si, si_id, false);
+	mutex_unlock(&pf->msg_lock);
+
+	enetc_set_si_uc_hash_filter(si, si_id, 0);
+	enetc_set_si_mc_hash_filter(si, si_id, 0);
+
+	mutex_unlock(&vf_state->lock);
+}
+
 static void enetc_msg_psi_free(struct enetc_pf *pf)
 {
 	struct enetc_si *si = pf->si;
 	int i;
 
-	/* disable MR interrupts */
-	enetc_msg_disable_mr_int(pf);
+	/* disable PSIIER interrupts */
+	enetc_disable_psiier_interrupts(pf);
 
 	/* de-register message passing interrupt handler */
 	free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si);
 
-	cancel_work_sync(&pf->msg_task);
+	cancel_work_sync(&si->msg_task);
 
-	/* MR interrupts may be re-enabled by workqueue */
-	enetc_msg_disable_mr_int(pf);
+	/* PSIIER interrupts may be re-enabled by workqueue */
+	enetc_disable_psiier_interrupts(pf);
 
-	for (i = 0; i < pf->num_vfs; i++)
+	for (i = 0; i < pf->num_vfs; i++) {
 		enetc_msg_free_mbx(si, i);
+		enetc_msg_clear_vf_config(pf, i);
+	}
 }
 
 int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
@@ -346,6 +818,11 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
 	int err;
 
 	if (!num_vfs) {
+		mutex_lock(&pf->msg_lock);
+		pf->sriov_enabled = false;
+		pf->link_status_ms_mask = 0;
+		mutex_unlock(&pf->msg_lock);
+
 		pci_disable_sriov(pdev);
 		enetc_msg_psi_free(pf);
 		pf->num_vfs = 0;
@@ -358,16 +835,31 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
 			goto err_msg_psi;
 		}
 
+		/* As PCI SR-IOV is not enabled at the moment, there is no
+		 * concurrent access to sriov_enabled. So no need to use
+		 * msg_lock to protect sriov_enabled.
+		 */
+		pf->sriov_enabled = true;
 		err = pci_enable_sriov(pdev, num_vfs);
 		if (err) {
 			dev_err(&pdev->dev, "pci_enable_sriov err %d\n", err);
 			goto err_en_sriov;
 		}
+
 	}
 
 	return num_vfs;
 
 err_en_sriov:
+	/* If pci_enable_sriov() fails after partially creating VFs, a VF
+	 * driver that successfully bound to one of the created VFs could
+	 * have sent a registration message, setting its bit in
+	 * link_status_ms_mask.
+	 */
+	mutex_lock(&pf->msg_lock);
+	pf->sriov_enabled = false;
+	pf->link_status_ms_mask = 0;
+	mutex_unlock(&pf->msg_lock);
 	enetc_msg_psi_free(pf);
 err_msg_psi:
 	pf->num_vfs = 0;
@@ -375,3 +867,34 @@ int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
 	return err;
 }
 EXPORT_SYMBOL_GPL(enetc_sriov_configure);
+
+static void enetc_pf_notify_vf_link_status(struct enetc_pf *pf,
+					   bool link_up)
+{
+	/* pf->msg_lock is initialized when pf->total_vfs is not 0 */
+	if (!pf->total_vfs)
+		return;
+
+	mutex_lock(&pf->msg_lock);
+
+	pf->link_up = link_up;
+	if (!pf->link_status_ms_mask)
+		goto msg_unlock;
+
+	enetc_msg_notify_vf_link_status(pf, pf->link_status_ms_mask);
+
+msg_unlock:
+	mutex_unlock(&pf->msg_lock);
+}
+
+void enetc_pf_notify_vf_link_up(struct enetc_pf *pf)
+{
+	enetc_pf_notify_vf_link_status(pf, true);
+}
+EXPORT_SYMBOL_GPL(enetc_pf_notify_vf_link_up);
+
+void enetc_pf_notify_vf_link_down(struct enetc_pf *pf)
+{
+	enetc_pf_notify_vf_link_status(pf, false);
+}
+EXPORT_SYMBOL_GPL(enetc_pf_notify_vf_link_down);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 55c07c528f223..d77a07cece28b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -60,10 +60,9 @@ static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,
 	filter->mac_addr_cnt++;
 }
 
-static void enetc_sync_mac_filters(struct enetc_pf *pf)
+static void enetc_sync_mac_filters(struct enetc_si *si)
 {
-	struct enetc_mac_filter *f = pf->mac_filter;
-	struct enetc_si *si = pf->si;
+	struct enetc_mac_filter *f = si->mac_filter;
 	int i, pos;
 
 	pos = EMETC_MAC_ADDR_FILT_RES;
@@ -115,9 +114,9 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
 static void enetc_pf_set_rx_mode(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_pf *pf = enetc_si_priv(priv->si);
 	bool uprom = false, mprom = false;
 	struct enetc_mac_filter *filter;
+	struct enetc_si *si = priv->si;
 	struct netdev_hw_addr *ha;
 	bool em;
 
@@ -133,7 +132,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
 	/* first 2 filter entries belong to PF */
 	if (!uprom) {
 		/* Update unicast filters */
-		filter = &pf->mac_filter[UC];
+		filter = &si->mac_filter[UC];
 		enetc_reset_mac_addr_filter(filter);
 
 		em = (netdev_uc_count(ndev) == 1);
@@ -149,7 +148,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
 
 	if (!mprom) {
 		/* Update multicast filters */
-		filter = &pf->mac_filter[MC];
+		filter = &si->mac_filter[MC];
 		enetc_reset_mac_addr_filter(filter);
 
 		netdev_for_each_mc_addr(ha, ndev) {
@@ -162,10 +161,10 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
 
 	if (!uprom || !mprom)
 		/* update PF entries */
-		enetc_sync_mac_filters(pf);
+		enetc_sync_mac_filters(si);
 
-	enetc_set_si_uc_promisc(priv->si, 0, uprom);
-	enetc_set_si_mc_promisc(priv->si, 0, mprom);
+	enetc_set_si_uc_promisc(si, 0, uprom);
+	enetc_set_si_mc_promisc(si, 0, mprom);
 }
 
 static void enetc_set_loopback(struct net_device *ndev, bool en)
@@ -191,33 +190,12 @@ static void enetc_set_loopback(struct net_device *ndev, bool en)
 	}
 }
 
-static int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
-{
-	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_pf *pf = enetc_si_priv(priv->si);
-	struct enetc_vf_state *vf_state;
-
-	if (vf >= pf->total_vfs)
-		return -EINVAL;
-
-	if (!is_valid_ether_addr(mac))
-		return -EADDRNOTAVAIL;
-
-	vf_state = &pf->vf_state[vf];
-
-	mutex_lock(&vf_state->lock);
-	vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC;
-	enetc_pf_set_primary_mac_addr(&priv->si->hw, vf + 1, mac);
-	mutex_unlock(&vf_state->lock);
-
-	return 0;
-}
-
 static int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
 				u8 qos, __be16 proto)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_vf_state *vf_state;
 
 	if (priv->si->errata & ENETC_ERR_VLAN_ISOL)
 		return -EOPNOTSUPP;
@@ -230,6 +208,17 @@ static int enetc_pf_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
 		return -EPROTONOSUPPORT;
 
 	enetc_set_isol_vlan(&priv->si->hw, vf + 1, vlan, qos);
+
+	vf_state = &pf->vf_state[vf];
+	mutex_lock(&vf_state->lock);
+	/* Currently only C-tags is supported, so tpid is always 0,
+	 * which indicates ETH_P_8021Q.
+	 */
+	vf_state->tpid = 0;
+	vf_state->qos = qos;
+	vf_state->vid = vlan;
+	mutex_unlock(&vf_state->lock);
+
 	return 0;
 }
 
@@ -237,6 +226,7 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_vf_state *vf_state;
 	u32 cfgr;
 
 	if (vf >= pf->total_vfs)
@@ -246,6 +236,16 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
 	cfgr = (cfgr & ~ENETC_PSICFGR0_ASE) | (en ? ENETC_PSICFGR0_ASE : 0);
 	enetc_port_wr(&priv->si->hw, ENETC_PSICFGR0(vf + 1), cfgr);
 
+	vf_state = &pf->vf_state[vf];
+	mutex_lock(&vf_state->lock);
+
+	if (en)
+		vf_state->flags |= ENETC_VF_FLAG_SPOOFCHK;
+	else
+		vf_state->flags &= ~ENETC_VF_FLAG_SPOOFCHK;
+
+	mutex_unlock(&vf_state->lock);
+
 	return 0;
 }
 
@@ -488,6 +488,7 @@ static const struct net_device_ops enetc_ndev_ops = {
 	.ndo_set_rx_mode	= enetc_pf_set_rx_mode,
 	.ndo_vlan_rx_add_vid	= enetc_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid	= enetc_vlan_rx_del_vid,
+	.ndo_set_vf_trust	= enetc_pf_set_vf_trust,
 	.ndo_set_vf_mac		= enetc_pf_set_vf_mac,
 	.ndo_set_vf_vlan	= enetc_pf_set_vf_vlan,
 	.ndo_set_vf_spoofchk	= enetc_pf_set_vf_spoofchk,
@@ -498,6 +499,7 @@ static const struct net_device_ops enetc_ndev_ops = {
 	.ndo_xdp_xmit		= enetc_xdp_xmit,
 	.ndo_hwtstamp_get	= enetc_hwtstamp_get,
 	.ndo_hwtstamp_set	= enetc_hwtstamp_set,
+	.ndo_get_vf_config	= enetc_pf_get_vf_config,
 };
 
 static struct phylink_pcs *
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 56d23a8a11a06..25e869d54365c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -6,14 +6,22 @@
 
 #define ENETC_PF_NUM_RINGS	8
 #define ENETC_VLAN_HT_SIZE	64
+#define ENETC_VF_MC_HASH_BITS_MAX	8 /* For untrusted VFs */
 
 enum enetc_vf_flags {
 	ENETC_VF_FLAG_PF_SET_MAC	= BIT(0),
+	ENETC_VF_FLAG_TRUSTED		= BIT(1),
+	ENETC_VF_FLAG_UC_PROMISC	= BIT(2),
+	ENETC_VF_FLAG_MC_PROMISC	= BIT(3),
+	ENETC_VF_FLAG_SPOOFCHK		= BIT(4),
 };
 
 struct enetc_vf_state {
 	struct mutex lock; /* Prevent concurrent access */
 	enum enetc_vf_flags flags;
+	u8 tpid; /* SI-based VLAN TPID (0: 0x8100, 1: 0x88a8) */
+	u8 qos; /* SI-based VLAN QOS (priority) bits */
+	u16 vid; /* SI-based VLAN ID */
 };
 
 struct enetc_port_caps {
@@ -30,6 +38,7 @@ struct enetc_pf_ops {
 	struct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus);
 	void (*destroy_pcs)(struct phylink_pcs *pcs);
 	int (*enable_psfp)(struct enetc_ndev_priv *priv);
+	void (*vf_flr_handler)(struct enetc_pf *pf, int vf_id);
 };
 
 struct enetc_pf {
@@ -37,12 +46,7 @@ struct enetc_pf {
 	int num_vfs; /* number of active VFs, after sriov_init */
 	int total_vfs; /* max number of VFs, set for PF at probe */
 	struct enetc_vf_state *vf_state;
-
-	struct enetc_mac_filter mac_filter[MADDR_TYPE];
-
 	struct enetc_msg_swbd *rxmsg;
-	struct work_struct msg_task;
-	char msg_int_name[ENETC_INT_NAME_MAX];
 
 	DECLARE_BITMAP(vlan_ht_filter, ENETC_VLAN_HT_SIZE);
 	DECLARE_BITMAP(active_vlans, VLAN_N_VID);
@@ -56,6 +60,12 @@ struct enetc_pf {
 
 	struct enetc_port_caps caps;
 	const struct enetc_pf_ops *ops;
+
+	/* Message lock, prevent concurrent access */
+	struct mutex msg_lock;
+	bool sriov_enabled;
+	bool link_up;
+	u16 link_status_ms_mask;
 };
 
 #define phylink_to_enetc_pf(config) \
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index d32a195a04c97..264294a0cc236 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -151,26 +151,44 @@ void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
 }
 EXPORT_SYMBOL_GPL(enetc_set_si_uc_hash_filter);
 
-void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
+static void enetc_get_psimmhfr_offsets(struct enetc_si *si, int si_id,
+				       int *psimmhfr0, int *psimmhfr1)
 {
-	int psimmhfr0_off, psimmhfr1_off;
-	struct enetc_hw *hw = &si->hw;
-
 	if (is_enetc_rev1(si)) {
 		bool err = si->errata & ENETC_ERR_UCMCSWP;
 
-		psimmhfr0_off = ENETC_PSIMMHFR0(si_id, err);
-		psimmhfr1_off = ENETC_PSIMMHFR1(si_id);
+		*psimmhfr0 = ENETC_PSIMMHFR0(si_id, err);
+		*psimmhfr1 = ENETC_PSIMMHFR1(si_id);
 	} else {
-		psimmhfr0_off = ENETC4_PSIMMHFR0(si_id);
-		psimmhfr1_off = ENETC4_PSIMMHFR1(si_id);
+		*psimmhfr0 = ENETC4_PSIMMHFR0(si_id);
+		*psimmhfr1 = ENETC4_PSIMMHFR1(si_id);
 	}
+}
+
+void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
+{
+	int psimmhfr0_off, psimmhfr1_off;
+	struct enetc_hw *hw = &si->hw;
 
+	enetc_get_psimmhfr_offsets(si, si_id, &psimmhfr0_off, &psimmhfr1_off);
 	enetc_port_wr(hw, psimmhfr0_off, lower_32_bits(hash));
 	enetc_port_wr(hw, psimmhfr1_off, upper_32_bits(hash));
 }
 EXPORT_SYMBOL_GPL(enetc_set_si_mc_hash_filter);
 
+static u64 enetc_get_si_mc_hash_filter(struct enetc_si *si, int si_id)
+{
+	int psimmhfr0_off, psimmhfr1_off;
+	struct enetc_hw *hw = &si->hw;
+	u32 hash_h, hash_l;
+
+	enetc_get_psimmhfr_offsets(si, si_id, &psimmhfr0_off, &psimmhfr1_off);
+	hash_l = enetc_port_rd(hw, psimmhfr0_off);
+	hash_h = enetc_port_rd(hw, psimmhfr1_off);
+
+	return ((u64)hash_h << 32) | hash_l;
+}
+
 void enetc_set_si_vlan_promisc(struct enetc_si *si, int si_id, bool promisc)
 {
 	struct enetc_hw *hw = &si->hw;
@@ -582,9 +600,120 @@ int enetc_init_sriov_resources(struct enetc_pf *pf)
 	for (int i = 0; i < pf->total_vfs; i++)
 		mutex_init(&pf->vf_state[i].lock);
 
+	mutex_init(&pf->msg_lock);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(enetc_init_sriov_resources);
 
+int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_vf_state *vf_state;
+	struct enetc_si *si = priv->si;
+	int si_id = vf + 1;
+
+	if (vf >= pf->total_vfs)
+		return -EINVAL;
+
+	vf_state = &pf->vf_state[vf];
+	mutex_lock(&vf_state->lock);
+
+	if (setting) {
+		vf_state->flags |= ENETC_VF_FLAG_TRUSTED;
+	} else {
+		u64 hash;
+
+		vf_state->flags &= ~(ENETC_VF_FLAG_TRUSTED |
+				     ENETC_VF_FLAG_UC_PROMISC |
+				     ENETC_VF_FLAG_MC_PROMISC);
+
+		/* For ENETC v1, we only support setting the VF's MAC address
+		 * via VSI-to-PSI messages. Unicast and multicast promiscuous
+		 * mode and hash filters are not supported, so there is no need
+		 * to clear these configurations.
+		 */
+		if (is_enetc_rev1(si))
+			goto vf_state_unlock;
+
+		/* Disable unicast and multicast promiscuous modes */
+		mutex_lock(&pf->msg_lock);
+		enetc_set_si_uc_promisc(si, si_id, false);
+		enetc_set_si_mc_promisc(si, si_id, false);
+		mutex_unlock(&pf->msg_lock);
+
+		/* Clear unicast hash filter */
+		enetc_set_si_uc_hash_filter(si, si_id, 0);
+
+		/* Clear multicast hash filter if its set bits exceed
+		 * ENETC_VF_MC_HASH_BITS_MAX.
+		 */
+		hash = enetc_get_si_mc_hash_filter(si, si_id);
+		if (hweight64(hash) > ENETC_VF_MC_HASH_BITS_MAX)
+			enetc_set_si_mc_hash_filter(si, si_id, 0);
+	}
+
+vf_state_unlock:
+	mutex_unlock(&vf_state->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_pf_set_vf_trust);
+
+int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_vf_state *vf_state;
+
+	if (vf >= pf->total_vfs)
+		return -EINVAL;
+
+	if (!is_valid_ether_addr(mac))
+		return -EADDRNOTAVAIL;
+
+	vf_state = &pf->vf_state[vf];
+
+	mutex_lock(&vf_state->lock);
+	vf_state->flags |= ENETC_VF_FLAG_PF_SET_MAC;
+	enetc_set_si_hw_addr(pf, vf + 1, mac);
+	mutex_unlock(&vf_state->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_pf_set_vf_mac);
+
+int enetc_pf_get_vf_config(struct net_device *ndev, int vf,
+			   struct ifla_vf_info *ivi)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_vf_state *vf_state;
+
+	if (vf >= pf->total_vfs)
+		return -EINVAL;
+
+	vf_state = &pf->vf_state[vf];
+	mutex_lock(&vf_state->lock);
+
+	ivi->vf = vf;
+	ivi->spoofchk = !!(vf_state->flags & ENETC_VF_FLAG_SPOOFCHK);
+	ivi->trusted = !!(vf_state->flags & ENETC_VF_FLAG_TRUSTED);
+	enetc_get_si_hw_addr(pf, vf + 1, ivi->mac);
+
+	if (vf_state->vid) {
+		ivi->vlan = vf_state->vid;
+		ivi->qos = vf_state->qos;
+		ivi->vlan_proto = vf_state->tpid ? htons(ETH_P_8021AD) :
+						   htons(ETH_P_8021Q);
+	}
+
+	mutex_unlock(&vf_state->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_pf_get_vf_config);
+
 MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index 8243ce0de57f6..f36f45450733f 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -22,17 +22,43 @@ void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc);
 void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash);
 void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash);
 void enetc_set_si_vlan_promisc(struct enetc_si *si, int si_id, bool promisc);
+int enetc_pf_set_vf_trust(struct net_device *ndev, int vf, bool setting);
+int enetc_pf_set_vf_mac(struct net_device *ndev, int vf, u8 *mac);
+int enetc_pf_get_vf_config(struct net_device *ndev, int vf,
+			   struct ifla_vf_info *ivi);
 
 static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
 {
 	return enetc_global_rd(hw, ENETC_G_EIPBRR0) & EIPBRR0_REVISION;
 }
 
+static inline void enetc_pf_msg_lock(struct enetc_pf *pf)
+{
+	if (pf->total_vfs)
+		mutex_lock(&pf->msg_lock);
+}
+
+static inline void enetc_pf_msg_unlock(struct enetc_pf *pf)
+{
+	if (pf->total_vfs)
+		mutex_unlock(&pf->msg_lock);
+}
+
 #if IS_ENABLED(CONFIG_PCI_IOV)
 int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs);
+void enetc_pf_notify_vf_link_up(struct enetc_pf *pf);
+void enetc_pf_notify_vf_link_down(struct enetc_pf *pf);
 #else
 static inline int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
 {
 	return 0;
 }
+
+static inline void enetc_pf_notify_vf_link_up(struct enetc_pf *pf)
+{
+}
+
+static inline void enetc_pf_notify_vf_link_down(struct enetc_pf *pf)
+{
+}
 #endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 7dcb4a0246f52..a4d0089ef1a93 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -107,8 +107,12 @@ static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg)
 		case ENETC_MSG_CLASS_ID_CMD_TIMEOUT:
 			err = -ETIME;
 			break;
-		case ENETC_MSG_CLASS_ID_INVALID_MSG_LEN:
 		case ENETC_MSG_CLASS_ID_MAC_FILTER:
+			if (FIELD_GET(ENETC_PF_MSG_CLASS_CODE, pf_msg) ==
+			    ENETC_MF_CLASS_CODE_UCF_DENY)
+				return -EACCES;
+			fallthrough;
+		case ENETC_MSG_CLASS_ID_INVALID_MSG_LEN:
 			err = -EINVAL;
 			break;
 		case ENETC_MSG_CLASS_ID_CMD_NOT_PERMITTED:
@@ -131,6 +135,52 @@ static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg)
 	return err;
 }
 
+static int enetc_msg_link_status_notifier(struct enetc_si *si, bool reg)
+{
+	struct device *dev = &si->pdev->dev;
+	struct enetc_msg_swbd msg_swbd;
+	u8 cmd_id;
+
+	msg_swbd.size = ALIGN(sizeof(struct enetc_msg_generic),
+			      ENETC_MSG_ALIGN);
+	msg_swbd.vaddr = dma_alloc_coherent(dev, msg_swbd.size,
+					    &msg_swbd.dma, GFP_KERNEL);
+	if (!msg_swbd.vaddr)
+		return -ENOMEM;
+
+	cmd_id = reg ? ENETC_MSG_REGISTER_LINK_CHANGE_NOTIFIER :
+		       ENETC_MSG_UNREGISTER_LINK_CHANGE_NOTIFIER;
+	enetc_msg_fill_common_hdr(&msg_swbd, ENETC_MSG_CLASS_ID_LINK_STATUS,
+				  cmd_id, 0, 0);
+
+	return enetc_msg_vsi_send(si, &msg_swbd);
+}
+
+static int enetc_vf_reg_link_status_notifier(struct enetc_si *si)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(si->ndev);
+	int err;
+
+	err = enetc_msg_link_status_notifier(si, true);
+	if (!err)
+		set_bit(ENETC_LINK_STATUS_NOTIFIER_REGISTERED, &priv->flags);
+
+	return err;
+}
+
+static int enetc_vf_unreg_link_status_notifier(struct enetc_si *si)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(si->ndev);
+	int err;
+
+	err = enetc_msg_link_status_notifier(si, false);
+	if (!err)
+		clear_bit(ENETC_LINK_STATUS_NOTIFIER_REGISTERED,
+			  &priv->flags);
+
+	return err;
+}
+
 static int enetc_msg_vsi_set_primary_mac_addr(struct enetc_ndev_priv *priv,
 					      struct sockaddr *saddr)
 {
@@ -209,6 +259,142 @@ static int enetc_vf_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 	}
 }
 
+static int enetc_vf_set_mac_promisc(struct enetc_si *si, int type, bool en)
+{
+	struct enetc_msg_mac_promisc_mode *msg;
+	struct device *dev = &si->pdev->dev;
+	struct enetc_msg_swbd msg_swbd;
+
+	if (!(type & ENETC_MAC_FILTER_TYPE_ALL))
+		return -EINVAL;
+
+	msg_swbd.size = ALIGN(sizeof(*msg), ENETC_MSG_ALIGN);
+	msg_swbd.vaddr = dma_alloc_coherent(dev, msg_swbd.size,
+					    &msg_swbd.dma, GFP_KERNEL);
+	if (!msg_swbd.vaddr)
+		return -ENOMEM;
+
+	msg = (struct enetc_msg_mac_promisc_mode *)msg_swbd.vaddr;
+	msg->config = FIELD_PREP(ENETC_MSG_MAC_TYPE,
+				 type & ENETC_MAC_FILTER_TYPE_ALL);
+	msg->config |= FIELD_PREP(ENETC_MSG_MAC_PROMISC_MODE, en);
+	msg->config |= FIELD_PREP(ENETC_MSG_MAC_FLUSH_MACS, en);
+	enetc_msg_fill_common_hdr(&msg_swbd, ENETC_MSG_CLASS_ID_MAC_FILTER,
+				  ENETC_MSG_SET_MAC_PROMISC_MODE, 0, 0);
+
+	return enetc_msg_vsi_send(si, &msg_swbd);
+}
+
+static int enetc_vf_set_mac_hash_filter(struct enetc_si *si,
+					struct netdev_hw_addr_list *uc,
+					struct netdev_hw_addr_list *mc)
+{
+	struct enetc_msg_mac_hash_filter *msg;
+	struct enetc_mac_filter *mac_filter;
+	struct device *dev = &si->pdev->dev;
+	struct net_device *ndev = si->ndev;
+	struct enetc_msg_swbd msg_swbd;
+	struct netdev_hw_addr *ha;
+	u32 msg_size, tbl_cnt;
+	int mac_filter_type;
+	int i = 0;
+
+	if (ndev->flags & IFF_PROMISC)
+		return 0;
+
+	if (ndev->flags & IFF_ALLMULTI) {
+		tbl_cnt = 2;
+		mac_filter_type = ENETC_MAC_FILTER_TYPE_UC;
+	} else {
+		tbl_cnt = 4;
+		mac_filter_type = ENETC_MAC_FILTER_TYPE_ALL;
+	}
+
+	msg_size = struct_size(msg, hash_tbl, tbl_cnt);
+	msg_swbd.size = ALIGN(msg_size, ENETC_MSG_ALIGN);
+	msg_swbd.vaddr = dma_alloc_coherent(dev, msg_swbd.size,
+					    &msg_swbd.dma, GFP_KERNEL);
+	if (!msg_swbd.vaddr)
+		return -ENOMEM;
+
+	msg = (struct enetc_msg_mac_hash_filter *)msg_swbd.vaddr;
+	msg->sz_type = FIELD_PREP(ENETC_MSG_MAC_TYPE, mac_filter_type);
+	msg->sz_type |= FIELD_PREP(ENETC_MSG_MAC_HASH_SIZE,
+				   ENETC_MAC_HASH_TABLE_SIZE_64);
+
+	if (mac_filter_type & ENETC_MAC_FILTER_TYPE_UC) {
+		mac_filter = &si->mac_filter[UC];
+		enetc_reset_mac_addr_filter(mac_filter);
+		netdev_hw_addr_list_for_each(ha, uc)
+			enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+		bitmap_to_arr32(&msg->hash_tbl[i], mac_filter->mac_hash_table,
+				ENETC_MADDR_HASH_TBL_SZ);
+		i += 2;
+	}
+
+	if (mac_filter_type & ENETC_MAC_FILTER_TYPE_MC) {
+		mac_filter = &si->mac_filter[MC];
+		enetc_reset_mac_addr_filter(mac_filter);
+		netdev_hw_addr_list_for_each(ha, mc)
+			enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+		bitmap_to_arr32(&msg->hash_tbl[i], mac_filter->mac_hash_table,
+				ENETC_MADDR_HASH_TBL_SZ);
+	}
+
+	enetc_msg_fill_common_hdr(&msg_swbd, ENETC_MSG_CLASS_ID_MAC_FILTER,
+				  ENETC_MSG_SET_MAC_HASH_TABLE, 0, 0);
+
+	return enetc_msg_vsi_send(si, &msg_swbd);
+}
+
+static int enetc_vf_set_rx_mode(struct net_device *ndev,
+				struct netdev_hw_addr_list *uc,
+				struct netdev_hw_addr_list *mc)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_si *si = priv->si;
+	int err;
+
+	/* For ENETC v1, we cannot return -EOPNOTSUPP or any other error,
+	 * otherwise ndev->rx_mode_retry_timer will try to set rx_mode
+	 * multiple times, which is pointless.
+	 */
+	if (is_enetc_rev1(si))
+		return 0;
+
+	if (ndev->flags & IFF_PROMISC) {
+		err = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_ALL,
+					       true);
+	} else if (ndev->flags & IFF_ALLMULTI) {
+		err = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_UC,
+					       false);
+		if (err)
+			goto out;
+
+		err = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_MC,
+					       true);
+	} else {
+		err = enetc_vf_set_mac_promisc(si, ENETC_MAC_FILTER_TYPE_ALL,
+					       false);
+	}
+
+	if (err)
+		goto out;
+
+	err = enetc_vf_set_mac_hash_filter(si, uc, mc);
+
+out:
+	/* If the error code is -EOPNOTSUPP or -EACCES or -EPERM, return 0
+	 * directly to avoid meaningless retries.
+	 */
+	if (err == -EOPNOTSUPP || err == -EACCES || err == -EPERM)
+		return 0;
+
+	return err;
+}
+
 /* Probing/ Init */
 static const struct net_device_ops enetc_ndev_ops = {
 	.ndo_open		= enetc_open,
@@ -221,6 +407,7 @@ static const struct net_device_ops enetc_ndev_ops = {
 	.ndo_setup_tc		= enetc_vf_setup_tc,
 	.ndo_hwtstamp_get	= enetc_hwtstamp_get,
 	.ndo_hwtstamp_set	= enetc_hwtstamp_set,
+	.ndo_set_rx_mode_async	= enetc_vf_set_rx_mode,
 };
 
 static void enetc_vf_get_revision(struct enetc_si *si)
@@ -276,15 +463,146 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
 			      NETIF_F_TSO | NETIF_F_TSO6;
 
+	if (!is_enetc_rev1(si))
+		ndev->priv_flags |= IFF_UNICAST_FLT;
+
 	if (si->num_rss) {
 		ndev->hw_features |= NETIF_F_RXHASH;
 		ndev->features |= NETIF_F_RXHASH;
 	}
 
+	if (si->drvdata->tx_csum)
+		priv->active_offloads |= ENETC_F_TXCSUM;
+
+	if (si->hw_features & ENETC_SI_F_LSO)
+		priv->active_offloads |= ENETC_F_LSO;
+
 	/* pick up primary MAC address from SI */
 	enetc_load_primary_mac_addr(&si->hw, ndev);
 }
 
+static void enetc_vf_enable_mr_int(struct enetc_si *si)
+{
+	if (is_enetc_rev1(si))
+		return;
+
+	enetc_wr(&si->hw, ENETC_VSIIER, VSIIER_MRIE);
+}
+
+static void enetc_vf_disable_mr_int(struct enetc_si *si)
+{
+	if (is_enetc_rev1(si))
+		return;
+
+	enetc_wr(&si->hw, ENETC_VSIIER, 0);
+}
+
+static void enetc_vf_msg_handle_link_status(struct enetc_si *si, u8 status)
+{
+	bool tx_pause = !!(status & ENETC_CLASS_CODE_TX_PAUSE_EN);
+	bool link_down = !!(status & ENETC_CLASS_CODE_LINK_DOWN);
+	struct enetc_ndev_priv *priv = netdev_priv(si->ndev);
+	struct net_device *ndev = si->ndev;
+
+	rtnl_lock();
+	if (!netif_running(ndev))
+		goto unlock_rtnl;
+
+	if (link_down) {
+		if (netif_carrier_ok(ndev)) {
+			netif_carrier_off(ndev);
+			netdev_info(ndev, "Link is Down\n");
+		}
+
+		goto unlock_rtnl;
+	}
+
+	/* Link is up */
+	enetc_set_congestion_mode(priv, tx_pause);
+
+	if (!netif_carrier_ok(ndev)) {
+		netif_carrier_on(ndev);
+		netdev_info(ndev, "Link is Up, tx pause %s\n",
+			    tx_pause ? "on" : "off");
+	}
+
+unlock_rtnl:
+	rtnl_unlock();
+}
+
+static void enetc_vf_msg_task(struct work_struct *work)
+{
+	struct enetc_si *si = container_of(work, struct enetc_si, msg_task);
+	struct enetc_hw *hw = &si->hw;
+	u8 class_id, class_code;
+	u16 pf_msg;
+
+	/* W1C to clear the message received interrupt event */
+	enetc_wr(hw, ENETC_VSIIDR, VSIIDR_MR);
+
+	/* Reading VSIMSGRR retrieves the message data and acknowledges to
+	 * the PF that the message was received and another message can be
+	 * sent.
+	 */
+	pf_msg = FIELD_GET(VSIMSGRR_MC, enetc_rd(hw, ENETC_VSIMSGRR));
+	class_id = FIELD_GET(ENETC_PF_MSG_CLASS_ID, pf_msg);
+
+	switch (class_id) {
+	case ENETC_MSG_CLASS_ID_LINK_STATUS:
+		class_code = FIELD_GET(ENETC_PF_MSG_CLASS_CODE_U8, pf_msg);
+		enetc_vf_msg_handle_link_status(si, class_code);
+		break;
+	default:
+		dev_err(&si->pdev->dev,
+			"Unsupported Message Class ID (0x%02x) from PF\n",
+			class_id);
+	}
+
+	enetc_vf_enable_mr_int(si);
+}
+
+static irqreturn_t enetc_vf_msg_msix_handler(int irq, void *data)
+{
+	struct enetc_si *si = (struct enetc_si *)data;
+
+	enetc_vf_disable_mr_int(si);
+	queue_work(si->workqueue, &si->msg_task);
+
+	return IRQ_HANDLED;
+}
+
+static int enetc_vf_register_msg_msix(struct enetc_si *si)
+{
+	int irq, err;
+
+	if (is_enetc_rev1(si))
+		return 0;
+
+	snprintf(si->msg_int_name, sizeof(si->msg_int_name), "%s-pfmsg",
+		 pci_name(si->pdev));
+	irq = pci_irq_vector(si->pdev, ENETC_SI_INT_IDX);
+	err = request_irq(irq, enetc_vf_msg_msix_handler, 0,
+			  si->msg_int_name, si);
+	if (err) {
+		dev_err(&si->pdev->dev,
+			"VF messaging: request_irq() failed!\n");
+		return err;
+	}
+
+	/* set one IRQ entry for PSI-to-VSI messaging */
+	enetc_wr(&si->hw, ENETC_SIMSIVR, ENETC_SI_INT_IDX);
+
+	return 0;
+}
+
+static void enetc_vf_free_msg_msix(struct enetc_si *si)
+{
+	if (is_enetc_rev1(si))
+		return;
+
+	free_irq(pci_irq_vector(si->pdev, ENETC_SI_INT_IDX), si);
+}
+
 static const struct enetc_si_ops enetc_vsi_ops = {
 	.get_rss_table = enetc_get_rss_table,
 	.set_rss_table = enetc_set_rss_table,
@@ -292,6 +610,43 @@ static const struct enetc_si_ops enetc_vsi_ops = {
 	.teardown_cbdr = enetc_teardown_cbdr,
 };
 
+static const struct enetc_si_ops enetc4_vsi_ops = {
+	.get_rss_table = enetc4_get_rss_table,
+	.set_rss_table = enetc4_set_rss_table,
+	.setup_cbdr = enetc4_setup_cbdr,
+	.teardown_cbdr = enetc4_teardown_cbdr,
+	.vf_reg_link_status_notifier = enetc_vf_reg_link_status_notifier,
+	.vf_unreg_link_status_notifier = enetc_vf_unreg_link_status_notifier,
+};
+
+static int enetc_vf_wq_task_init(struct enetc_si *si)
+{
+	if (is_enetc_rev1(si))
+		return 0;
+
+	si->workqueue = alloc_ordered_workqueue("enetc-%s-wq", WQ_MEM_RECLAIM,
+						pci_name(si->pdev));
+	if (!si->workqueue)
+		return -ENOMEM;
+
+	INIT_WORK(&si->msg_task, enetc_vf_msg_task);
+
+	return 0;
+}
+
+static void enetc_vf_wq_task_destroy(struct enetc_si *si)
+{
+	if (!si->workqueue)
+		return;
+
+	disable_work_sync(&si->msg_task);
+
+	/* The MR interrupt may be re-enabled by si->msg_task */
+	enetc_vf_disable_mr_int(si);
+
+	destroy_workqueue(si->workqueue);
+}
+
 static int enetc_vf_probe(struct pci_dev *pdev,
 			  const struct pci_device_id *ent)
 {
@@ -307,7 +662,11 @@ static int enetc_vf_probe(struct pci_dev *pdev,
 
 	si = pci_get_drvdata(pdev);
 	enetc_vf_get_revision(si);
-	si->ops = &enetc_vsi_ops;
+	if (is_enetc_rev1(si))
+		si->ops = &enetc_vsi_ops;
+	else
+		si->ops = &enetc4_vsi_ops;
+
 	err = enetc_get_driver_data(si);
 	if (err) {
 		dev_err_probe(&pdev->dev, err,
@@ -359,15 +718,33 @@ static int enetc_vf_probe(struct pci_dev *pdev,
 		goto err_alloc_msix;
 	}
 
+	err = enetc_vf_wq_task_init(si);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to init workqueue\n");
+		goto err_wq_init;
+	}
+
+	err = enetc_vf_register_msg_msix(si);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to register msg irq\n");
+		goto err_register_msg_msix;
+	}
+
 	err = register_netdev(ndev);
 	if (err)
 		goto err_reg_netdev;
 
+	/* Enable message received interrupt */
+	enetc_vf_enable_mr_int(si);
 	netif_carrier_off(ndev);
 
 	return 0;
 
 err_reg_netdev:
+	enetc_vf_free_msg_msix(si);
+err_register_msg_msix:
+	enetc_vf_wq_task_destroy(si);
+err_wq_init:
 	enetc_free_msix(priv);
 err_config_si:
 err_alloc_msix:
@@ -393,8 +770,11 @@ static void enetc_vf_remove(struct pci_dev *pdev)
 	struct enetc_msg_swbd msg;
 
 	priv = netdev_priv(si->ndev);
+	enetc_vf_disable_mr_int(si);
 	unregister_netdev(si->ndev);
 
+	enetc_vf_free_msg_msix(si);
+	enetc_vf_wq_task_destroy(si);
 	enetc_free_msix(priv);
 
 	enetc_free_si_resources(priv);
@@ -409,6 +789,7 @@ static void enetc_vf_remove(struct pci_dev *pdev)
 
 static const struct pci_device_id enetc_vf_id_table[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_VF) },
+	{ PCI_DEVICE(NXP_ENETC_VENDOR_ID, NXP_ENETC_VF_DEV_ID) },
 	{ 0, } /* End of table. */
 };
 MODULE_DEVICE_TABLE(pci, enetc_vf_id_table);

3/2 2026/08/31 03:57 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 34938
							output: 21
							thoughts: 808
						

Thoughts:
**Analyzing the Patch Series for WorthFuzzing**

Okay, let's dive into this patch series. My initial thought is to identify exactly what's being modified. Based on the diff, it looks like this centers around the `drivers/net/ethernet/freescale/enetc/` directory. Specifically, it touches a range of files: `Kconfig`, `enetc.c`, `enetc.h`, `enetc4_debugfs.c`, `enetc4_hw.h`, `enetc4_pf.c`, `enetc_ethtool.c`, `enetc_hw.h`, `enetc_mailbox.h`, `enetc_msg.c`, `enetc_pf.c`, `enetc_pf.h`, `enetc_pf_common.c`, `enetc_pf_common.h`, and `enetc_vf.c`. It looks like we have changes spanning configuration, core driver logic, header files, debugging interfaces, hardware definitions, PF/VF handling (including SRIOV/FLR), ethtool integration, mailbox communication and link status notifications.

The `Kconfig` changes caught my eye first, especially the `FSL_ENETC_VF` which selects `NXP_NTMP`. This points to some Virtual Function (VF) configuration, and therefore, an involved driver.

Now, I need to evaluate this against the "WorthFuzzing" rules. Let's make a quick rundown in my mind: no documentation updates, no logging, no constant changes, no unreachable code, and, most importantly, *no changes to vendor-specific PCIe switch, SmartNIC, or GPU drivers*. This is the crux of the matter.

The key question is whether this ENETC driver on Freescale/NXP hardware, specifically the Layerscape, i.MX, and S32G SoCs, depends on physical PCIe hardware. My initial hunch is that ENETC is indeed an integrated Ethernet controller on these SoCs, probably implemented as a PCIe endpoint. It's likely *not* a standalone PCIe card, but a tightly integrated component. I need to confirm if this requires physical PCIe cards or SoC hardware that standard QEMU can't emulate. I seem to recall that QEMU does support some aspects of Freescale/NXP SoCs, but this requires more specific information about this particular ENETC implementation.

I need to quickly search the kernel documentation and QEMU's supported hardware list to either confirm or refute my suspicion. I'll need to confirm if this is supported in standard QEMU or if this requires a specific setup to emulate the Freescale/NXP hardware. Let's see...ENETC is likely a vendor-specific NIC driver that needs specific hardware or specific QEMU configuration.



4/2 2026/08/31 03:58 tool grepper
0m Args:
{
  "Expression": "CONFIG_FSL_ENETC"
}

Results:
{
  "Output": "arch/arm64/configs/defconfig=387=CONFIG_FSL_DPAA2_ETH=m\narch/arm64/configs/defconfig:388:CONFIG_FSL_ENETC=m\narch/arm64/configs/defconfig-389-CONFIG_NXP_ENETC4=m\narch/arm64/configs/defconfig:390:CONFIG_FSL_ENETC_VF=m\narch/arm64/configs/defconfig:391:CONFIG_FSL_ENETC_QOS=y\narch/arm64/configs/defconfig-392-CONFIG_NXP_NETC_BLK_CTRL=m\n--\ndrivers/net/ethernet/freescale/enetc/Makefile-2-\ndrivers/net/ethernet/freescale/enetc/Makefile:3:obj-$(CONFIG_FSL_ENETC_CORE) += fsl-enetc-core.o\ndrivers/net/ethernet/freescale/enetc/Makefile-4-fsl-enetc-core-y := enetc.o enetc_cbdr.o enetc_ethtool.o\n--\ndrivers/net/ethernet/freescale/enetc/Makefile=11=nxp-netc-lib-y := ntmp.o\ndrivers/net/ethernet/freescale/enetc/Makefile-12-\ndrivers/net/ethernet/freescale/enetc/Makefile:13:obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o\ndrivers/net/ethernet/freescale/enetc/Makefile-14-fsl-enetc-y := enetc_pf.o\ndrivers/net/ethernet/freescale/enetc/Makefile:15:fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o\ndrivers/net/ethernet/freescale/enetc/Makefile-16-\n--\ndrivers/net/ethernet/freescale/enetc/Makefile=19=nxp-enetc4-$(CONFIG_DEBUG_FS) += enetc4_debugfs.o\ndrivers/net/ethernet/freescale/enetc/Makefile-20-\ndrivers/net/ethernet/freescale/enetc/Makefile:21:obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o\ndrivers/net/ethernet/freescale/enetc/Makefile-22-fsl-enetc-vf-y := enetc_vf.o\ndrivers/net/ethernet/freescale/enetc/Makefile-23-\ndrivers/net/ethernet/freescale/enetc/Makefile:24:obj-$(CONFIG_FSL_ENETC_IERB) += fsl-enetc-ierb.o\ndrivers/net/ethernet/freescale/enetc/Makefile-25-fsl-enetc-ierb-y := enetc_ierb.o\ndrivers/net/ethernet/freescale/enetc/Makefile-26-\ndrivers/net/ethernet/freescale/enetc/Makefile:27:obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o\ndrivers/net/ethernet/freescale/enetc/Makefile-28-fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o\ndrivers/net/ethernet/freescale/enetc/Makefile-29-\ndrivers/net/ethernet/freescale/enetc/Makefile:30:obj-$(CONFIG_FSL_ENETC_PTP_CLOCK) += fsl-enetc-ptp.o\ndrivers/net/ethernet/freescale/enetc/Makefile-31-fsl-enetc-ptp-y := enetc_ptp.o\n--\ndrivers/net/ethernet/freescale/enetc/enetc.h=614=static inline bool enetc_ptp_clock_is_enabled(struct enetc_si *si)\n--\ndrivers/net/ethernet/freescale/enetc/enetc.h-616-\tif (is_enetc_rev1(si))\ndrivers/net/ethernet/freescale/enetc/enetc.h:617:\t\treturn IS_ENABLED(CONFIG_FSL_ENETC_PTP_CLOCK);\ndrivers/net/ethernet/freescale/enetc/enetc.h-618-\n--\ndrivers/net/ethernet/freescale/enetc/enetc.h-621-\ndrivers/net/ethernet/freescale/enetc/enetc.h:622:#ifdef CONFIG_FSL_ENETC_QOS\ndrivers/net/ethernet/freescale/enetc/enetc.h-623-int enetc_qos_query_caps(struct net_device *ndev, void *type_data);\n--\ndrivers/net/ethernet/freescale/enetc/enetc_ierb.h-6-\ndrivers/net/ethernet/freescale/enetc/enetc_ierb.h:7:#if IS_ENABLED(CONFIG_FSL_ENETC_IERB)\ndrivers/net/ethernet/freescale/enetc/enetc_ierb.h-8-\n--\ninclude/linux/fsl/enetc_mdio.h=33=struct enetc_mdio_priv {\n--\ninclude/linux/fsl/enetc_mdio.h-37-\ninclude/linux/fsl/enetc_mdio.h:38:#if IS_REACHABLE(CONFIG_FSL_ENETC_MDIO)\ninclude/linux/fsl/enetc_mdio.h-39-\n"
}

5/2 2026/08/31 03:58 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 37738
							output: 41
							thoughts: 15
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Investigating the FSL_ENETC Kconfig Configuration**

Okay, so I need to refresh my memory on the specifics of FSL_ENETC. Time to dive into the `Kconfig` file. I'll need to confirm a few things. First, what are the dependencies? Are there any prerequisites that I'm overlooking? Next, I want to clarify the build options. What flags are relevant and how do they interact? I need to understand the impact of any conditional compilation, and what happens in different configurations. Specifically, I'm thinking about the implications for performance and power consumption. I should also see if there's any commentary on compatibility, or known issues. Hopefully the description is clear enough to pinpoint the correct settings for this specific project. It will be helpful to reference any relevant documentation or previous implementations of this driver in similar contexts, if present within the Kconfig file.



6/2 2026/08/31 03:58 tool read-file
0m Args:
{
  "File": "drivers/net/ethernet/freescale/enetc/Kconfig",
  "FirstLine": 1,
  "LineCount": 80
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0\n   2:\tconfig FSL_ENETC_CORE\n   3:\t\ttristate\n   4:\t\tselect NXP_NETC_LIB if NXP_NTMP\n   5:\t\thelp\n   6:\t\t  This module supports common functionality between the PF and VF\n   7:\t\t  drivers for the NXP ENETC controller.\n   8:\t\n   9:\t\t  If compiled as module (M), the module name is fsl-enetc-core.\n  10:\t\n  11:\tconfig NXP_ENETC_PF_COMMON\n  12:\t\ttristate\n  13:\t\tselect CRC_ITU_T\n  14:\t\thelp\n  15:\t\t  This module supports common functionality between drivers of\n  16:\t\t  different versions of NXP ENETC PF controllers.\n  17:\t\n  18:\t\t  If compiled as module (M), the module name is nxp-enetc-pf-common.\n  19:\t\n  20:\tconfig NXP_NETC_LIB\n  21:\t\ttristate\n  22:\t\thelp\n  23:\t\t  This module provides common functionalities for both ENETC and NETC\n  24:\t\t  Switch, such as NETC Table Management Protocol (NTMP) 2.0, common tc\n  25:\t\t  flower and debugfs interfaces and so on.\n  26:\t\n  27:\tconfig NXP_NTMP\n  28:\t\tbool\n  29:\t\n  30:\tconfig FSL_ENETC\n  31:\t\ttristate \"ENETC PF driver\"\n  32:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n  33:\t\tdepends on PCI_MSI\n  34:\t\tselect FSL_ENETC_CORE\n  35:\t\tselect FSL_ENETC_IERB\n  36:\t\tselect FSL_ENETC_MDIO\n  37:\t\tselect NXP_ENETC_PF_COMMON\n  38:\t\tselect PHYLINK\n  39:\t\tselect PCS_LYNX\n  40:\t\tselect DIMLIB\n  41:\t\thelp\n  42:\t\t  This driver supports NXP ENETC gigabit ethernet controller PCIe\n  43:\t\t  physical function (PF) devices, managing ENETC Ports at a privileged\n  44:\t\t  level.\n  45:\t\n  46:\t\t  If compiled as module (M), the module name is fsl-enetc.\n  47:\t\n  48:\tconfig NXP_ENETC4\n  49:\t\ttristate \"ENETC4 PF driver\"\n  50:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n  51:\t\tdepends on PCI_MSI\n  52:\t\tselect FSL_ENETC_CORE\n  53:\t\tselect FSL_ENETC_MDIO\n  54:\t\tselect NXP_ENETC_PF_COMMON\n  55:\t\tselect NXP_NTMP\n  56:\t\tselect PHYLINK\n  57:\t\tselect DIMLIB\n  58:\t\thelp\n  59:\t\t  This driver supports NXP ENETC devices with major revision 4. ENETC is\n  60:\t\t  as the NIC functionality in NETC, it supports virtualization/isolation\n  61:\t\t  based on PCIe Single Root IO Virtualization (SR-IOV) and a full range\n  62:\t\t  of TSN standards and NIC offload capabilities.\n  63:\t\n  64:\t\t  If compiled as module (M), the module name is nxp-enetc4.\n  65:\t\n  66:\tconfig FSL_ENETC_VF\n  67:\t\ttristate \"ENETC VF driver\"\n  68:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n  69:\t\tdepends on PCI_MSI\n  70:\t\tselect FSL_ENETC_CORE\n  71:\t\tselect FSL_ENETC_MDIO\n  72:\t\tselect NXP_NTMP\n  73:\t\tselect PHYLINK\n  74:\t\tselect DIMLIB\n  75:\t\tselect CRC_ITU_T\n  76:\t\thelp\n  77:\t\t  This driver supports NXP ENETC gigabit ethernet controller PCIe\n  78:\t\t  virtual function (VF) devices enabled by the ENETC PF driver.\n  79:\t\n  80:\t\t  If compiled as module (M), the module name is fsl-enetc-vf.\n"
}

7/2 2026/08/31 03:58 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 39098
							output: 119
							thoughts: 638
						

Thoughts:
**My Assessment: ENETC Driver Patch is Not Worth Fuzzing**

Okay, let me break this down. First, I need to make sure I understand the "WorthFuzzing" criteria. I have a checklist here: documentation, comments, decorative changes, unreachable code paths in virtualization, vendor-specific hardware requiring physical PCIe, and teardown callbacks. Got it.

Now, let's analyze this specific patch related to the NXP/Freescale ENETC driver. I know ENETC – it's an on-chip Ethernet controller, a PCIe endpoint. Specifically, it's found in NXP QorIQ Layerscape and i.MX/S32G automotive SoCs. The key here is *on-chip*. This is not a standard, emulated piece of hardware. I see the PCIe device IDs confirming this is NXP (0x1957, 0x1131).

My expertise tells me that *standard* QEMU, the kind used in these fuzzing environments (GCE, standard QEMU x86_64, arm64 virt machine), *does not* emulate NXP ENETC. They have virtio, e1000, etc., but not ENETC.  You'd need custom QEMU with specific NXP ENETC emulation, or to be running on an actual physical board with the NXP SoC.

Therefore, the ENETC driver code, residing in `drivers/net/ethernet/freescale/enetc/`, falls squarely into the "vendor-specific PCIe hardware not emulated in standard QEMU" category. The code path is unreachable in our standard virtualized fuzzing environments.

So, *WorthFuzzing* must be false in this case. The changes are entirely within the NXP/Freescale ENETC (Ethernet Controller) PF and VF drivers, meaning this patch is not relevant for fuzzing in a standard QEMU environment. The changes are in vendor-specific NIC drivers for NXP SoC hardware not emulated in standard QEMU or virtualized test environments like GCE.

Now, let's craft that `set-results` call...



8/2 2026/08/31 03:58 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch series modifies the NXP/Freescale ENETC Ethernet PF and VF drivers (drivers/net/ethernet/freescale/enetc/), adding support for ENETC v4 VF mailbox communications, MAC hash filtering, and link status notifications. These changes are specific to NXP ENETC PCIe hardware not emulated in standard QEMU or virtualized environments like GCE, making the modified code unreachable for fuzzing.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch series modifies the NXP/Freescale ENETC Ethernet PF and VF drivers (drivers/net/ethernet/freescale/enetc/), adding support for ENETC v4 VF mailbox communications, MAC hash filtering, and link status notifications. These changes are specific to NXP ENETC PCIe hardware not emulated in standard QEMU or virtualized environments like GCE, making the modified code unreachable for fuzzing.",
  "WorthFuzzing": false
}

9/1 2026/08/31 03:58 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)