| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/25 08:57 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch series modifies only the Marvell OcteonTX2 NIC driver (drivers/net/ethernet/marvell/octeontx2/nic/). This driver requires vendor-specific Cavium/Marvell OcteonTX2 physical ASIC/PCIe hardware (primarily ARM64 SoC/SmartNIC silicon) that is not emulated in standard virtualized fuzzing environments (QEMU/GCE), making the modified code structurally unreachable for syzkaller.",
"WorthFuzzing": false
} |
| 1/1 | 2026/09/25 08:57 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 1f60c40a3f415df94ede05c9b547c42901cc4723\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Fri Sep 25 08:57:45 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c\nindex 77543d472345e..50ec4542c4183 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c\n@@ -334,7 +334,7 @@ static int cn10k_outb_cpt_init(struct net_device *netdev)\n \t\t\t\t\t\tCN10K_CPT_LF_NQX(0));\n \n \t/* Set ipsec offload enabled for this device */\n-\tpf-\u003eflags |= OTX2_FLAG_IPSEC_OFFLOAD_ENABLED;\n+\totx2_set_flag(pf, OTX2_FLAG_IPSEC_OFFLOAD_ENABLED);\n \n \tcn10k_cpt_device_set_available(pf);\n \treturn 0;\n@@ -356,7 +356,7 @@ static int cn10k_outb_cpt_clean(struct otx2_nic *pf)\n \t}\n \n \t/* Set ipsec offload disabled for this device */\n-\tpf-\u003eflags \u0026= ~OTX2_FLAG_IPSEC_OFFLOAD_ENABLED;\n+\totx2_clear_flag(pf, OTX2_FLAG_IPSEC_OFFLOAD_ENABLED);\n \n \t/* Disable CPTLF Instruction Queue (IQ) */\n \tcn10k_outb_cptlf_iq_disable(pf);\n@@ -820,7 +820,7 @@ void cn10k_ipsec_clean(struct otx2_nic *pf)\n \tif (!is_dev_support_ipsec_offload(pf-\u003epdev))\n \t\treturn;\n \n-\tif (!(pf-\u003eflags \u0026 OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))\n+\tif (!otx2_test_flag(pf, OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))\n \t\treturn;\n \n \tif (pf-\u003eipsec.sa_workq) {\n@@ -945,7 +945,7 @@ bool cn10k_ipsec_transmit(struct otx2_nic *pf, struct netdev_queue *txq,\n \tu16 dlen;\n \n \t/* Check for IPSEC offload enabled */\n-\tif (!(pf-\u003eflags \u0026 OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))\n+\tif (!otx2_test_flag(pf, OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))\n \t\tgoto drop;\n \n \tsp = skb_sec_path(skb);\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c\nindex 175992188c18a..8b922d719491f 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c\n@@ -220,10 +220,10 @@ int otx2_set_mac_address(struct net_device *netdev, void *p)\n \t\teth_hw_addr_set(netdev, addr-\u003esa_data);\n \t\t/* update dmac field in vlan offload rule */\n \t\tif (netif_running(netdev) \u0026\u0026\n-\t\t pfvf-\u003eflags \u0026 OTX2_FLAG_RX_VLAN_SUPPORT)\n+\t\t otx2_test_flag(pfvf, OTX2_FLAG_RX_VLAN_SUPPORT))\n \t\t\totx2_install_rxvlan_offload_flow(pfvf);\n \t\t/* update dmac address in ntuple and DMAC filter list */\n-\t\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_DMACFLTR_SUPPORT)\n+\t\tif (otx2_test_flag(pfvf, OTX2_FLAG_DMACFLTR_SUPPORT))\n \t\t\totx2_dmacflt_update_pfmac_flow(pfvf);\n \t} else {\n \t\treturn -EPERM;\n@@ -275,8 +275,8 @@ int otx2_config_pause_frm(struct otx2_nic *pfvf)\n \t\tgoto unlock;\n \t}\n \n-\treq-\u003erx_pause = !!(pfvf-\u003eflags \u0026 OTX2_FLAG_RX_PAUSE_ENABLED);\n-\treq-\u003etx_pause = !!(pfvf-\u003eflags \u0026 OTX2_FLAG_TX_PAUSE_ENABLED);\n+\treq-\u003erx_pause = otx2_test_flag(pfvf, OTX2_FLAG_RX_PAUSE_ENABLED);\n+\treq-\u003etx_pause = otx2_test_flag(pfvf, OTX2_FLAG_TX_PAUSE_ENABLED);\n \treq-\u003eset = 1;\n \n \terr = otx2_sync_mbox_msg(\u0026pfvf-\u003embox);\n@@ -615,6 +615,138 @@ void otx2_get_mac_from_af(struct net_device *netdev)\n }\n EXPORT_SYMBOL(otx2_get_mac_from_af);\n \n+static int\n+otx2_nix_tmq_reg_write(struct otx2_nic *pfvf, int cnt,\n+\t\t u64 reg_addr[MAX_REGS_PER_MBOX_MSG],\n+\t\t u64 reg_val[MAX_REGS_PER_MBOX_MSG])\n+{\n+\tstruct mbox *mbox = \u0026pfvf-\u003embox;\n+\tstruct nix_txschq_config *req;\n+\tint i, err;\n+\n+\tmutex_lock(\u0026mbox-\u003elock);\n+\treq = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox);\n+\tif (!req) {\n+\t\tmutex_unlock(\u0026mbox-\u003elock);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\treq-\u003elvl = NIX_TXSCH_LVL_MDQ;\n+\treq-\u003enum_regs = cnt;\n+\n+\tfor (i = 0; i \u003c cnt; i++) {\n+\t\treq-\u003ereg[i] = reg_addr[i];\n+\t\treq-\u003eregval[i] = reg_val[i];\n+\t}\n+\n+\terr = otx2_sync_mbox_msg(mbox);\n+\tmutex_unlock(\u0026mbox-\u003elock);\n+\n+\treturn err;\n+}\n+\n+int otx2_nix_tm_clear_queue_shaper(struct otx2_nic *pfvf)\n+{\n+\tu64 reg_addr[MAX_REGS_PER_MBOX_MSG];\n+\tu64 reg_val[MAX_REGS_PER_MBOX_MSG];\n+\tint err, smq, i, cnt = 0;\n+\n+\tfor (i = 0; i \u003c pfvf-\u003ehw.txschq_cnt[NIX_TXSCH_LVL_SMQ]; i++) {\n+\t\tsmq = pfvf-\u003ehw.txschq_list[NIX_TXSCH_LVL_SMQ][i];\n+\n+\t\treg_addr[cnt] = NIX_AF_MDQX_PIR(smq);\n+\t\treg_val[cnt] = 0;\n+\t\tcnt++;\n+\n+\t\treg_addr[cnt] = NIX_AF_MDQX_CIR(smq);\n+\t\treg_val[cnt] = 0;\n+\t\tcnt++;\n+\n+\t\tif (cnt \u003c MAX_REGS_PER_MBOX_MSG - 1)\n+\t\t\tcontinue;\n+\n+\t\terr = otx2_nix_tmq_reg_write(pfvf, cnt,\n+\t\t\t\t\t reg_addr, reg_val);\n+\t\tif (err)\n+\t\t\tgoto fail;\n+\t\tcnt = 0;\n+\t}\n+\n+\tif (cnt) {\n+\t\terr = otx2_nix_tmq_reg_write(pfvf, cnt,\n+\t\t\t\t\t reg_addr, reg_val);\n+\t\tif (err)\n+\t\t\tgoto fail;\n+\t}\n+\n+\treturn 0;\n+fail:\n+\treturn err;\n+}\n+\n+int otx2_nix_tm_set_queue_shaper(struct otx2_nic *pfvf,\n+\t\t\t\t int txq, u64 minrate, u64 maxrate)\n+{\n+\tstruct mbox *mbox = \u0026pfvf-\u003embox;\n+\tstruct nix_txschq_config *req;\n+\tint err, smq, n = 0;\n+\tu64 reg_addr[2];\n+\tu64 reg_val[2];\n+\tu64 rate;\n+\n+\tif (!maxrate \u0026\u0026 !minrate) {\n+\t\tsmq = otx2_get_smq_idx(pfvf, txq);\n+\t\treg_addr[0] = NIX_AF_MDQX_PIR(smq);\n+\t\treg_val[0] = 0;\n+\t\treg_addr[1] = NIX_AF_MDQX_CIR(smq);\n+\t\treg_val[1] = 0;\n+\t\treturn otx2_nix_tmq_reg_write(pfvf, 2, reg_addr, reg_val);\n+\t}\n+\n+\tsmq = otx2_get_smq_idx(pfvf, txq);\n+\n+\tmutex_lock(\u0026mbox-\u003elock);\n+\treq = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox);\n+\tif (!req) {\n+\t\tmutex_unlock(\u0026mbox-\u003elock);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\treq-\u003elvl = NIX_TXSCH_LVL_MDQ;\n+\n+\t/* MQPRIO exposes only min/max rate, not burst. Use the same 65536\n+\t * byte default as the HTB shaper path.\n+\t *\n+\t * mqprio setup restarts the netdev (otx2_mqprio_restart_netdev),\n+\t * which resets MDQ shapers to zero. Program both PIR and CIR on\n+\t * every update so omitted rates are applied explicitly rather than\n+\t * relying on stale hardware state.\n+\t */\n+\treq-\u003ereg[n] = NIX_AF_MDQX_PIR(smq);\n+\tif (maxrate) {\n+\t\trate = otx2_convert_rate(maxrate);\n+\t\treq-\u003eregval[n] = otx2_get_txschq_rate_regval(pfvf, rate, 65536);\n+\t} else {\n+\t\treq-\u003eregval[n] = 0;\n+\t}\n+\tn++;\n+\n+\t/* CIR+PIR support is required and checked at mqprio setup. */\n+\treq-\u003ereg[n] = NIX_AF_MDQX_CIR(smq);\n+\tif (minrate) {\n+\t\trate = otx2_convert_rate(minrate);\n+\t\treq-\u003eregval[n] = otx2_get_txschq_rate_regval(pfvf, rate, 65536);\n+\t} else {\n+\t\treq-\u003eregval[n] = 0;\n+\t}\n+\tn++;\n+\treq-\u003enum_regs = n;\n+\n+\terr = otx2_sync_mbox_msg(mbox);\n+\tmutex_unlock(\u0026mbox-\u003elock);\n+\treturn err;\n+}\n+\n int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for_pfc)\n {\n \tu16 (*schq_list)[MAX_TXSCHQ_PER_FUNC];\n@@ -651,7 +783,11 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for\n \t\t\t\t\t\t(u64)hw-\u003esmq_link_type);\n \t\treq-\u003enum_regs++;\n \t\t/* MDQ config */\n-\t\tparent = schq_list[NIX_TXSCH_LVL_TL4][prio];\n+\t\tif (pfvf-\u003emqprio.rate_limit)\n+\t\t\tparent = schq_list[NIX_TXSCH_LVL_TL4][0];\n+\t\telse\n+\t\t\tparent = schq_list[NIX_TXSCH_LVL_TL4][prio];\n+\n \t\treq-\u003ereg[1] = NIX_AF_MDQX_PARENT(schq);\n \t\treq-\u003eregval[1] = parent \u003c\u003c 16;\n \t\treq-\u003enum_regs++;\n@@ -779,6 +915,9 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf)\n \t\treq-\u003eschq[NIX_TXSCH_LVL_TL4] = chan_cnt;\n \t}\n \n+\tif (pfvf-\u003emqprio.rate_limit)\n+\t\treq-\u003eschq[NIX_TXSCH_LVL_SMQ] = pfvf-\u003ehw.non_qos_queues;\n+\n \trc = otx2_sync_mbox_msg(\u0026pfvf-\u003embox);\n \tif (rc)\n \t\treturn rc;\n@@ -844,6 +983,7 @@ void otx2_txschq_stop(struct otx2_nic *pfvf)\n \n \t/* Clear the txschq list */\n \tfor (lvl = 0; lvl \u003c NIX_TXSCH_LVL_CNT; lvl++) {\n+\t\tpfvf-\u003ehw.txschq_cnt[lvl] = 0;\n \t\tfor (schq = 0; schq \u003c MAX_TXSCHQ_PER_FUNC; schq++)\n \t\t\tpfvf-\u003ehw.txschq_list[lvl][schq] = 0;\n \t}\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h\nindex 5850bc1870a1d..7bbb162fdffa7 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h\n@@ -17,6 +17,7 @@\n #include \u003clinux/soc/marvell/silicons.h\u003e\n #include \u003clinux/soc/marvell/octeontx2/asm.h\u003e\n #include \u003cnet/macsec.h\u003e\n+#include \u003cuapi/linux/pkt_sched.h\u003e\n #include \u003cnet/pkt_cls.h\u003e\n #include \u003cnet/devlink.h\u003e\n #include \u003clinux/time64.h\u003e\n@@ -482,6 +483,61 @@ struct pf_irq_data {\n \tint mdevs;\n };\n \n+enum otx2_flag_bits {\n+\tOTX2_FLAG_RX_TSTAMP_ENABLED,\n+\tOTX2_FLAG_TX_TSTAMP_ENABLED,\n+\tOTX2_FLAG_INTF_DOWN,\n+\tOTX2_FLAG_MCAM_ENTRIES_ALLOC,\n+\tOTX2_FLAG_NTUPLE_SUPPORT,\n+\tOTX2_FLAG_UCAST_FLTR_SUPPORT,\n+\tOTX2_FLAG_RX_VLAN_SUPPORT,\n+\tOTX2_FLAG_VF_VLAN_SUPPORT,\n+\tOTX2_FLAG_PF_SHUTDOWN,\n+\tOTX2_FLAG_RX_PAUSE_ENABLED,\n+\tOTX2_FLAG_TX_PAUSE_ENABLED,\n+\tOTX2_FLAG_TC_FLOWER_SUPPORT,\n+\tOTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED,\n+\tOTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED,\n+\tOTX2_FLAG_DMACFLTR_SUPPORT,\n+\tOTX2_FLAG_PTP_ONESTEP_SYNC,\n+\tOTX2_FLAG_ADPTV_INT_COAL_ENABLED,\n+\tOTX2_FLAG_TC_MARK_ENABLED,\n+\tOTX2_FLAG_REP_MODE_ENABLED,\n+\tOTX2_FLAG_PORT_UP,\n+\tOTX2_FLAG_IPSEC_OFFLOAD_ENABLED,\n+\tOTX2_FLAG_REP_VF_INITIALIZED,\n+\tOTX2_FLAG_MAX,\n+};\n+\n+/* Representor-owned flags copied onto the PF mailbox context in\n+ * rvu_rep_setup_tc_cb(). All other bits are owned by the PF/VF netdev.\n+ */\n+#define OTX2_REP_SYNC_FLAGS_MASK\t\t\t\t\\\n+\t(BIT(OTX2_FLAG_MCAM_ENTRIES_ALLOC) |\t\t\t\\\n+\t BIT(OTX2_FLAG_NTUPLE_SUPPORT) |\t\t\t\\\n+\t BIT(OTX2_FLAG_TC_FLOWER_SUPPORT) |\t\t\t\\\n+\t BIT(OTX2_FLAG_REP_VF_INITIALIZED))\n+\n+struct mq_offload_snap {\n+\tu64 min_rate[TC_QOPT_MAX_QUEUE];\n+\tu64 max_rate[TC_QOPT_MAX_QUEUE];\n+\tu32 flags;\n+\t__u8 num_tc;\n+\t__u16 count[TC_QOPT_MAX_QUEUE];\n+\t__u16 offset[TC_QOPT_MAX_QUEUE];\n+\t__u8 prio_tc_map[TC_QOPT_BITMASK + 1];\n+};\n+\n+struct otx2_mqprio {\n+\tu32\tflags;\n+\tu64\t*min_rate;\n+\tu64\t*max_rate;\n+\tbool\trate_limit;\n+\tbool\treplace_setup_done;\n+\tbool\treplace_graft_done;\n+\tstruct work_struct netdev_tc_work;\n+};\n+\n struct otx2_nic {\n \tvoid __iomem\t\t*reg_base;\n \tstruct net_device\t*netdev;\n@@ -490,30 +546,13 @@ struct otx2_nic {\n \tu16\t\t\ttx_max_pktlen;\n \tu16\t\t\trbsize; /* Receive buffer size */\n \n-#define OTX2_FLAG_RX_TSTAMP_ENABLED\t\tBIT_ULL(0)\n-#define OTX2_FLAG_TX_TSTAMP_ENABLED\t\tBIT_ULL(1)\n-#define OTX2_FLAG_INTF_DOWN\t\t\tBIT_ULL(2)\n-#define OTX2_FLAG_MCAM_ENTRIES_ALLOC\t\tBIT_ULL(3)\n-#define OTX2_FLAG_NTUPLE_SUPPORT\t\tBIT_ULL(4)\n-#define OTX2_FLAG_UCAST_FLTR_SUPPORT\t\tBIT_ULL(5)\n-#define OTX2_FLAG_RX_VLAN_SUPPORT\t\tBIT_ULL(6)\n-#define OTX2_FLAG_VF_VLAN_SUPPORT\t\tBIT_ULL(7)\n-#define OTX2_FLAG_PF_SHUTDOWN\t\t\tBIT_ULL(8)\n-#define OTX2_FLAG_RX_PAUSE_ENABLED\t\tBIT_ULL(9)\n-#define OTX2_FLAG_TX_PAUSE_ENABLED\t\tBIT_ULL(10)\n-#define OTX2_FLAG_TC_FLOWER_SUPPORT\t\tBIT_ULL(11)\n-#define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED\tBIT_ULL(12)\n-#define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED\tBIT_ULL(13)\n-#define OTX2_FLAG_DMACFLTR_SUPPORT\t\tBIT_ULL(14)\n-#define OTX2_FLAG_PTP_ONESTEP_SYNC\t\tBIT_ULL(15)\n-#define OTX2_FLAG_ADPTV_INT_COAL_ENABLED BIT_ULL(16)\n-#define OTX2_FLAG_TC_MARK_ENABLED\t\tBIT_ULL(17)\n-#define OTX2_FLAG_REP_MODE_ENABLED\t\t BIT_ULL(18)\n-#define OTX2_FLAG_PORT_UP\t\t\tBIT_ULL(19)\n-#define OTX2_FLAG_IPSEC_OFFLOAD_ENABLED\t\tBIT_ULL(20)\n-\tu64\t\t\tflags;\n+\tunsigned long\t\tflags;\n \tu64\t\t\t*cq_op_addr;\n \n+\tstruct otx2_mqprio\tmqprio;\n+\tstruct mq_offload_snap\t*cur_mq_snap;\n+\tstruct mq_offload_snap\t*old_mq_snap;\n+\n \tstruct bpf_prog\t\t*xdp_prog;\n \tstruct otx2_qset\tqset;\n \tstruct otx2_hw\t\thw;\n@@ -593,6 +632,32 @@ struct otx2_nic {\n \tunsigned long\t\t*af_xdp_zc_qidx;\n };\n \n+static inline void otx2_set_flag(struct otx2_nic *nic, unsigned int flag)\n+{\n+\tset_bit(flag, \u0026nic-\u003eflags);\n+}\n+\n+static inline void otx2_clear_flag(struct otx2_nic *nic, unsigned int flag)\n+{\n+\tclear_bit(flag, \u0026nic-\u003eflags);\n+}\n+\n+static inline bool otx2_test_flag(struct otx2_nic *nic, unsigned int flag)\n+{\n+\treturn test_bit(flag, \u0026nic-\u003eflags);\n+}\n+\n+static inline void otx2_sync_flags_from_rep(struct otx2_nic *dst,\n+\t\t\t\t\t unsigned long *src_flags)\n+{\n+\tunsigned long src = READ_ONCE(*src_flags);\n+\tunsigned long new_flags;\n+\n+\tnew_flags = (READ_ONCE(dst-\u003eflags) \u0026 ~OTX2_REP_SYNC_FLAGS_MASK) |\n+\t\t (src \u0026 OTX2_REP_SYNC_FLAGS_MASK);\n+\tWRITE_ONCE(dst-\u003eflags, new_flags);\n+}\n+\n static inline bool is_otx2_lbkvf(struct pci_dev *pdev)\n {\n \treturn (pdev-\u003edevice == PCI_DEVID_OCTEONTX2_RVU_AFVF) ||\n@@ -996,6 +1061,8 @@ static inline u16 otx2_get_smq_idx(struct otx2_nic *pfvf, u16 qidx)\n \tif (qidx \u003e= pfvf-\u003ehw.non_qos_queues) {\n \t\tsmq = pfvf-\u003eqos.qid_to_sqmap[qidx - pfvf-\u003ehw.non_qos_queues];\n \t} else {\n+\t\tif (!pfvf-\u003ehw.txschq_cnt[NIX_TXSCH_LVL_SMQ])\n+\t\t\treturn 0;\n \t\tidx = qidx % pfvf-\u003ehw.txschq_cnt[NIX_TXSCH_LVL_SMQ];\n \t\tsmq = pfvf-\u003ehw.txschq_list[NIX_TXSCH_LVL_SMQ][idx];\n \t}\n@@ -1245,6 +1312,11 @@ dma_addr_t otx2_dma_map_skb_frag(struct otx2_nic *pfvf,\n \t\t\t\t struct sk_buff *skb, int seg, int *len);\n void otx2_dma_unmap_skb_frags(struct otx2_nic *pfvf, struct sg_list *sg);\n int otx2_read_free_sqe(struct otx2_nic *pfvf, u16 qidx);\n+int otx2_nix_tm_set_queue_shaper(struct otx2_nic *pfvf, int txq,\n+\t\t\t\t u64 minrate, u64 maxrate);\n+int otx2_nix_tm_clear_queue_shaper(struct otx2_nic *pfvf);\n+int otx2_mqprio_down(struct otx2_nic *pfvf);\n+int otx2_mqprio_up(struct otx2_nic *pfvf);\n void otx2_queue_vf_work(struct mbox *mw, struct workqueue_struct *mbox_wq,\n \t\t\tint first, int mdevs, u64 intr);\n int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry,\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c\nindex 91d346d114af5..b7bd08129fb64 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c\n@@ -413,6 +413,12 @@ static int otx2_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc)\n \tu8 old_pfc_en;\n \tint err;\n \n+\tif (pfvf-\u003emqprio.rate_limit \u0026\u0026 pfc-\u003epfc_en) {\n+\t\tnetdev_err(dev,\n+\t\t\t \"PFC: cannot enable while mqprio bandwidth offload is active\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n \told_pfc_en = pfvf-\u003epfc_en;\n \tpfvf-\u003epfc_en = pfc-\u003epfc_en;\n \ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c\nindex 4a5ce0e67dda8..863a5ced9a26b 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c\n@@ -104,7 +104,7 @@ static int otx2_dl_ucast_flt_cnt_validate(struct devlink *devlink, u32 id,\n \tstruct otx2_nic *pfvf = otx2_dl-\u003epfvf;\n \n \t/* Check for UNICAST filter support*/\n-\tif (!(pfvf-\u003eflags \u0026 OTX2_FLAG_UCAST_FLTR_SUPPORT)) {\n+\tif (!otx2_test_flag(pfvf, OTX2_FLAG_UCAST_FLTR_SUPPORT)) {\n \t\tNL_SET_ERR_MSG_MOD(extack,\n \t\t\t\t \"Unicast filter not enabled\");\n \t\treturn -EINVAL;\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c\nindex a05dee0085a39..5428b3d1b3329 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c\n@@ -287,6 +287,14 @@ static int otx2_set_channels(struct net_device *dev,\n \t\treturn -EINVAL;\n \t}\n \n+\tif (pfvf-\u003emqprio.rate_limit \u0026\u0026\n+\t (channel-\u003etx_count != pfvf-\u003ehw.tx_queues ||\n+\t channel-\u003erx_count != pfvf-\u003ehw.rx_queues)) {\n+\t\tnetdev_info(dev,\n+\t\t\t \"Not permitted to change channel count while MQ prio is active\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n \tif (if_up)\n \t\tdev-\u003enetdev_ops-\u003endo_stop(dev);\n \n@@ -354,14 +362,14 @@ static int otx2_set_pauseparam(struct net_device *netdev,\n \t\treturn -EOPNOTSUPP;\n \n \tif (pause-\u003erx_pause)\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_RX_PAUSE_ENABLED;\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_RX_PAUSE_ENABLED);\n \telse\n-\t\tpfvf-\u003eflags \u0026= ~OTX2_FLAG_RX_PAUSE_ENABLED;\n+\t\totx2_clear_flag(pfvf, OTX2_FLAG_RX_PAUSE_ENABLED);\n \n \tif (pause-\u003etx_pause)\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_TX_PAUSE_ENABLED;\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_TX_PAUSE_ENABLED);\n \telse\n-\t\tpfvf-\u003eflags \u0026= ~OTX2_FLAG_TX_PAUSE_ENABLED;\n+\t\totx2_clear_flag(pfvf, OTX2_FLAG_TX_PAUSE_ENABLED);\n \n \treturn otx2_config_pause_frm(pfvf);\n }\n@@ -470,8 +478,7 @@ static int otx2_get_coalesce(struct net_device *netdev,\n \tcmd-\u003erx_max_coalesced_frames = hw-\u003ecq_ecount_wait;\n \tcmd-\u003etx_coalesce_usecs = hw-\u003ecq_time_wait;\n \tcmd-\u003etx_max_coalesced_frames = hw-\u003ecq_ecount_wait;\n-\tif ((pfvf-\u003eflags \u0026 OTX2_FLAG_ADPTV_INT_COAL_ENABLED) ==\n-\t\t\tOTX2_FLAG_ADPTV_INT_COAL_ENABLED) {\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED)) {\n \t\tcmd-\u003euse_adaptive_rx_coalesce = 1;\n \t\tcmd-\u003euse_adaptive_tx_coalesce = 1;\n \t} else {\n@@ -502,15 +509,14 @@ static int otx2_set_coalesce(struct net_device *netdev,\n \t}\n \n \t/* Check and update coalesce status */\n-\tif ((pfvf-\u003eflags \u0026 OTX2_FLAG_ADPTV_INT_COAL_ENABLED) ==\n-\t\t\tOTX2_FLAG_ADPTV_INT_COAL_ENABLED) {\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED)) {\n \t\tpriv_coalesce_status = 1;\n \t\tif (!ec-\u003euse_adaptive_rx_coalesce)\n-\t\t\tpfvf-\u003eflags \u0026= ~OTX2_FLAG_ADPTV_INT_COAL_ENABLED;\n+\t\t\totx2_clear_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED);\n \t} else {\n \t\tpriv_coalesce_status = 0;\n \t\tif (ec-\u003euse_adaptive_rx_coalesce)\n-\t\t\tpfvf-\u003eflags |= OTX2_FLAG_ADPTV_INT_COAL_ENABLED;\n+\t\t\totx2_set_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED);\n \t}\n \n \t/* 'cq_time_wait' is 8bit and is in multiple of 100ns,\n@@ -556,8 +562,7 @@ static int otx2_set_coalesce(struct net_device *netdev,\n \t * 'on' to 'off'.\n \t */\n \tif (priv_coalesce_status \u0026\u0026\n-\t ((pfvf-\u003eflags \u0026 OTX2_FLAG_ADPTV_INT_COAL_ENABLED) !=\n-\t OTX2_FLAG_ADPTV_INT_COAL_ENABLED)) {\n+\t (!otx2_test_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED))) {\n \t\thw-\u003ecq_time_wait = CQ_TIMER_THRESH_DEFAULT;\n \t\thw-\u003ecq_ecount_wait = CQ_CQE_THRESH_DEFAULT;\n \t}\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c\nindex 99d78fc5a2c4a..b8ff49f0f6e3b 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c\n@@ -270,9 +270,9 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)\n \tflow_cfg-\u003emax_flows = allocated;\n \n \tif (allocated) {\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_NTUPLE_SUPPORT;\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_TC_FLOWER_SUPPORT;\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC);\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_NTUPLE_SUPPORT);\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_TC_FLOWER_SUPPORT);\n \t}\n \n \tif (allocated != count)\n@@ -376,7 +376,7 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)\n \tflow_cfg-\u003eunicast_offset = vf_vlan_max_flows;\n \tflow_cfg-\u003erx_vlan_offset = flow_cfg-\u003eunicast_offset +\n \t\t\t\t\tflow_cfg-\u003eucast_flt_cnt;\n-\tpfvf-\u003eflags |= OTX2_FLAG_UCAST_FLTR_SUPPORT;\n+\totx2_set_flag(pfvf, OTX2_FLAG_UCAST_FLTR_SUPPORT);\n \n \t/* Check if NPC_DMAC field is supported\n \t * by the mkex profile before setting VLAN support flag.\n@@ -401,11 +401,11 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)\n \t}\n \n \tif (frsp-\u003eenable) {\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_RX_VLAN_SUPPORT;\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_VF_VLAN_SUPPORT;\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_RX_VLAN_SUPPORT);\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_VF_VLAN_SUPPORT);\n \t}\n \n-\tpfvf-\u003eflags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;\n+\totx2_set_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC);\n \tmutex_unlock(\u0026pfvf-\u003embox.lock);\n \n \t/* Allocate entries for Ntuple filters */\n@@ -415,7 +415,7 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)\n \t\treturn 0;\n \t}\n \n-\tpfvf-\u003eflags |= OTX2_FLAG_TC_FLOWER_SUPPORT;\n+\totx2_set_flag(pfvf, OTX2_FLAG_TC_FLOWER_SUPPORT);\n \n \trefcount_set(\u0026flow_cfg-\u003emark_flows, 1);\n \treturn 0;\n@@ -479,7 +479,7 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)\n \t\treturn err;\n \n \t/* Check if MCAM entries are allocate or not */\n-\tif (!(pf-\u003eflags \u0026 OTX2_FLAG_UCAST_FLTR_SUPPORT))\n+\tif (!otx2_test_flag(pf, OTX2_FLAG_UCAST_FLTR_SUPPORT))\n \t\treturn 0;\n \n \tpf-\u003emac_table = devm_kzalloc(pf-\u003edev, sizeof(struct otx2_mac_table)\n@@ -501,7 +501,7 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)\n \tif (!pf-\u003eflow_cfg-\u003ebmap_to_dmacindex)\n \t\treturn -ENOMEM;\n \n-\tpf-\u003eflags |= OTX2_FLAG_DMACFLTR_SUPPORT;\n+\totx2_set_flag(pf, OTX2_FLAG_DMACFLTR_SUPPORT);\n \n \treturn 0;\n }\n@@ -521,7 +521,7 @@ static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac)\n \tstruct npc_install_flow_req *req;\n \tint err, i;\n \n-\tif (!(pf-\u003eflags \u0026 OTX2_FLAG_UCAST_FLTR_SUPPORT))\n+\tif (!otx2_test_flag(pf, OTX2_FLAG_UCAST_FLTR_SUPPORT))\n \t\treturn -ENOMEM;\n \n \t/* dont have free mcam entries or uc list is greater than alloted */\n@@ -1167,7 +1167,7 @@ static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,\n \tu64 ring_cookie = fsp-\u003ering_cookie;\n \tu32 flow_type;\n \n-\tif (!(pfvf-\u003eflags \u0026 OTX2_FLAG_DMACFLTR_SUPPORT))\n+\tif (!otx2_test_flag(pfvf, OTX2_FLAG_DMACFLTR_SUPPORT))\n \t\treturn false;\n \n \tflow_type = fsp-\u003eflow_type \u0026 ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);\n@@ -1364,7 +1364,7 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)\n \t}\n \n \tring = ethtool_get_flow_spec_ring(fsp-\u003ering_cookie);\n-\tif (!(pfvf-\u003eflags \u0026 OTX2_FLAG_NTUPLE_SUPPORT))\n+\tif (!otx2_test_flag(pfvf, OTX2_FLAG_NTUPLE_SUPPORT))\n \t\treturn -ENOMEM;\n \n \t/* Number of queues on a VF can be greater or less than\n@@ -1596,7 +1596,7 @@ int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf)\n \tstruct otx2_flow *iter, *tmp;\n \tint err;\n \n-\tif (!(pfvf-\u003eflags \u0026 OTX2_FLAG_NTUPLE_SUPPORT))\n+\tif (!otx2_test_flag(pfvf, OTX2_FLAG_NTUPLE_SUPPORT))\n \t\treturn 0;\n \n \tif (!flow_cfg-\u003emax_flows)\n@@ -1629,7 +1629,7 @@ int otx2_destroy_mcam_flows(struct otx2_nic *pfvf)\n \tstruct otx2_flow *iter, *tmp;\n \tint err;\n \n-\tif (!(pfvf-\u003eflags \u0026 OTX2_FLAG_MCAM_ENTRIES_ALLOC))\n+\tif (!otx2_test_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC))\n \t\treturn 0;\n \n \t/* remove all flows */\n@@ -1658,7 +1658,7 @@ int otx2_destroy_mcam_flows(struct otx2_nic *pfvf)\n \t\treturn err;\n \t}\n \n-\tpfvf-\u003eflags \u0026= ~OTX2_FLAG_MCAM_ENTRIES_ALLOC;\n+\totx2_clear_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC);\n \tflow_cfg-\u003emax_flows = 0;\n \tmutex_unlock(\u0026pfvf-\u003embox.lock);\n \n@@ -1721,7 +1721,7 @@ int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable)\n \tint err;\n \n \t/* Dont have enough mcam entries */\n-\tif (!(pf-\u003eflags \u0026 OTX2_FLAG_RX_VLAN_SUPPORT))\n+\tif (!otx2_test_flag(pf, OTX2_FLAG_RX_VLAN_SUPPORT))\n \t\treturn -ENOMEM;\n \n \tif (enable) {\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c\nindex c0e2100de1d93..5f1d8287b00e4 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c\n@@ -879,7 +879,7 @@ static void otx2_handle_link_event(struct otx2_nic *pf)\n \tstruct cgx_link_user_info *linfo = \u0026pf-\u003elinfo;\n \tstruct net_device *netdev = pf-\u003enetdev;\n \n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_PORT_UP)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_PORT_UP))\n \t\treturn;\n \n \tpr_info(\"%s NIC Link is %s %d Mbps %s duplex\\n\", netdev-\u003ename,\n@@ -907,11 +907,11 @@ static int otx2_mbox_up_handler_rep_event_up_notify(struct otx2_nic *pf,\n \n \tif (info-\u003eevent == RVU_EVENT_PORT_STATE) {\n \t\tif (info-\u003eevt_data.port_state) {\n-\t\t\tpf-\u003eflags |= OTX2_FLAG_PORT_UP;\n+\t\t\totx2_set_flag(pf, OTX2_FLAG_PORT_UP);\n \t\t\tnetif_carrier_on(netdev);\n \t\t\tnetif_tx_start_all_queues(netdev);\n \t\t} else {\n-\t\t\tpf-\u003eflags \u0026= ~OTX2_FLAG_PORT_UP;\n+\t\t\totx2_clear_flag(pf, OTX2_FLAG_PORT_UP);\n \t\t\tnetif_tx_stop_all_queues(netdev);\n \t\t\tnetif_carrier_off(netdev);\n \t\t}\n@@ -953,7 +953,7 @@ int otx2_mbox_up_handler_cgx_link_event(struct otx2_nic *pf,\n \t}\n \n \t/* interface has not been fully configured yet */\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_INTF_DOWN))\n \t\treturn 0;\n \n \totx2_handle_link_event(pf);\n@@ -1828,7 +1828,7 @@ void otx2_free_hw_resources(struct otx2_nic *pf)\n \tfree_req = otx2_mbox_alloc_msg_nix_lf_free(mbox);\n \tif (free_req) {\n \t\tfree_req-\u003eflags = NIX_LF_DISABLE_FLOWS | NIX_LF_DONT_FREE_DFT_IDXS;\n-\t\tif (!(pf-\u003eflags \u0026 OTX2_FLAG_PF_SHUTDOWN))\n+\t\tif (!otx2_test_flag(pf, OTX2_FLAG_PF_SHUTDOWN))\n \t\t\tfree_req-\u003eflags |= NIX_LF_DONT_FREE_TX_VTAG;\n \t\tif (otx2_sync_mbox_msg(mbox))\n \t\t\tdev_err(pf-\u003edev, \"%s failed to free nixlf\\n\", __func__);\n@@ -2007,6 +2007,15 @@ int otx2_open(struct net_device *netdev)\n \tif (err)\n \t\tgoto err_free_mem;\n \n+\t/* Fail closed: abort open if cached mqprio shapers cannot be restored. */\n+\terr = otx2_mqprio_up(pf);\n+\tif (err) {\n+\t\tnetdev_err(pf-\u003enetdev,\n+\t\t\t \"mqprio: failed to restore shapers during open: %d\\n\",\n+\t\t\t err);\n+\t\tgoto err_free_hw;\n+\t}\n+\n \t/* Register NAPI handler */\n \tfor (qidx = 0; qidx \u003c pf-\u003ehw.cint_cnt; qidx++) {\n \t\tcq_poll = \u0026qset-\u003enapi[qidx];\n@@ -2135,21 +2144,21 @@ int otx2_open(struct net_device *netdev)\n \t}\n \totx2_write64(pf, NIX_LF_RAS_ENA_W1S, NIX_LF_RAS_MASK);\n \n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_RX_VLAN_SUPPORT)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_RX_VLAN_SUPPORT))\n \t\totx2_enable_rxvlan(pf, true);\n \n \t/* When reinitializing enable time stamping if it is enabled before */\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_TX_TSTAMP_ENABLED) {\n-\t\tpf-\u003eflags \u0026= ~OTX2_FLAG_TX_TSTAMP_ENABLED;\n+\tif (otx2_test_flag(pf, OTX2_FLAG_TX_TSTAMP_ENABLED)) {\n+\t\totx2_clear_flag(pf, OTX2_FLAG_TX_TSTAMP_ENABLED);\n \t\totx2_config_hw_tx_tstamp(pf, true);\n \t}\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_RX_TSTAMP_ENABLED) {\n-\t\tpf-\u003eflags \u0026= ~OTX2_FLAG_RX_TSTAMP_ENABLED;\n+\tif (otx2_test_flag(pf, OTX2_FLAG_RX_TSTAMP_ENABLED)) {\n+\t\totx2_clear_flag(pf, OTX2_FLAG_RX_TSTAMP_ENABLED);\n \t\totx2_config_hw_rx_tstamp(pf, true);\n \t}\n \n-\tpf-\u003eflags \u0026= ~OTX2_FLAG_INTF_DOWN;\n-\tpf-\u003eflags \u0026= ~OTX2_FLAG_PORT_UP;\n+\totx2_clear_flag(pf, OTX2_FLAG_INTF_DOWN);\n+\totx2_clear_flag(pf, OTX2_FLAG_PORT_UP);\n \t/* 'intf_down' may be checked on any cpu */\n \tsmp_wmb();\n \n@@ -2161,7 +2170,7 @@ int otx2_open(struct net_device *netdev)\n \t\totx2_handle_link_event(pf);\n \n \t/* Install DMAC Filters */\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_DMACFLTR_SUPPORT)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_DMACFLTR_SUPPORT))\n \t\totx2_dmacflt_reinstall_flows(pf);\n \n \totx2_tc_apply_ingress_police_rules(pf);\n@@ -2186,7 +2195,7 @@ int otx2_open(struct net_device *netdev)\n err_tx_stop_queues:\n \tnetif_tx_stop_all_queues(netdev);\n \tnetif_carrier_off(netdev);\n-\tpf-\u003eflags |= OTX2_FLAG_INTF_DOWN;\n+\totx2_set_flag(pf, OTX2_FLAG_INTF_DOWN);\n \t/* free NIXLF POISON irq */\n \tvec = pci_irq_vector(pf-\u003epdev,\n \t\t\t pf-\u003ehw.nix_msixoff + NIX_LF_POISON_VEC);\n@@ -2205,6 +2214,7 @@ int otx2_open(struct net_device *netdev)\n \tfree_irq(vec, pf);\n err_disable_napi:\n \totx2_disable_napi(pf);\n+err_free_hw:\n \totx2_free_hw_resources(pf);\n err_free_mem:\n \totx2_free_queue_mem(qset);\n@@ -2220,13 +2230,13 @@ int otx2_stop(struct net_device *netdev)\n \tint qidx, vec, wrk;\n \n \t/* If the DOWN flag is set resources are already freed */\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_INTF_DOWN))\n \t\treturn 0;\n \n \tnetif_carrier_off(netdev);\n \tnetif_tx_stop_all_queues(netdev);\n \n-\tpf-\u003eflags |= OTX2_FLAG_INTF_DOWN;\n+\totx2_set_flag(pf, OTX2_FLAG_INTF_DOWN);\n \t/* 'intf_down' may be checked on any cpu */\n \tsmp_wmb();\n \n@@ -2280,6 +2290,7 @@ int otx2_stop(struct net_device *netdev)\n \tfor (qidx = 0; qidx \u003c netdev-\u003enum_tx_queues; qidx++)\n \t\tnetdev_tx_reset_queue(netdev_get_tx_queue(netdev, qidx));\n \n+\tsynchronize_net();\n \totx2_free_queue_mem(qset);\n \t/* Do not clear RQ/SQ ringsize settings */\n \tmemset_startat(qset, 0, sqe_cnt);\n@@ -2457,7 +2468,7 @@ static int otx2_config_hw_rx_tstamp(struct otx2_nic *pfvf, bool enable)\n \tstruct msg_req *req;\n \tint err;\n \n-\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_RX_TSTAMP_ENABLED \u0026\u0026 enable)\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_RX_TSTAMP_ENABLED) \u0026\u0026 enable)\n \t\treturn 0;\n \n \tmutex_lock(\u0026pfvf-\u003embox.lock);\n@@ -2478,9 +2489,9 @@ static int otx2_config_hw_rx_tstamp(struct otx2_nic *pfvf, bool enable)\n \n \tmutex_unlock(\u0026pfvf-\u003embox.lock);\n \tif (enable)\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_RX_TSTAMP_ENABLED;\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_RX_TSTAMP_ENABLED);\n \telse\n-\t\tpfvf-\u003eflags \u0026= ~OTX2_FLAG_RX_TSTAMP_ENABLED;\n+\t\totx2_clear_flag(pfvf, OTX2_FLAG_RX_TSTAMP_ENABLED);\n \treturn 0;\n }\n \n@@ -2489,7 +2500,7 @@ static int otx2_config_hw_tx_tstamp(struct otx2_nic *pfvf, bool enable)\n \tstruct msg_req *req;\n \tint err;\n \n-\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_TX_TSTAMP_ENABLED \u0026\u0026 enable)\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_TX_TSTAMP_ENABLED) \u0026\u0026 enable)\n \t\treturn 0;\n \n \tmutex_lock(\u0026pfvf-\u003embox.lock);\n@@ -2510,9 +2521,9 @@ static int otx2_config_hw_tx_tstamp(struct otx2_nic *pfvf, bool enable)\n \n \tmutex_unlock(\u0026pfvf-\u003embox.lock);\n \tif (enable)\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_TX_TSTAMP_ENABLED;\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_TX_TSTAMP_ENABLED);\n \telse\n-\t\tpfvf-\u003eflags \u0026= ~OTX2_FLAG_TX_TSTAMP_ENABLED;\n+\t\totx2_clear_flag(pfvf, OTX2_FLAG_TX_TSTAMP_ENABLED);\n \treturn 0;\n }\n \n@@ -2537,8 +2548,8 @@ int otx2_config_hwtstamp_set(struct net_device *netdev,\n \n \tswitch (config-\u003etx_type) {\n \tcase HWTSTAMP_TX_OFF:\n-\t\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_PTP_ONESTEP_SYNC)\n-\t\t\tpfvf-\u003eflags \u0026= ~OTX2_FLAG_PTP_ONESTEP_SYNC;\n+\t\tif (otx2_test_flag(pfvf, OTX2_FLAG_PTP_ONESTEP_SYNC))\n+\t\t\totx2_clear_flag(pfvf, OTX2_FLAG_PTP_ONESTEP_SYNC);\n \n \t\tcancel_delayed_work(\u0026pfvf-\u003eptp-\u003esynctstamp_work);\n \t\totx2_config_hw_tx_tstamp(pfvf, false);\n@@ -2549,7 +2560,7 @@ int otx2_config_hwtstamp_set(struct net_device *netdev,\n \t\t\t\t\t \"One-step time stamping is not supported\");\n \t\t\treturn -ERANGE;\n \t\t}\n-\t\tpfvf-\u003eflags |= OTX2_FLAG_PTP_ONESTEP_SYNC;\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_PTP_ONESTEP_SYNC);\n \t\tschedule_delayed_work(\u0026pfvf-\u003eptp-\u003esynctstamp_work,\n \t\t\t\t msecs_to_jiffies(500));\n \t\tfallthrough;\n@@ -2835,7 +2846,7 @@ static int otx2_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos,\n \tif (proto != htons(ETH_P_8021Q))\n \t\treturn -EPROTONOSUPPORT;\n \n-\tif (!(pf-\u003eflags \u0026 OTX2_FLAG_VF_VLAN_SUPPORT))\n+\tif (!otx2_test_flag(pf, OTX2_FLAG_VF_VLAN_SUPPORT))\n \t\treturn -EOPNOTSUPP;\n \n \treturn otx2_do_set_vf_vlan(pf, vf, vlan, qos, proto);\n@@ -2923,6 +2934,12 @@ static int otx2_xdp_setup(struct otx2_nic *pf, struct bpf_prog *prog)\n \tbool if_up = netif_running(pf-\u003enetdev);\n \tstruct bpf_prog *old_prog;\n \n+\tif (prog \u0026\u0026 pf-\u003emqprio.rate_limit) {\n+\t\tnetdev_err(dev,\n+\t\t\t \"XDP: cannot attach while mqprio bandwidth offload is active\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n \tif (prog \u0026\u0026 dev-\u003emtu \u003e MAX_XDP_MTU) {\n \t\tnetdev_warn(dev, \"Jumbo frames not yet supported with XDP\\n\");\n \t\treturn -EOPNOTSUPP;\n@@ -3086,7 +3103,7 @@ int otx2_realloc_msix_vectors(struct otx2_nic *pf)\n \t * interrupt range (QINT, CINT, GINT, ERR and POISON vectors).\n \t */\n \tnum_vec = hw-\u003enix_msixoff;\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_REP_MODE_ENABLED)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_REP_MODE_ENABLED))\n \t\tnum_vec += NIX_LF_CINT_VEC_START + hw-\u003emax_queues;\n \telse\n \t\tnum_vec += NIX_LF_POISON_VEC + 1;\n@@ -3273,7 +3290,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \tpf-\u003epdev = pdev;\n \tpf-\u003edev = dev;\n \tpf-\u003etotal_vfs = pci_sriov_get_totalvfs(pdev);\n-\tpf-\u003eflags |= OTX2_FLAG_INTF_DOWN;\n+\totx2_set_flag(pf, OTX2_FLAG_INTF_DOWN);\n \n \thw = \u0026pf-\u003ehw;\n \thw-\u003epdev = pdev;\n@@ -3328,24 +3345,26 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \tif (err)\n \t\tgoto err_del_mcam_entries;\n \n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_NTUPLE_SUPPORT)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_NTUPLE_SUPPORT))\n \t\tnetdev-\u003ehw_features |= NETIF_F_NTUPLE;\n \n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_UCAST_FLTR_SUPPORT)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_UCAST_FLTR_SUPPORT))\n \t\tnetdev-\u003epriv_flags |= IFF_UNICAST_FLT;\n \n \t/* Support TSO on tag interface */\n \tnetdev-\u003evlan_features |= netdev-\u003efeatures;\n \tnetdev-\u003ehw_features |= NETIF_F_HW_VLAN_CTAG_TX |\n \t\t\t\tNETIF_F_HW_VLAN_STAG_TX;\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_RX_VLAN_SUPPORT)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_RX_VLAN_SUPPORT))\n \t\tnetdev-\u003ehw_features |= NETIF_F_HW_VLAN_CTAG_RX |\n \t\t\t\t NETIF_F_HW_VLAN_STAG_RX;\n \tnetdev-\u003efeatures |= netdev-\u003ehw_features;\n \n \t/* HW supports tc offload but mutually exclusive with n-tuple filters */\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_TC_FLOWER_SUPPORT)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_TC_FLOWER_SUPPORT)) {\n \t\tnetdev-\u003ehw_features |= NETIF_F_HW_TC;\n+\t\tnetdev-\u003efeatures |= NETIF_F_HW_TC;\n+\t}\n \n \tnetdev-\u003ehw_features |= NETIF_F_LOOPBACK | NETIF_F_RXALL;\n \n@@ -3368,10 +3387,14 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \tif (err)\n \t\tgoto err_mcs_free;\n \n+\terr = otx2_init_tc(pf);\n+\tif (err)\n+\t\tgoto err_ipsec_clean;\n+\n \terr = register_netdev(netdev);\n \tif (err) {\n \t\tdev_err(dev, \"Failed to register netdevice\\n\");\n-\t\tgoto err_ipsec_clean;\n+\t\tgoto err_shutdown_tc;\n \t}\n \n \terr = otx2_wq_init(pf);\n@@ -3380,10 +3403,6 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \n \totx2_set_ethtool_ops(netdev);\n \n-\terr = otx2_init_tc(pf);\n-\tif (err)\n-\t\tgoto err_mcam_flow_del;\n-\n \terr = otx2_register_dl(pf);\n \tif (err)\n \t\tgoto err_mcam_flow_del;\n@@ -3420,11 +3439,13 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \totx2_sriov_vfcfg_cleanup(pf);\n err_pf_sriov_init:\n \totx2_unregister_dl(pf);\n-\totx2_shutdown_tc(pf);\n err_mcam_flow_del:\n \totx2_mcam_flow_del(pf);\n err_unreg_netdev:\n+\totx2_shutdown_tc(pf);\n \tunregister_netdev(netdev);\n+err_shutdown_tc:\n+\totx2_shutdown_tc(pf);\n err_ipsec_clean:\n \tcn10k_ipsec_clean(pf);\n err_mcs_free:\n@@ -3595,18 +3616,18 @@ static void otx2_remove(struct pci_dev *pdev)\n \n \tpf = netdev_priv(netdev);\n \n-\tpf-\u003eflags |= OTX2_FLAG_PF_SHUTDOWN;\n+\totx2_set_flag(pf, OTX2_FLAG_PF_SHUTDOWN);\n \n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_TX_TSTAMP_ENABLED)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_TX_TSTAMP_ENABLED))\n \t\totx2_config_hw_tx_tstamp(pf, false);\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_RX_TSTAMP_ENABLED)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_RX_TSTAMP_ENABLED))\n \t\totx2_config_hw_rx_tstamp(pf, false);\n \n \t/* Disable 802.3x pause frames */\n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_RX_PAUSE_ENABLED ||\n-\t (pf-\u003eflags \u0026 OTX2_FLAG_TX_PAUSE_ENABLED)) {\n-\t\tpf-\u003eflags \u0026= ~OTX2_FLAG_RX_PAUSE_ENABLED;\n-\t\tpf-\u003eflags \u0026= ~OTX2_FLAG_TX_PAUSE_ENABLED;\n+\tif (otx2_test_flag(pf, OTX2_FLAG_RX_PAUSE_ENABLED) ||\n+\t otx2_test_flag(pf, OTX2_FLAG_TX_PAUSE_ENABLED)) {\n+\t\totx2_clear_flag(pf, OTX2_FLAG_RX_PAUSE_ENABLED);\n+\t\totx2_clear_flag(pf, OTX2_FLAG_TX_PAUSE_ENABLED);\n \t\totx2_config_pause_frm(pf);\n \t}\n \n@@ -3622,6 +3643,7 @@ static void otx2_remove(struct pci_dev *pdev)\n \totx2_cgx_config_linkevents(pf, false);\n \n \totx2_unregister_dl(pf);\n+\totx2_shutdown_tc(pf);\n \tunregister_netdev(netdev);\n \tcn10k_ipsec_clean(pf);\n \tcn10k_mcs_free(pf);\n@@ -3632,7 +3654,6 @@ static void otx2_remove(struct pci_dev *pdev)\n \n \totx2_ptp_destroy(pf);\n \totx2_mcam_flow_del(pf);\n-\totx2_shutdown_tc(pf);\n \totx2_shutdown_qos(pf);\n \totx2_ndc_sync(pf);\n \totx2_detach_resources(\u0026pf-\u003embox);\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c\nindex 039fd47ebf522..453c598c6c5db 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c\n@@ -6,6 +6,8 @@\n */\n \n #include \u003clinux/netdevice.h\u003e\n+#include \u003clinux/rtnetlink.h\u003e\n+#include \u003clinux/string.h\u003e\n #include \u003clinux/etherdevice.h\u003e\n #include \u003clinux/inetdevice.h\u003e\n #include \u003clinux/rhashtable.h\u003e\n@@ -16,6 +18,7 @@\n #include \u003cnet/tc_act/tc_mirred.h\u003e\n #include \u003cnet/tc_act/tc_vlan.h\u003e\n #include \u003cnet/ipv6.h\u003e\n+#include \u003cnet/pkt_sched.h\u003e\n \n #include \"cn10k.h\"\n #include \"otx2_common.h\"\n@@ -31,6 +34,19 @@\n \n #define MCAST_INVALID_GRP\t\t(-1U)\n #define RATE_MANTISSA_BITS\t\t8\n+/* Min per-queue egress shaping rate the NIX TLX encoder supports (2 Mbps). */\n+#define OTX2_MQPRIO_MIN_RATE_BYTES_PS\t250000ULL\n+\n+static u64 otx2_mqprio_max_rate_bytes_ps(void)\n+{\n+\tu64 max_mbps;\n+\n+\t/* NIX TLX maximum rate (Mbps), not the burst bucket cap. */\n+\tmax_mbps = 2ULL * ((256ULL + MAX_RATE_MANTISSA) \u003c\u003c MAX_RATE_EXPONENT) /\n+\t\t 256ULL;\n+\n+\treturn div_u64(max_mbps * 1000000ULL, 8ULL);\n+}\n \n static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,\n \t\t\t\t u32 *burst_exp, u32 *burst_mantissa)\n@@ -61,6 +77,9 @@ static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,\n \t\t\t*burst_mantissa = tmp / (1ULL \u003c\u003c (*burst_exp - 7));\n \t\t}\n \t} else {\n+\t\t/* burst 0: largest encodable burst (CN10K_MAX_BURST_SIZE on\n+\t\t * CN10K), not a minimal burst.\n+\t\t */\n \t\t*burst_exp = MAX_BURST_EXPONENT;\n \t\t*burst_mantissa = max_mantissa;\n \t}\n@@ -159,7 +178,7 @@ static int otx2_tc_validate_flow(struct otx2_nic *nic,\n \t\t\t\t struct flow_action *actions,\n \t\t\t\t struct netlink_ext_ack *extack)\n {\n-\tif (nic-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN) {\n+\tif (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN)) {\n \t\tNL_SET_ERR_MSG_MOD(extack, \"Interface not initialized\");\n \t\treturn -EINVAL;\n \t}\n@@ -223,7 +242,7 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,\n \tif (err)\n \t\treturn err;\n \n-\tif (nic-\u003eflags \u0026 OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED) {\n+\tif (otx2_test_flag(nic, OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED)) {\n \t\tNL_SET_ERR_MSG_MOD(extack,\n \t\t\t\t \"Only one Egress MATCHALL ratelimiter can be offloaded\");\n \t\treturn -ENOMEM;\n@@ -244,7 +263,7 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,\n \t\t\t\t\t\t otx2_convert_rate(entry-\u003epolice.rate_bytes_ps));\n \t\tif (err)\n \t\t\treturn err;\n-\t\tnic-\u003eflags |= OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED;\n+\t\totx2_set_flag(nic, OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED);\n \t\tbreak;\n \tdefault:\n \t\tNL_SET_ERR_MSG_MOD(extack,\n@@ -261,13 +280,13 @@ static int otx2_tc_egress_matchall_delete(struct otx2_nic *nic,\n \tstruct netlink_ext_ack *extack = cls-\u003ecommon.extack;\n \tint err;\n \n-\tif (nic-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN) {\n+\tif (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN)) {\n \t\tNL_SET_ERR_MSG_MOD(extack, \"Interface not initialized\");\n \t\treturn -EINVAL;\n \t}\n \n \terr = otx2_set_matchall_egress_rate(nic, 0, 0);\n-\tnic-\u003eflags \u0026= ~OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED;\n+\totx2_clear_flag(nic, OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED);\n \treturn err;\n }\n \n@@ -505,7 +524,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,\n \t\t\tmark = act-\u003emark;\n \t\t\treq-\u003ematch_id = mark \u0026 OTX2_RX_MATCH_ID_MASK;\n \t\t\treq-\u003eop = NIX_RX_ACTION_DEFAULT;\n-\t\t\tnic-\u003eflags |= OTX2_FLAG_TC_MARK_ENABLED;\n+\t\t\totx2_set_flag(nic, OTX2_FLAG_TC_MARK_ENABLED);\n \t\t\trefcount_inc(\u0026nic-\u003eflow_cfg-\u003emark_flows);\n \t\t\tbreak;\n \n@@ -942,7 +961,7 @@ static void otx2_destroy_tc_flow_list(struct otx2_nic *pfvf)\n \tstruct otx2_flow_config *flow_cfg = pfvf-\u003eflow_cfg;\n \tstruct otx2_tc_flow *iter, *tmp;\n \n-\tif (!(pfvf-\u003eflags \u0026 OTX2_FLAG_MCAM_ENTRIES_ALLOC))\n+\tif (!otx2_test_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC))\n \t\treturn;\n \n \tlist_for_each_entry_safe(iter, tmp, \u0026flow_cfg-\u003eflow_list_tc, list) {\n@@ -1195,12 +1214,12 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,\n \t/* Disable TC MARK flag if they are no rules with skbedit mark action */\n \tif (flow_node-\u003ereq.match_id)\n \t\tif (!refcount_dec_and_test(\u0026flow_cfg-\u003emark_flows))\n-\t\t\tnic-\u003eflags \u0026= ~OTX2_FLAG_TC_MARK_ENABLED;\n+\t\t\totx2_clear_flag(nic, OTX2_FLAG_TC_MARK_ENABLED);\n \n \tif (flow_node-\u003eis_act_police) {\n \t\t__clear_bit(flow_node-\u003erq, \u0026nic-\u003erq_bmap);\n \n-\t\tif (nic-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN)\n+\t\tif (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN))\n \t\t\tgoto free_mcam_flow;\n \n \t\tmutex_lock(\u0026nic-\u003embox.lock);\n@@ -1246,10 +1265,10 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,\n \tstruct npc_install_flow_req *req, dummy;\n \tint rc, err, entry;\n \n-\tif (!(nic-\u003eflags \u0026 OTX2_FLAG_TC_FLOWER_SUPPORT))\n+\tif (!otx2_test_flag(nic, OTX2_FLAG_TC_FLOWER_SUPPORT))\n \t\treturn -ENOMEM;\n \n-\tif (nic-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN) {\n+\tif (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN)) {\n \t\tNL_SET_ERR_MSG_MOD(extack, \"Interface not initialized\");\n \t\treturn -EINVAL;\n \t}\n@@ -1444,7 +1463,7 @@ static int otx2_tc_ingress_matchall_install(struct otx2_nic *nic,\n \tif (err)\n \t\treturn err;\n \n-\tif (nic-\u003eflags \u0026 OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED) {\n+\tif (otx2_test_flag(nic, OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED)) {\n \t\tNL_SET_ERR_MSG_MOD(extack,\n \t\t\t\t \"Only one ingress MATCHALL ratelimitter can be offloaded\");\n \t\treturn -ENOMEM;\n@@ -1469,7 +1488,7 @@ static int otx2_tc_ingress_matchall_install(struct otx2_nic *nic,\n \t\terr = cn10k_set_matchall_ipolicer_rate(nic, entry-\u003epolice.burst, rate);\n \t\tif (err)\n \t\t\treturn err;\n-\t\tnic-\u003eflags |= OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED;\n+\t\totx2_set_flag(nic, OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED);\n \t\tbreak;\n \tdefault:\n \t\tNL_SET_ERR_MSG_MOD(extack,\n@@ -1486,13 +1505,13 @@ static int otx2_tc_ingress_matchall_delete(struct otx2_nic *nic,\n \tstruct netlink_ext_ack *extack = cls-\u003ecommon.extack;\n \tint err;\n \n-\tif (nic-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN) {\n+\tif (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN)) {\n \t\tNL_SET_ERR_MSG_MOD(extack, \"Interface not initialized\");\n \t\treturn -EINVAL;\n \t}\n \n \terr = cn10k_free_matchall_ipolicer(nic);\n-\tnic-\u003eflags \u0026= ~OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED;\n+\totx2_clear_flag(nic, OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED);\n \treturn err;\n }\n \n@@ -1600,14 +1619,827 @@ static int otx2_setup_tc_block(struct net_device *netdev,\n \t\t\t\t\t nic, nic, ingress);\n }\n \n+/* Free the per-queue min/max rate caches. */\n+static void otx2_mqprio_free_cache(struct otx2_nic *pfvf)\n+{\n+\tdevm_kfree(pfvf-\u003edev, pfvf-\u003emqprio.min_rate);\n+\tdevm_kfree(pfvf-\u003edev, pfvf-\u003emqprio.max_rate);\n+\tpfvf-\u003emqprio.min_rate = NULL;\n+\tpfvf-\u003emqprio.max_rate = NULL;\n+\tpfvf-\u003emqprio.flags = 0;\n+}\n+\n+static int otx2_mqprio_alloc_cache(struct otx2_nic *pfvf, bool replacing)\n+{\n+\tu16 num_txq = pfvf-\u003ehw.non_qos_queues;\n+\tu64 *min_rate, *max_rate;\n+\n+\tif (replacing \u0026\u0026 pfvf-\u003emqprio.min_rate \u0026\u0026 pfvf-\u003emqprio.max_rate) {\n+\t\tmemset(pfvf-\u003emqprio.min_rate, 0,\n+\t\t num_txq * sizeof(*pfvf-\u003emqprio.min_rate));\n+\t\tmemset(pfvf-\u003emqprio.max_rate, 0,\n+\t\t num_txq * sizeof(*pfvf-\u003emqprio.max_rate));\n+\t\tpfvf-\u003emqprio.flags = 0;\n+\t\treturn 0;\n+\t}\n+\n+\tmin_rate = devm_kcalloc(pfvf-\u003edev, num_txq, sizeof(*min_rate), GFP_KERNEL);\n+\tmax_rate = devm_kcalloc(pfvf-\u003edev, num_txq, sizeof(*max_rate), GFP_KERNEL);\n+\tif (!min_rate || !max_rate) {\n+\t\tdevm_kfree(pfvf-\u003edev, min_rate);\n+\t\tdevm_kfree(pfvf-\u003edev, max_rate);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\totx2_mqprio_free_cache(pfvf);\n+\tpfvf-\u003emqprio.min_rate = min_rate;\n+\tpfvf-\u003emqprio.max_rate = max_rate;\n+\n+\treturn 0;\n+}\n+\n+static void otx2_mqprio_snap_free(struct otx2_nic *pfvf,\n+\t\t\t\t struct mq_offload_snap **snap)\n+{\n+\tif (!*snap)\n+\t\treturn;\n+\n+\tdevm_kfree(pfvf-\u003edev, *snap);\n+\t*snap = NULL;\n+}\n+\n+static int otx2_mqprio_snap_copy(struct otx2_nic *pfvf,\n+\t\t\t\t struct mq_offload_snap **dst,\n+\t\t\t\t const struct tc_mqprio_qopt_offload *mqprio)\n+{\n+\tconst struct tc_mqprio_qopt *qopt = \u0026mqprio-\u003eqopt;\n+\tstruct mq_offload_snap *snap;\n+\tint tc;\n+\n+\tif (!*dst) {\n+\t\tsnap = devm_kzalloc(pfvf-\u003edev, sizeof(*snap), GFP_KERNEL);\n+\t\tif (!snap)\n+\t\t\treturn -ENOMEM;\n+\t\t*dst = snap;\n+\t} else {\n+\t\tsnap = *dst;\n+\t}\n+\n+\tsnap-\u003enum_tc = qopt-\u003enum_tc;\n+\tsnap-\u003eflags = mqprio-\u003eflags;\n+\tfor (tc = 0; tc \u003c TC_QOPT_MAX_QUEUE; tc++) {\n+\t\tsnap-\u003ecount[tc] = qopt-\u003ecount[tc];\n+\t\tsnap-\u003eoffset[tc] = qopt-\u003eoffset[tc];\n+\t\tsnap-\u003emin_rate[tc] = 0;\n+\t\tsnap-\u003emax_rate[tc] = 0;\n+\t}\n+\n+\tfor (tc = 0; tc \u003c qopt-\u003enum_tc; tc++) {\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MIN_RATE)\n+\t\t\tsnap-\u003emin_rate[tc] = mqprio-\u003emin_rate[tc];\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MAX_RATE)\n+\t\t\tsnap-\u003emax_rate[tc] = mqprio-\u003emax_rate[tc];\n+\t}\n+\tmemcpy(snap-\u003eprio_tc_map, qopt-\u003eprio_tc_map, sizeof(snap-\u003eprio_tc_map));\n+\n+\treturn 0;\n+}\n+\n+static int otx2_mqprio_stage_cur(struct otx2_nic *pfvf,\n+\t\t\t\t const struct tc_mqprio_qopt_offload *mqprio)\n+{\n+\treturn otx2_mqprio_snap_copy(pfvf, \u0026pfvf-\u003ecur_mq_snap, mqprio);\n+}\n+\n+static void otx2_mqprio_snap_commit(struct otx2_nic *pfvf)\n+{\n+\totx2_mqprio_snap_free(pfvf, \u0026pfvf-\u003eold_mq_snap);\n+\tpfvf-\u003eold_mq_snap = pfvf-\u003ecur_mq_snap;\n+\tpfvf-\u003ecur_mq_snap = NULL;\n+}\n+\n+static void otx2_mqprio_clear_replace_state(struct otx2_nic *pfvf)\n+{\n+\tpfvf-\u003emqprio.replace_setup_done = false;\n+\tpfvf-\u003emqprio.replace_graft_done = false;\n+}\n+\n+static bool otx2_mqprio_mdq_allocated(struct otx2_nic *pfvf)\n+{\n+\treturn pfvf-\u003ehw.txschq_cnt[NIX_TXSCH_LVL_MDQ] != 0;\n+}\n+\n+static int otx2_mqprio_restart_netdev(struct net_device *netdev, bool rate_limit);\n+\n+static void otx2_mqprio_apply_snap_netdev(struct net_device *netdev,\n+\t\t\t\t\t const struct mq_offload_snap *snap)\n+{\n+\tint tc;\n+\n+\tif (!snap)\n+\t\treturn;\n+\n+\tnetdev_set_num_tc(netdev, snap-\u003enum_tc);\n+\tfor (tc = 0; tc \u003c snap-\u003enum_tc; tc++)\n+\t\tnetdev_set_tc_queue(netdev, tc, snap-\u003ecount[tc],\n+\t\t\t\t snap-\u003eoffset[tc]);\n+\tfor (tc = 0; tc \u003c TC_QOPT_BITMASK + 1; tc++)\n+\t\tnetdev_set_prio_tc_map(netdev, tc, snap-\u003eprio_tc_map[tc]);\n+}\n+\n+static void otx2_mqprio_netdev_tc_work(struct work_struct *work)\n+{\n+\tstruct otx2_mqprio *mqprio = container_of(work, struct otx2_mqprio,\n+\t\t\t\t\t\t netdev_tc_work);\n+\tstruct otx2_nic *pfvf = container_of(mqprio, struct otx2_nic, mqprio);\n+\n+\trtnl_lock();\n+\tif (pfvf-\u003emqprio.rate_limit \u0026\u0026 pfvf-\u003eold_mq_snap)\n+\t\totx2_mqprio_apply_snap_netdev(pfvf-\u003enetdev, pfvf-\u003eold_mq_snap);\n+\trtnl_unlock();\n+}\n+\n+static void otx2_mqprio_defer_netdev_tc_restore(struct otx2_nic *pfvf)\n+{\n+\tschedule_work(\u0026pfvf-\u003emqprio.netdev_tc_work);\n+}\n+\n+static int otx2_mqprio_restore_old(struct otx2_nic *pfvf)\n+{\n+\tstruct mq_offload_snap *snap = pfvf-\u003eold_mq_snap;\n+\tstruct net_device *netdev = pfvf-\u003enetdev;\n+\tu16 num_txq = pfvf-\u003ehw.non_qos_queues;\n+\tint tc, txq, err;\n+\n+\tif (!snap)\n+\t\treturn 0;\n+\n+\terr = otx2_mqprio_alloc_cache(pfvf, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\tmemset(pfvf-\u003emqprio.min_rate, 0, num_txq * sizeof(*pfvf-\u003emqprio.min_rate));\n+\tmemset(pfvf-\u003emqprio.max_rate, 0, num_txq * sizeof(*pfvf-\u003emqprio.max_rate));\n+\tpfvf-\u003emqprio.flags = snap-\u003eflags;\n+\n+\tfor (tc = 0; tc \u003c snap-\u003enum_tc; tc++) {\n+\t\tu64 min_rate = snap-\u003emin_rate[tc];\n+\t\tu64 max_rate = snap-\u003emax_rate[tc];\n+\n+\t\tfor (txq = snap-\u003eoffset[tc];\n+\t\t txq \u003c snap-\u003eoffset[tc] + snap-\u003ecount[tc]; txq++) {\n+\t\t\tpfvf-\u003emqprio.min_rate[txq] = min_rate;\n+\t\t\tpfvf-\u003emqprio.max_rate[txq] = max_rate;\n+\t\t}\n+\t}\n+\n+\totx2_mqprio_apply_snap_netdev(netdev, snap);\n+\n+\tif (otx2_mqprio_mdq_allocated(pfvf)) {\n+\t\terr = otx2_nix_tm_clear_queue_shaper(pfvf);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\t/* Rebuild the TX scheduler via netdev restart when running; otx2_mqprio_up()\n+\t * alone is insufficient after a failed replace that already bounced the\n+\t * interface. If open failed, TX schedulers were freed; defer shaper restore\n+\t * to the next successful ndo_open() via otx2_mqprio_up().\n+\t */\n+\tpfvf-\u003emqprio.rate_limit = true;\n+\n+\tif (netif_running(netdev)) {\n+\t\terr = otx2_mqprio_restart_netdev(netdev, true);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t} else if (pfvf-\u003ehw.txschq_cnt[NIX_TXSCH_LVL_SMQ]) {\n+\t\terr = otx2_mqprio_up(pfvf);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\totx2_mqprio_snap_free(pfvf, \u0026pfvf-\u003ecur_mq_snap);\n+\n+\treturn 0;\n+}\n+\n+static void otx2_mqprio_snap_destroy(struct otx2_nic *pfvf)\n+{\n+\totx2_mqprio_snap_free(pfvf, \u0026pfvf-\u003ecur_mq_snap);\n+\totx2_mqprio_snap_free(pfvf, \u0026pfvf-\u003eold_mq_snap);\n+}\n+\n+/* Offloaded mqprio replaced by software mqprio installs netdev TC layout in\n+ * mqprio_init() before the old offload instance is destroyed during graft.\n+ */\n+static bool otx2_mqprio_keep_netdev_tc(struct otx2_nic *pfvf)\n+{\n+\tstruct Qdisc *qdisc = rtnl_dereference(pfvf-\u003enetdev-\u003eqdisc);\n+\n+\treturn qdisc \u0026\u0026 qdisc-\u003eops \u0026\u0026 !strcmp(qdisc-\u003eops-\u003eid, \"mqprio\");\n+}\n+\n+static void otx2_mqprio_clear_sw(struct otx2_nic *pfvf)\n+{\n+\tstruct net_device *netdev = pfvf-\u003enetdev;\n+\n+\tpfvf-\u003emqprio.rate_limit = false;\n+\totx2_mqprio_clear_replace_state(pfvf);\n+\tif (!otx2_mqprio_keep_netdev_tc(pfvf))\n+\t\tnetdev_set_num_tc(netdev, 0);\n+\totx2_mqprio_free_cache(pfvf);\n+}\n+\n+/* Tear down mqprio bandwidth offload: clear per-queue shapers,\n+ * mqprio_rate_limit, netdev TC mappings, and the cached rates. Called on\n+ * explicit mqprio teardown (tc qdisc del) and error cleanup, not on\n+ * routine netdev stop/open cycles where the offload stays active.\n+ */\n+int otx2_mqprio_down(struct otx2_nic *pfvf)\n+{\n+\tint err = 0;\n+\n+\tif (!pfvf-\u003emqprio.rate_limit)\n+\t\treturn 0;\n+\n+\tif (netif_running(pfvf-\u003enetdev) \u0026\u0026\n+\t otx2_mqprio_mdq_allocated(pfvf))\n+\t\terr = otx2_nix_tm_clear_queue_shaper(pfvf);\n+\n+\tif (err) {\n+\t\tnetdev_warn(pfvf-\u003enetdev,\n+\t\t\t \"mqprio: failed to clear hardware shapers: %d; keeping offload state\\n\",\n+\t\t\t err);\n+\t\treturn err;\n+\t}\n+\n+\totx2_mqprio_clear_sw(pfvf);\n+\n+\treturn 0;\n+}\n+\n+/* Restore cached mqprio MDQ shapers after ndo_open() reprograms the TX\n+ * scheduler. Called from otx2_open() when bandwidth offload stays active\n+ * across admin down/up or an mqprio netdev bounce.\n+ *\n+ * Returns an error if any shaper mailbox operation fails. otx2_open()\n+ * fail-closes on that error: it aborts open and leaves the interface down\n+ * rather than running with partial or missing bandwidth limits.\n+ */\n+int otx2_mqprio_up(struct otx2_nic *pfvf)\n+{\n+\tstruct net_device *netdev = pfvf-\u003enetdev;\n+\tint txq, err;\n+\n+\tif (!pfvf-\u003emqprio.rate_limit)\n+\t\treturn 0;\n+\n+\tif (!pfvf-\u003emqprio.min_rate || !pfvf-\u003emqprio.max_rate)\n+\t\treturn 0;\n+\n+\tfor (txq = 0; txq \u003c pfvf-\u003ehw.non_qos_queues; txq++) {\n+\t\tu64 min_rate = 0, max_rate = 0;\n+\n+\t\tif (pfvf-\u003emqprio.flags \u0026 TC_MQPRIO_F_MIN_RATE)\n+\t\t\tmin_rate = pfvf-\u003emqprio.min_rate[txq];\n+\t\tif (pfvf-\u003emqprio.flags \u0026 TC_MQPRIO_F_MAX_RATE)\n+\t\t\tmax_rate = pfvf-\u003emqprio.max_rate[txq];\n+\n+\t\tif (!min_rate \u0026\u0026 !max_rate)\n+\t\t\tcontinue;\n+\n+\t\terr = otx2_nix_tm_set_queue_shaper(pfvf, txq, min_rate,\n+\t\t\t\t\t\t max_rate);\n+\t\tif (err) {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"mqprio: failed to restore shaper for txq %d: %d\\n\",\n+\t\t\t\t txq, err);\n+\t\t\tif (otx2_mqprio_mdq_allocated(pfvf) \u0026\u0026\n+\t\t\t otx2_nix_tm_clear_queue_shaper(pfvf))\n+\t\t\t\tnetdev_warn(netdev,\n+\t\t\t\t\t \"mqprio: failed to clear shapers after partial restore\\n\");\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* Restart the netdev to reprogram the TX scheduler hierarchy for mqprio\n+ * bandwidth offload. Both mqprio add and delete (when offload was active)\n+ * take this path via ndo_stop()/ndo_open() so VF-specific open logic (e.g.\n+ * LBK carrier on) runs correctly.\n+ *\n+ * Intentional behaviour: this full stop/open cycle drops in-flight traffic\n+ * (carrier off, IRQ/NAPI teardown, queue drain). The NIX TX scheduler must\n+ * be reallocated (e.g. one SMQ per non-QoS queue) and cannot be reprogrammed\n+ * live today, so a netdev bounce is required on every mqprio add, replace,\n+ * delete, and rollback. Users see a brief connectivity blip; this is not a\n+ * bug to \"fix\" without implementing the live-reprogramming path noted below.\n+ * If open fails, the interface is left administratively down without calling\n+ * ndo_stop() again on resources already torn down by the open error path.\n+ *\n+ * Do not call dev_deactivate()/dev_activate() here. On replace,\n+ * qdisc_graft() already deactivates qdiscs around offload teardown;\n+ * dev_activate() from ndo_setup_tc() would republish qdiscs before graft\n+ * completes and race __qdisc_run() on the old root qdisc. After\n+ * ndo_open(), carrier and TX queues are restored via otx2_handle_link_event()\n+ * when link is up, same as otx2_change_mtu(), not via dev_activate().\n+ *\n+ * Clear __LINK_STATE_START before ndo_stop() so netif_running() is false\n+ * for the duration of the bounce.\n+ */\n+static int otx2_mqprio_restart_netdev(struct net_device *netdev, bool rate_limit)\n+{\n+\tstruct otx2_nic *pfvf = netdev_priv(netdev);\n+\tconst struct net_device_ops *ops = netdev-\u003enetdev_ops;\n+\tbool running = netif_running(netdev);\n+\tint err;\n+\n+\t/* TODO: Explore live TX scheduler reprogramming to avoid a full\n+\t * ndo_stop()/ndo_open() bounce on every mqprio change.\n+\t */\n+\tnetdev_dbg(netdev,\n+\t\t \"mqprio: restarting interface to reprogram TX scheduler; in-flight traffic will be dropped\\n\");\n+\n+\tif (running) {\n+\t\tclear_bit(__LINK_STATE_START, \u0026netdev-\u003estate);\n+\t\tsmp_mb__after_atomic(); /* Commit netif_running(). */\n+\t}\n+\n+\terr = ops-\u003endo_stop(netdev);\n+\tif (err) {\n+\t\tif (running)\n+\t\t\tset_bit(__LINK_STATE_START, \u0026netdev-\u003estate);\n+\t\treturn err;\n+\t}\n+\n+\t/* Set before ndo_open() so otx2_txsch_alloc() widens SMQ allocation.\n+\t * On teardown, drop mqprio software state so ndo_open() does not\n+\t * re-apply bandwidth limits via otx2_mqprio_up() after the kernel\n+\t * removed the qdisc.\n+\t */\n+\tif (rate_limit)\n+\t\tpfvf-\u003emqprio.rate_limit = true;\n+\telse\n+\t\totx2_mqprio_clear_sw(pfvf);\n+\n+\terr = ops-\u003endo_open(netdev);\n+\tif (!err \u0026\u0026 running) {\n+\t\tset_bit(__LINK_STATE_START, \u0026netdev-\u003estate);\n+\t} else if (err) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"Failed to restart device after mqprio change: %d\\n\",\n+\t\t\t err);\n+\t\t/* ndo_open() already freed the TX schedulers on failure while\n+\t\t * netif_running() may still be true; drop mqprio software state\n+\t\t * only instead of sending shaper clears to freed queues.\n+\t\t */\n+\t\totx2_mqprio_clear_sw(pfvf);\n+\t\t/* ndo_open() rolls back on failure; mark the interface down so\n+\t\t * netif_close() does not invoke ndo_stop() on freed NAPI/queue\n+\t\t * state. Caller holds RTNL; dev_close() would deadlock.\n+\t\t */\n+\t\totx2_set_flag(pfvf, OTX2_FLAG_INTF_DOWN);\n+\t\t/* visible to otx2_stop() on other cpus */\n+\t\tsmp_wmb();\n+\t\tnetif_close(netdev);\n+\t}\n+\n+\treturn err;\n+}\n+\n+static int otx2_mqprio_validate_tc_rate(struct net_device *netdev,\n+\t\t\t\t\tstruct netlink_ext_ack *extack,\n+\t\t\t\t\tu64 rate, u32 qcount, int tc,\n+\t\t\t\t\tconst char *name)\n+{\n+\tif (!rate)\n+\t\treturn 0;\n+\n+\tif (qcount \u003c= 1)\n+\t\treturn 0;\n+\n+\t/* TODO: per-TC TL4 shapers or equal per-queue MDQ split for multi-queue TC rates. */\n+\tnetdev_err(netdev,\n+\t\t \"mqprio: %s rate for tc %d not supported with %u queues\\n\",\n+\t\t name, tc, qcount);\n+\tNL_SET_ERR_MSG_FMT_MOD(extack,\n+\t\t\t \"mqprio: %s rate for tc %d not supported with %u queues\",\n+\t\t\t name, tc, qcount);\n+\treturn -EOPNOTSUPP;\n+}\n+\n+static int otx2_mqprio_validate_txqs(struct net_device *netdev,\n+\t\t\t\t struct netlink_ext_ack *extack,\n+\t\t\t\t struct tc_mqprio_qopt *qopt)\n+{\n+\tstruct otx2_nic *pfvf = netdev_priv(netdev);\n+\tu16 num_txq = pfvf-\u003ehw.non_qos_queues;\n+\tint tc, txq;\n+\n+\tif (qopt-\u003enum_tc \u003e num_txq) {\n+\t\tnetdev_err(netdev, \"Number of TCs (%u) exceeds hw queues %u\\n\",\n+\t\t\t qopt-\u003enum_tc, num_txq);\n+\t\tNL_SET_ERR_MSG_FMT_MOD(extack,\n+\t\t\t\t \"Number of TCs (%u) exceeds hw queues %u\",\n+\t\t\t\t qopt-\u003enum_tc, num_txq);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (num_txq \u003e MAX_TXSCHQ_PER_FUNC) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"Number of queues (%u) exceeds max scheduler queues %u\\n\",\n+\t\t\t num_txq, MAX_TXSCHQ_PER_FUNC);\n+\t\tNL_SET_ERR_MSG_FMT_MOD(extack,\n+\t\t\t\t \"Number of queues (%u) exceeds max scheduler queues %u\",\n+\t\t\t\t num_txq, MAX_TXSCHQ_PER_FUNC);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfor (tc = 0; tc \u003c qopt-\u003enum_tc; tc++) {\n+\t\tu32 qcount = qopt-\u003ecount[tc];\n+\n+\t\tfor (txq = qopt-\u003eoffset[tc];\n+\t\t txq \u003c qopt-\u003eoffset[tc] + qcount; txq++) {\n+\t\t\tif (txq \u003e= num_txq) {\n+\t\t\t\tnetdev_err(netdev,\n+\t\t\t\t\t \"mqprio: txq %d exceeds offload queue count %u\\n\",\n+\t\t\t\t\t txq, num_txq);\n+\t\t\t\tNL_SET_ERR_MSG_FMT_MOD(extack,\n+\t\t\t\t\t\t \"mqprio: txq %d exceeds offload queue count %u\",\n+\t\t\t\t\t\t txq, num_txq);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static bool otx2_mqprio_rate_valid(struct otx2_nic *pfvf, u64 rate_bytes_ps)\n+{\n+\tu64 mbps;\n+\n+\tif (!rate_bytes_ps)\n+\t\treturn true;\n+\n+\tif (rate_bytes_ps \u003c OTX2_MQPRIO_MIN_RATE_BYTES_PS)\n+\t\treturn false;\n+\n+\tif (rate_bytes_ps \u003e otx2_mqprio_max_rate_bytes_ps())\n+\t\treturn false;\n+\n+\tif (rate_bytes_ps \u003e div_u64(U64_MAX, 8))\n+\t\treturn false;\n+\n+\tmbps = otx2_convert_rate(rate_bytes_ps);\n+\treturn ilog2(mbps / 2) \u003c= MAX_RATE_EXPONENT;\n+}\n+\n+static int otx2_teardown_tc_mqprio(struct otx2_nic *pfvf,\n+\t\t\t\t struct tc_mqprio_qopt_offload *mqprio)\n+{\n+\tstruct tc_mqprio_qopt *qopt = \u0026mqprio-\u003eqopt;\n+\tbool had_mqprio = pfvf-\u003emqprio.rate_limit;\n+\tstruct net_device *netdev = pfvf-\u003enetdev;\n+\tbool if_up = netif_running(netdev);\n+\tint err;\n+\n+\tqopt-\u003ehw = 0;\n+\n+\t/* tc qdisc replace runs setup on the new mqprio before destroying the\n+\t * old one. replace_setup_done and TC_ROOT_GRAFT distinguish stale\n+\t * old-instance teardown from graft failure after setup.\n+\t */\n+\tif (pfvf-\u003emqprio.replace_setup_done \u0026\u0026 pfvf-\u003ecur_mq_snap) {\n+\t\terr = 0;\n+\t\tif (pfvf-\u003emqprio.replace_graft_done)\n+\t\t\totx2_mqprio_snap_commit(pfvf);\n+\t\telse\n+\t\t\terr = otx2_mqprio_restore_old(pfvf);\n+\t\totx2_mqprio_clear_replace_state(pfvf);\n+\t\treturn err;\n+\t}\n+\n+\t/* Skip the netdev restart when mqprio offload was not active. */\n+\tif (!had_mqprio)\n+\t\treturn 0;\n+\n+\tif (if_up) {\n+\t\terr = otx2_mqprio_down(pfvf);\n+\t\tif (err)\n+\t\t\treturn err;\n+\n+\t\treturn otx2_mqprio_restart_netdev(netdev, false);\n+\t}\n+\n+\t/* ndo_stop() already freed the TX scheduler TL nodes; drop software\n+\t * state only.\n+\t */\n+\totx2_mqprio_clear_sw(pfvf);\n+\treturn 0;\n+}\n+\n+static int otx2_setup_tc_mqprio(struct net_device *netdev,\n+\t\t\t\tstruct tc_mqprio_qopt_offload *mqprio)\n+{\n+\tstruct netlink_ext_ack *extack = mqprio-\u003eextack;\n+\tstruct otx2_nic *pfvf = netdev_priv(netdev);\n+\tstruct tc_mqprio_qopt *qopt = \u0026mqprio-\u003eqopt;\n+\tbool replacing = pfvf-\u003emqprio.rate_limit;\n+\tbool if_up = netif_running(netdev);\n+\tint tc, txq, err, i;\n+\n+\tif (!qopt-\u003ehw)\n+\t\treturn otx2_teardown_tc_mqprio(pfvf, mqprio);\n+\n+\tif (!if_up) {\n+\t\tnetdev_err(netdev, \"mqprio: setup requires interface UP\\n\");\n+\t\tNL_SET_ERR_MSG_MOD(extack, \"mqprio: setup requires interface UP\");\n+\t\terr = -EOPNOTSUPP;\n+\t\tgoto fail_validate;\n+\t}\n+\n+\tif (!replacing \u0026\u0026 otx2_mqprio_keep_netdev_tc(pfvf)) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"mqprio: delete existing mqprio before re-enabling hw/sw offload\\n\");\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"mqprio: delete existing mqprio before re-enabling hw/sw offload\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tif (mqprio-\u003eshaper != TC_MQPRIO_SHAPER_BW_RATE) {\n+\t\tnetdev_err(netdev, \"Unsupported mqprio shaper %#x\\n\", mqprio-\u003eshaper);\n+\t\tNL_SET_ERR_MSG_FMT_MOD(extack, \"Unsupported mqprio shaper %#x\",\n+\t\t\t\t mqprio-\u003eshaper);\n+\t\terr = -EOPNOTSUPP;\n+\t\tgoto fail_validate;\n+\t}\n+\n+\tif (!test_bit(QOS_CIR_PIR_SUPPORT, \u0026pfvf-\u003ehw.cap_flag)) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"mqprio: bandwidth offload requires CIR+PIR support\\n\");\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"mqprio: bandwidth offload requires CIR+PIR support\");\n+\t\terr = -EOPNOTSUPP;\n+\t\tgoto fail_validate;\n+\t}\n+\n+\tif (is_otx2_sdp_rep(pfvf-\u003epdev)) {\n+\t\tnetdev_err(netdev, \"mqprio: bandwidth offload not supported on SDP rep\\n\");\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"mqprio: bandwidth offload not supported on SDP rep\");\n+\t\terr = -EOPNOTSUPP;\n+\t\tgoto fail_validate;\n+\t}\n+\n+\tif (pfvf-\u003epfc_en) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"mqprio: cannot enable offload while PFC is enabled\\n\");\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"mqprio: cannot enable offload while PFC is enabled\");\n+\t\terr = -EOPNOTSUPP;\n+\t\tgoto fail_validate;\n+\t}\n+\n+\tif (pfvf-\u003exdp_prog) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"mqprio: cannot enable offload while XDP is active\\n\");\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"mqprio: cannot enable offload while XDP is active\");\n+\t\terr = -EOPNOTSUPP;\n+\t\tgoto fail_validate;\n+\t}\n+\n+\tif (!list_empty(\u0026pfvf-\u003eqos.qos_tree)) {\n+\t\tnetdev_err(netdev,\n+\t\t\t \"mqprio: cannot enable offload while HTB is active\\n\");\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"mqprio: cannot enable offload while HTB is active\");\n+\t\terr = -EOPNOTSUPP;\n+\t\tgoto fail_validate;\n+\t}\n+\n+\tfor (tc = 0; tc \u003c qopt-\u003enum_tc; tc++) {\n+\t\tu64 min_rate = 0, max_rate = 0;\n+\t\tu32 qcount = qopt-\u003ecount[tc];\n+\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MIN_RATE)\n+\t\t\tmin_rate = mqprio-\u003emin_rate[tc];\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MAX_RATE)\n+\t\t\tmax_rate = mqprio-\u003emax_rate[tc];\n+\n+\t\tif (min_rate \u0026\u0026 max_rate \u0026\u0026 min_rate \u003e max_rate) {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"min_rate %llu exceeds max_rate %llu for tc %d\\n\",\n+\t\t\t\t min_rate, max_rate, tc);\n+\t\t\tNL_SET_ERR_MSG_FMT_MOD(extack,\n+\t\t\t\t\t \"min_rate %llu exceeds max_rate %llu for tc %d\",\n+\t\t\t\t\t min_rate, max_rate, tc);\n+\t\t\terr = -EINVAL;\n+\t\t\tgoto fail_validate;\n+\t\t}\n+\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MIN_RATE) {\n+\t\t\terr = otx2_mqprio_validate_tc_rate(netdev, extack, min_rate,\n+\t\t\t\t\t\t\t qcount, tc, \"min\");\n+\t\t\tif (err)\n+\t\t\t\tgoto fail_validate;\n+\t\t}\n+\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MAX_RATE) {\n+\t\t\terr = otx2_mqprio_validate_tc_rate(netdev, extack, max_rate,\n+\t\t\t\t\t\t\t qcount, tc, \"max\");\n+\t\t\tif (err)\n+\t\t\t\tgoto fail_validate;\n+\t\t}\n+\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MIN_RATE \u0026\u0026\n+\t\t !otx2_mqprio_rate_valid(pfvf, min_rate)) {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"mqprio: min_rate %llu for tc %d is outside hardware limits\\n\",\n+\t\t\t\t min_rate, tc);\n+\t\t\tNL_SET_ERR_MSG_FMT_MOD(extack,\n+\t\t\t\t\t \"mqprio: min_rate %llu for tc %d is outside hardware limits\",\n+\t\t\t\t\t min_rate, tc);\n+\t\t\terr = -EINVAL;\n+\t\t\tgoto fail_validate;\n+\t\t}\n+\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MAX_RATE \u0026\u0026\n+\t\t !otx2_mqprio_rate_valid(pfvf, max_rate)) {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"mqprio: max_rate %llu for tc %d is outside hardware limits\\n\",\n+\t\t\t\t max_rate, tc);\n+\t\t\tNL_SET_ERR_MSG_FMT_MOD(extack,\n+\t\t\t\t\t \"mqprio: max_rate %llu for tc %d is outside hardware limits\",\n+\t\t\t\t\t max_rate, tc);\n+\t\t\terr = -EINVAL;\n+\t\t\tgoto fail_validate;\n+\t\t}\n+\t}\n+\n+\terr = otx2_mqprio_validate_txqs(netdev, extack, qopt);\n+\tif (err)\n+\t\tgoto fail_validate;\n+\n+\terr = otx2_mqprio_stage_cur(pfvf, mqprio);\n+\tif (err)\n+\t\tgoto fail_validate;\n+\n+\terr = otx2_mqprio_restart_netdev(pfvf-\u003enetdev, true);\n+\tif (err)\n+\t\tgoto cleanup;\n+\n+\terr = otx2_mqprio_alloc_cache(pfvf, replacing);\n+\tif (err)\n+\t\tgoto cleanup;\n+\n+\t/* otx2_mqprio_up() may have restored the previous configuration during\n+\t * the restart above. Clear every MDQ shaper before applying the new\n+\t * mapping so queues dropped from the TC layout do not keep stale\n+\t * limits in hardware.\n+\t */\n+\tif (otx2_mqprio_mdq_allocated(pfvf)) {\n+\t\terr = otx2_nix_tm_clear_queue_shaper(pfvf);\n+\t\tif (err)\n+\t\t\tgoto cleanup;\n+\t}\n+\n+\tpfvf-\u003emqprio.flags = mqprio-\u003eflags;\n+\n+\tfor (tc = 0; tc \u003c qopt-\u003enum_tc; tc++) {\n+\t\tu64 min_rate = 0, max_rate = 0;\n+\t\tu32 qcount = qopt-\u003ecount[tc];\n+\n+\t\t/* Rates omitted from tc mqprio are passed as zero and both MDQ\n+\t\t * shaper registers are programmed; see\n+\t\t * otx2_nix_tm_set_queue_shaper().\n+\t\t * TODO: multi-queue TC rates need per-queue split; see\n+\t\t * otx2_mqprio_validate_tc_rate().\n+\t\t */\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MIN_RATE)\n+\t\t\tmin_rate = mqprio-\u003emin_rate[tc];\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MAX_RATE)\n+\t\t\tmax_rate = mqprio-\u003emax_rate[tc];\n+\n+\t\tfor (txq = qopt-\u003eoffset[tc];\n+\t\t txq \u003c qopt-\u003eoffset[tc] + qcount; txq++) {\n+\t\t\tnetdev_dbg(netdev,\n+\t\t\t\t \"mqprio: tc %d txq %d min_rate %llu max_rate %llu\\n\",\n+\t\t\t\t tc, txq, min_rate, max_rate);\n+\n+\t\t\tpfvf-\u003emqprio.min_rate[txq] = min_rate;\n+\t\t\tpfvf-\u003emqprio.max_rate[txq] = max_rate;\n+\n+\t\t\terr = otx2_nix_tm_set_queue_shaper(pfvf, txq,\n+\t\t\t\t\t\t\t min_rate, max_rate);\n+\t\t\tif (err)\n+\t\t\t\tgoto cleanup;\n+\t\t}\n+\t}\n+\n+\tnetdev_set_num_tc(netdev, pfvf-\u003ecur_mq_snap-\u003enum_tc);\n+\tfor (i = 0; i \u003c pfvf-\u003ecur_mq_snap-\u003enum_tc; i++)\n+\t\tnetdev_set_tc_queue(netdev, i, pfvf-\u003ecur_mq_snap-\u003ecount[i],\n+\t\t\t\t qopt-\u003eoffset[i]);\n+\n+\tqopt-\u003ehw = TC_MQPRIO_HW_OFFLOAD_TCS;\n+\n+\tif (replacing) {\n+\t\tpfvf-\u003emqprio.replace_setup_done = true;\n+\t\tpfvf-\u003emqprio.replace_graft_done = false;\n+\t} else {\n+\t\totx2_mqprio_snap_commit(pfvf);\n+\t}\n+\n+\treturn 0;\n+\n+fail_validate:\n+\t/* Failed replace destroys the new qdisc with hw_offload unset, so\n+\t * mqprio_destroy() clears netdev TC after we return. Re-apply the\n+\t * prior layout when validation fails before any hardware change.\n+\t */\n+\tif (replacing)\n+\t\totx2_mqprio_defer_netdev_tc_restore(pfvf);\n+\treturn err;\n+\n+cleanup:\n+\tqopt-\u003ehw = 0;\n+\tif (replacing) {\n+\t\tint restore_err = otx2_mqprio_restore_old(pfvf);\n+\n+\t\totx2_mqprio_clear_replace_state(pfvf);\n+\t\tif (restore_err) {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"mqprio: replace failed and prior configuration rollback failed: %d\\n\",\n+\t\t\t\t restore_err);\n+\t\t\tif (extack)\n+\t\t\t\tNL_SET_ERR_MSG_FMT_MOD(extack,\n+\t\t\t\t\t\t \"mqprio: replace failed and prior configuration rollback failed: %d\",\n+\t\t\t\t\t\t restore_err);\n+\t\t} else {\n+\t\t\tnetdev_err(netdev,\n+\t\t\t\t \"mqprio: replace failed; hardware limits restored, netdev TC layout restore deferred\\n\");\n+\t\t\tif (extack)\n+\t\t\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t\t\t \"mqprio: replace failed; hardware limits restored, netdev TC layout restore deferred\");\n+\t\t\t/* Failed replace destroys the new qdisc with hw_offload\n+\t\t\t * unset, so mqprio_destroy() clears netdev TC after we\n+\t\t\t * return. Re-apply the restored layout once that unwind\n+\t\t\t * finishes.\n+\t\t\t */\n+\t\t\totx2_mqprio_defer_netdev_tc_restore(pfvf);\n+\t\t}\n+\t\treturn err ? err : -EIO;\n+\t}\n+\totx2_mqprio_snap_free(pfvf, \u0026pfvf-\u003ecur_mq_snap);\n+\totx2_teardown_tc_mqprio(pfvf, mqprio);\n+\treturn err;\n+}\n+\n+static int otx2_setup_tc_root(struct otx2_nic *pfvf,\n+\t\t\t struct tc_root_qopt_offload *root)\n+{\n+\tswitch (root-\u003ecommand) {\n+\tcase TC_ROOT_GRAFT:\n+\t\tif (pfvf-\u003emqprio.replace_setup_done)\n+\t\t\tpfvf-\u003emqprio.replace_graft_done = true;\n+\t\treturn 0;\n+\tdefault:\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+}\n+\n+static int otx2_setup_tc_query_caps(void *type_data)\n+{\n+\tstruct tc_query_caps_base *base = type_data;\n+\tstruct tc_mqprio_caps *caps;\n+\n+\tif (base-\u003etype != TC_SETUP_QDISC_MQPRIO)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tcaps = base-\u003ecaps;\n+\tcaps-\u003evalidate_queue_counts = true;\n+\n+\treturn 0;\n+}\n+\n int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,\n \t\t void *type_data)\n {\n \tswitch (type) {\n+\tcase TC_QUERY_CAPS:\n+\t\treturn otx2_setup_tc_query_caps(type_data);\n \tcase TC_SETUP_BLOCK:\n \t\treturn otx2_setup_tc_block(netdev, type_data);\n \tcase TC_SETUP_QDISC_HTB:\n \t\treturn otx2_setup_tc_htb(netdev, type_data);\n+\tcase TC_SETUP_QDISC_MQPRIO:\n+\t\treturn otx2_setup_tc_mqprio(netdev, type_data);\n+\tcase TC_SETUP_ROOT_QDISC:\n+\t\treturn otx2_setup_tc_root(netdev_priv(netdev), type_data);\n \tdefault:\n \t\treturn -EOPNOTSUPP;\n \t}\n@@ -1625,13 +2457,17 @@ int otx2_init_tc(struct otx2_nic *nic)\n \t\treturn -EINVAL;\n \t}\n \n+\tINIT_WORK(\u0026nic-\u003emqprio.netdev_tc_work, otx2_mqprio_netdev_tc_work);\n+\n \treturn 0;\n }\n EXPORT_SYMBOL(otx2_init_tc);\n \n void otx2_shutdown_tc(struct otx2_nic *nic)\n {\n+\tcancel_work_sync(\u0026nic-\u003emqprio.netdev_tc_work);\n \totx2_destroy_tc_flow_list(nic);\n+\totx2_mqprio_snap_destroy(nic);\n }\n EXPORT_SYMBOL(otx2_shutdown_tc);\n \ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c\nindex 8d2d607bc92f9..f65ba44db60b6 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c\n@@ -171,7 +171,7 @@ static void otx2_set_rxtstamp(struct otx2_nic *pfvf,\n \tu64 timestamp, tsns;\n \tint err;\n \n-\tif (!(pfvf-\u003eflags \u0026 OTX2_FLAG_RX_TSTAMP_ENABLED))\n+\tif (!otx2_test_flag(pfvf, OTX2_FLAG_RX_TSTAMP_ENABLED))\n \t\treturn;\n \n \ttimestamp = pfvf-\u003eptp-\u003econvert_rx_ptp_tstmp(*(u64 *)data);\n@@ -374,13 +374,13 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf,\n \t}\n \totx2_set_rxhash(pfvf, cqe, skb);\n \n-\tif (!(pfvf-\u003eflags \u0026 OTX2_FLAG_REP_MODE_ENABLED)) {\n+\tif (!otx2_test_flag(pfvf, OTX2_FLAG_REP_MODE_ENABLED)) {\n \t\tskb_record_rx_queue(skb, cq-\u003ecq_idx);\n \t\tif (pfvf-\u003enetdev-\u003efeatures \u0026 NETIF_F_RXCSUM)\n \t\t\tskb-\u003eip_summed = CHECKSUM_UNNECESSARY;\n \t}\n \n-\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_TC_MARK_ENABLED)\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_TC_MARK_ENABLED))\n \t\tskb-\u003emark = parse-\u003ematch_id;\n \n \tskb_mark_for_recycle(skb);\n@@ -513,7 +513,7 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf,\n \t\t ((u64)cq-\u003ecq_idx \u003c\u003c 32) | processed_cqe);\n \n #if IS_ENABLED(CONFIG_RVU_ESWITCH)\n-\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_REP_MODE_ENABLED)\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_REP_MODE_ENABLED))\n \t\tndev = pfvf-\u003ereps[qidx]-\u003enetdev;\n \telse\n #endif\n@@ -526,7 +526,7 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf,\n \n \t\tif (qidx \u003e= pfvf-\u003ehw.tx_queues)\n \t\t\tqidx -= pfvf-\u003ehw.xdp_queues;\n-\t\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_REP_MODE_ENABLED)\n+\t\tif (otx2_test_flag(pfvf, OTX2_FLAG_REP_MODE_ENABLED))\n \t\t\tqidx = 0;\n \t\ttxq = netdev_get_tx_queue(ndev, qidx);\n \t\tnetdev_tx_completed_queue(txq, tx_pkts, tx_bytes);\n@@ -599,11 +599,11 @@ int otx2_napi_handler(struct napi_struct *napi, int budget)\n \n \tif (workdone \u003c budget \u0026\u0026 napi_complete_done(napi, workdone)) {\n \t\t/* If interface is going down, don't re-enable IRQ */\n-\t\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN)\n+\t\tif (otx2_test_flag(pfvf, OTX2_FLAG_INTF_DOWN))\n \t\t\treturn workdone;\n \n \t\t/* Adjust irq coalese using net_dim */\n-\t\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_ADPTV_INT_COAL_ENABLED)\n+\t\tif (otx2_test_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED))\n \t\t\totx2_adjust_adaptive_coalese(pfvf, cq_poll);\n \n \t\tif (likely(cq))\n@@ -1137,7 +1137,7 @@ static void otx2_set_txtstamp(struct otx2_nic *pfvf, struct sk_buff *skb,\n \n \tif (unlikely(!skb_shinfo(skb)-\u003egso_size \u0026\u0026\n \t\t (skb_shinfo(skb)-\u003etx_flags \u0026 SKBTX_HW_TSTAMP))) {\n-\t\tif (unlikely(pfvf-\u003eflags \u0026 OTX2_FLAG_PTP_ONESTEP_SYNC \u0026\u0026\n+\t\tif (unlikely(otx2_test_flag(pfvf, OTX2_FLAG_PTP_ONESTEP_SYNC) \u0026\u0026\n \t\t\t otx2_ptp_is_sync(skb, \u0026ptp_offset, \u0026udp_csum_crt))) {\n \t\t\torigin_tstamp = (struct ptpv2_tstamp *)\n \t\t\t\t\t((u8 *)skb-\u003edata + ptp_offset +\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c\nindex f7765e19d78a9..2837e19c780f6 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c\n@@ -610,7 +610,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \tvf-\u003edev = dev;\n \tvf-\u003eiommu_domain = iommu_get_domain_for_dev(dev);\n \n-\tvf-\u003eflags |= OTX2_FLAG_INTF_DOWN;\n+\totx2_set_flag(vf, OTX2_FLAG_INTF_DOWN);\n \thw = \u0026vf-\u003ehw;\n \thw-\u003epdev = vf-\u003epdev;\n \thw-\u003erx_queues = qcount;\n@@ -703,6 +703,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \tnetdev-\u003ehw_features |= NETIF_F_NTUPLE;\n \tnetdev-\u003ehw_features |= NETIF_F_RXALL;\n \tnetdev-\u003ehw_features |= NETIF_F_HW_TC;\n+\tnetdev-\u003efeatures |= NETIF_F_HW_TC;\n \n \tnetif_set_tso_max_segs(netdev, OTX2_MAX_GSO_SEGS);\n \tnetdev-\u003ewatchdog_timeo = OTX2_TX_TIMEOUT;\n@@ -740,25 +741,25 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \tif (err)\n \t\tgoto err_ipsec_clean;\n \n+\terr = otx2vf_mcam_flow_init(vf);\n+\tif (err)\n+\t\tgoto err_wq_destroy;\n+\n+\terr = otx2_init_tc(vf);\n+\tif (err)\n+\t\tgoto err_wq_destroy;\n+\n \terr = register_netdev(netdev);\n \tif (err) {\n \t\tdev_err(dev, \"Failed to register netdevice\\n\");\n-\t\tgoto err_wq_destroy;\n+\t\tgoto err_shutdown_tc;\n \t}\n \n \totx2vf_set_ethtool_ops(netdev);\n \n-\terr = otx2vf_mcam_flow_init(vf);\n-\tif (err)\n-\t\tgoto err_unreg_netdev;\n-\n-\terr = otx2_init_tc(vf);\n-\tif (err)\n-\t\tgoto err_unreg_netdev;\n-\n \terr = otx2_register_dl(vf);\n \tif (err)\n-\t\tgoto err_shutdown_tc;\n+\t\tgoto err_unreg_netdev;\n \n \tvf-\u003eaf_xdp_zc_qidx = bitmap_zalloc(qcount, GFP_KERNEL);\n \tif (!vf-\u003eaf_xdp_zc_qidx) {\n@@ -784,10 +785,11 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n #endif\n err_unreg_devlink:\n \totx2_unregister_dl(vf);\n-err_shutdown_tc:\n-\totx2_shutdown_tc(vf);\n err_unreg_netdev:\n+\totx2_shutdown_tc(vf);\n \tunregister_netdev(netdev);\n+err_shutdown_tc:\n+\totx2_shutdown_tc(vf);\n err_wq_destroy:\n \tcancel_work_sync(\u0026vf-\u003ereset_task);\n \tcancel_work_sync(\u0026vf-\u003erx_mode_work);\n@@ -824,10 +826,10 @@ static void otx2vf_remove(struct pci_dev *pdev)\n \tvf = netdev_priv(netdev);\n \n \t/* Disable 802.3x pause frames */\n-\tif (vf-\u003eflags \u0026 OTX2_FLAG_RX_PAUSE_ENABLED ||\n-\t (vf-\u003eflags \u0026 OTX2_FLAG_TX_PAUSE_ENABLED)) {\n-\t\tvf-\u003eflags \u0026= ~OTX2_FLAG_RX_PAUSE_ENABLED;\n-\t\tvf-\u003eflags \u0026= ~OTX2_FLAG_TX_PAUSE_ENABLED;\n+\tif (otx2_test_flag(vf, OTX2_FLAG_RX_PAUSE_ENABLED) ||\n+\t otx2_test_flag(vf, OTX2_FLAG_TX_PAUSE_ENABLED)) {\n+\t\totx2_clear_flag(vf, OTX2_FLAG_RX_PAUSE_ENABLED);\n+\t\totx2_clear_flag(vf, OTX2_FLAG_TX_PAUSE_ENABLED);\n \t\totx2_config_pause_frm(vf);\n \t}\n \n@@ -840,6 +842,7 @@ static void otx2vf_remove(struct pci_dev *pdev)\n #endif\n \n \totx2_unregister_dl(vf);\n+\totx2_shutdown_tc(vf);\n \tunregister_netdev(netdev);\n \tif (vf-\u003eotx2_wq) {\n \t\tcancel_work_sync(\u0026vf-\u003ereset_task);\n@@ -849,7 +852,6 @@ static void otx2vf_remove(struct pci_dev *pdev)\n \tcn10k_ipsec_clean(vf);\n \totx2_ptp_destroy(vf);\n \totx2_mcam_flow_del(vf);\n-\totx2_shutdown_tc(vf);\n \totx2_shutdown_qos(vf);\n \totx2_detach_resources(\u0026vf-\u003embox);\n \totx2vf_disable_mbox_intr(vf);\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_xsk.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_xsk.c\nindex 0e8a6a6486c4a..7808588a0234a 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_xsk.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_xsk.c\n@@ -96,7 +96,7 @@ static void otx2_clean_up_rq(struct otx2_nic *pfvf, int qidx)\n \tu64 iova;\n \n \t/* If the DOWN flag is set SQs are already freed */\n-\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN)\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_INTF_DOWN))\n \t\treturn;\n \n \tcq = \u0026qset-\u003ecq[qidx];\n@@ -172,7 +172,7 @@ int otx2_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)\n \tstruct otx2_cq_poll *cq_poll = NULL;\n \tstruct otx2_qset *qset = \u0026pf-\u003eqset;\n \n-\tif (pf-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN)\n+\tif (otx2_test_flag(pf, OTX2_FLAG_INTF_DOWN))\n \t\treturn -ENETDOWN;\n \n \tif (queue_id \u003e= pf-\u003ehw.rx_queues || queue_id \u003e= pf-\u003ehw.tx_queues)\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c\nindex f160b1618efa2..9ef55a6db50b7 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c\n@@ -118,6 +118,9 @@ static void otx2_config_sched_shaping(struct otx2_nic *pfvf,\n \t/* configure PIR */\n \tmaxrate = (node-\u003erate \u003e node-\u003eceil) ? node-\u003erate : node-\u003eceil;\n \n+\t/* 65536 is the kernel-side default burst when HTB does not supply an\n+\t * explicit value, not the NIX hardware maximum (CN10K_MAX_BURST_SIZE).\n+\t */\n \tcfg-\u003eregval[*num_regs] =\n \t\totx2_get_txschq_rate_regval(pfvf, maxrate, 65536);\n \t(*num_regs)++;\n@@ -1088,6 +1091,14 @@ static int otx2_qos_root_add(struct otx2_nic *pfvf, u16 htb_maj_id, u16 htb_defc\n \t\t \"TC_HTB_CREATE: handle=0x%x defcls=0x%x\\n\",\n \t\t htb_maj_id, htb_defcls);\n \n+\tif (pfvf-\u003emqprio.rate_limit) {\n+\t\tnetdev_err(pfvf-\u003enetdev,\n+\t\t\t \"HTB: cannot enable while mqprio bandwidth offload is active\\n\");\n+\t\tNL_SET_ERR_MSG_MOD(extack,\n+\t\t\t\t \"HTB: cannot enable while mqprio bandwidth offload is active\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n \troot = otx2_qos_alloc_root(pfvf);\n \tif (IS_ERR(root)) {\n \t\terr = PTR_ERR(root);\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c\nindex 2872adabc8305..5f09e29601441 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c\n@@ -238,7 +238,7 @@ int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx)\n \tstruct otx2_hw *hw = \u0026pfvf-\u003ehw;\n \tint pool_id, sq_idx, err;\n \n-\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN)\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_INTF_DOWN))\n \t\treturn -EPERM;\n \n \tsq_idx = hw-\u003enon_qos_queues + qidx;\n@@ -288,7 +288,7 @@ void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx)\n \tsq_idx = hw-\u003enon_qos_queues + qidx;\n \n \t/* If the DOWN flag is set SQs are already freed */\n-\tif (pfvf-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN)\n+\tif (otx2_test_flag(pfvf, OTX2_FLAG_INTF_DOWN))\n \t\treturn;\n \n \tsq = \u0026pfvf-\u003eqset.sq[sq_idx];\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c\nindex 0f5d5642d3f7a..7df82c22cc12b 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c\n@@ -93,9 +93,9 @@ static int rvu_rep_mcam_flow_init(struct rep_dev *rep)\n \trep-\u003eflow_cfg-\u003emax_flows = allocated;\n \n \tif (allocated) {\n-\t\trep-\u003eflags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;\n-\t\trep-\u003eflags |= OTX2_FLAG_NTUPLE_SUPPORT;\n-\t\trep-\u003eflags |= OTX2_FLAG_TC_FLOWER_SUPPORT;\n+\t\tset_bit(OTX2_FLAG_MCAM_ENTRIES_ALLOC, \u0026rep-\u003eflags);\n+\t\tset_bit(OTX2_FLAG_NTUPLE_SUPPORT, \u0026rep-\u003eflags);\n+\t\tset_bit(OTX2_FLAG_TC_FLOWER_SUPPORT, \u0026rep-\u003eflags);\n \t}\n \n \tINIT_LIST_HEAD(\u0026rep-\u003eflow_cfg-\u003eflow_list);\n@@ -109,14 +109,14 @@ static int rvu_rep_setup_tc_cb(enum tc_setup_type type,\n \tstruct rep_dev *rep = cb_priv;\n \tstruct otx2_nic *priv = rep-\u003emdev;\n \n-\tif (!(rep-\u003eflags \u0026 RVU_REP_VF_INITIALIZED))\n+\tif (!test_bit(OTX2_FLAG_REP_VF_INITIALIZED, \u0026rep-\u003eflags))\n \t\treturn -EINVAL;\n \n-\tif (!(rep-\u003eflags \u0026 OTX2_FLAG_TC_FLOWER_SUPPORT))\n+\tif (!test_bit(OTX2_FLAG_TC_FLOWER_SUPPORT, \u0026rep-\u003eflags))\n \t\trvu_rep_mcam_flow_init(rep);\n \n \tpriv-\u003enetdev = rep-\u003enetdev;\n-\tpriv-\u003eflags = rep-\u003eflags;\n+\totx2_sync_flags_from_rep(priv, \u0026rep-\u003eflags);\n \tpriv-\u003epcifunc = rep-\u003epcifunc;\n \tpriv-\u003eflow_cfg = rep-\u003eflow_cfg;\n \n@@ -303,9 +303,9 @@ static void rvu_rep_state_evt_handler(struct otx2_nic *priv,\n \trep_id = rvu_rep_get_repid(priv, info-\u003epcifunc);\n \trep = priv-\u003ereps[rep_id];\n \tif (info-\u003eevt_data.vf_state)\n-\t\trep-\u003eflags |= RVU_REP_VF_INITIALIZED;\n+\t\tset_bit(OTX2_FLAG_REP_VF_INITIALIZED, \u0026rep-\u003eflags);\n \telse\n-\t\trep-\u003eflags \u0026= ~RVU_REP_VF_INITIALIZED;\n+\t\tclear_bit(OTX2_FLAG_REP_VF_INITIALIZED, \u0026rep-\u003eflags);\n }\n \n int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info)\n@@ -382,7 +382,7 @@ static void rvu_rep_get_stats64(struct net_device *dev,\n {\n \tstruct rep_dev *rep = netdev_priv(dev);\n \n-\tif (!(rep-\u003eflags \u0026 RVU_REP_VF_INITIALIZED))\n+\tif (!test_bit(OTX2_FLAG_REP_VF_INITIALIZED, \u0026rep-\u003eflags))\n \t\treturn;\n \n \tstats-\u003erx_packets = rep-\u003estats.rx_frames;\n@@ -453,7 +453,7 @@ static int rvu_rep_open(struct net_device *dev)\n \tstruct otx2_nic *priv = rep-\u003emdev;\n \tstruct rep_event evt = {0};\n \n-\tif (!(rep-\u003eflags \u0026 RVU_REP_VF_INITIALIZED))\n+\tif (!test_bit(OTX2_FLAG_REP_VF_INITIALIZED, \u0026rep-\u003eflags))\n \t\treturn 0;\n \n \tnetif_carrier_on(dev);\n@@ -472,7 +472,7 @@ static int rvu_rep_stop(struct net_device *dev)\n \tstruct otx2_nic *priv = rep-\u003emdev;\n \tstruct rep_event evt = {0};\n \n-\tif (!(rep-\u003eflags \u0026 RVU_REP_VF_INITIALIZED))\n+\tif (!test_bit(OTX2_FLAG_REP_VF_INITIALIZED, \u0026rep-\u003eflags))\n \t\treturn 0;\n \n \tnetif_carrier_off(dev);\n@@ -547,7 +547,7 @@ static int rvu_rep_napi_init(struct otx2_nic *priv,\n \t\totx2_write64(priv, NIX_LF_CINTX_INT(qidx), BIT_ULL(0));\n \t\totx2_write64(priv, NIX_LF_CINTX_ENA_W1S(qidx), BIT_ULL(0));\n \t}\n-\tpriv-\u003eflags \u0026= ~OTX2_FLAG_INTF_DOWN;\n+\totx2_clear_flag(priv, OTX2_FLAG_INTF_DOWN);\n \treturn 0;\n \n err_free_cints:\n@@ -632,7 +632,7 @@ void rvu_rep_destroy(struct otx2_nic *priv)\n \tint rep_id;\n \n \trvu_eswitch_config(priv, false);\n-\tpriv-\u003eflags |= OTX2_FLAG_INTF_DOWN;\n+\totx2_set_flag(priv, OTX2_FLAG_INTF_DOWN);\n \trvu_rep_free_cq_rsrc(priv);\n \tfor (rep_id = 0; rep_id \u003c priv-\u003erep_cnt; rep_id++) {\n \t\trep = priv-\u003ereps[rep_id];\n@@ -801,8 +801,8 @@ static int rvu_rep_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n \tpci_set_drvdata(pdev, priv);\n \tpriv-\u003epdev = pdev;\n \tpriv-\u003edev = dev;\n-\tpriv-\u003eflags |= OTX2_FLAG_INTF_DOWN;\n-\tpriv-\u003eflags |= OTX2_FLAG_REP_MODE_ENABLED;\n+\totx2_set_flag(priv, OTX2_FLAG_INTF_DOWN);\n+\totx2_set_flag(priv, OTX2_FLAG_REP_MODE_ENABLED);\n \n \thw = \u0026priv-\u003ehw;\n \thw-\u003epdev = pdev;\n@@ -845,7 +845,7 @@ static void rvu_rep_remove(struct pci_dev *pdev)\n \tstruct otx2_nic *priv = pci_get_drvdata(pdev);\n \n \totx2_unregister_dl(priv);\n-\tif (!(priv-\u003eflags \u0026 OTX2_FLAG_INTF_DOWN))\n+\tif (!otx2_test_flag(priv, OTX2_FLAG_INTF_DOWN))\n \t\trvu_rep_destroy(priv);\n \totx2_detach_resources(\u0026priv-\u003embox);\n \tif (priv-\u003ehw.lmt_info)\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h\nindex 5bc9e2c7d800b..45707c434d89f 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h\n@@ -37,8 +37,7 @@ struct rep_dev {\n \tstruct delayed_work stats_wrk;\n \tstruct devlink_port dl_port;\n \tstruct otx2_flow_config\t*flow_cfg;\n-#define RVU_REP_VF_INITIALIZED\t\tBIT_ULL(0)\n-\tu64 flags;\n+\tunsigned long\t\tflags;\n \tu16 rep_id;\n \tu16 pcifunc;\n \tu8 mac[ETH_ALEN];\n"
} |
| 2/1 | 2026/09/25 08:57 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series modifies only the Marvell OcteonTX2 NIC driver (drivers/net/ethernet/marvell/octeontx2/nic/). This driver requires vendor-specific Cavium/Marvell OcteonTX2 physical ASIC/PCIe hardware (primarily ARM64 SoC/SmartNIC silicon) that is not emulated in standard virtualized fuzzing environments (QEMU/GCE), making the modified code structurally unreachable for syzkaller.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any '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: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 1f60c40a3f415df94ede05c9b547c42901cc4723
Author: syz-cluster <triage@syzkaller.com>
Date: Fri Sep 25 08:57:45 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c
index 77543d472345e..50ec4542c4183 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c
@@ -334,7 +334,7 @@ static int cn10k_outb_cpt_init(struct net_device *netdev)
CN10K_CPT_LF_NQX(0));
/* Set ipsec offload enabled for this device */
- pf->flags |= OTX2_FLAG_IPSEC_OFFLOAD_ENABLED;
+ otx2_set_flag(pf, OTX2_FLAG_IPSEC_OFFLOAD_ENABLED);
cn10k_cpt_device_set_available(pf);
return 0;
@@ -356,7 +356,7 @@ static int cn10k_outb_cpt_clean(struct otx2_nic *pf)
}
/* Set ipsec offload disabled for this device */
- pf->flags &= ~OTX2_FLAG_IPSEC_OFFLOAD_ENABLED;
+ otx2_clear_flag(pf, OTX2_FLAG_IPSEC_OFFLOAD_ENABLED);
/* Disable CPTLF Instruction Queue (IQ) */
cn10k_outb_cptlf_iq_disable(pf);
@@ -820,7 +820,7 @@ void cn10k_ipsec_clean(struct otx2_nic *pf)
if (!is_dev_support_ipsec_offload(pf->pdev))
return;
- if (!(pf->flags & OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))
+ if (!otx2_test_flag(pf, OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))
return;
if (pf->ipsec.sa_workq) {
@@ -945,7 +945,7 @@ bool cn10k_ipsec_transmit(struct otx2_nic *pf, struct netdev_queue *txq,
u16 dlen;
/* Check for IPSEC offload enabled */
- if (!(pf->flags & OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))
+ if (!otx2_test_flag(pf, OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))
goto drop;
sp = skb_sec_path(skb);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
index 175992188c18a..8b922d719491f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
@@ -220,10 +220,10 @@ int otx2_set_mac_address(struct net_device *netdev, void *p)
eth_hw_addr_set(netdev, addr->sa_data);
/* update dmac field in vlan offload rule */
if (netif_running(netdev) &&
- pfvf->flags & OTX2_FLAG_RX_VLAN_SUPPORT)
+ otx2_test_flag(pfvf, OTX2_FLAG_RX_VLAN_SUPPORT))
otx2_install_rxvlan_offload_flow(pfvf);
/* update dmac address in ntuple and DMAC filter list */
- if (pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_DMACFLTR_SUPPORT))
otx2_dmacflt_update_pfmac_flow(pfvf);
} else {
return -EPERM;
@@ -275,8 +275,8 @@ int otx2_config_pause_frm(struct otx2_nic *pfvf)
goto unlock;
}
- req->rx_pause = !!(pfvf->flags & OTX2_FLAG_RX_PAUSE_ENABLED);
- req->tx_pause = !!(pfvf->flags & OTX2_FLAG_TX_PAUSE_ENABLED);
+ req->rx_pause = otx2_test_flag(pfvf, OTX2_FLAG_RX_PAUSE_ENABLED);
+ req->tx_pause = otx2_test_flag(pfvf, OTX2_FLAG_TX_PAUSE_ENABLED);
req->set = 1;
err = otx2_sync_mbox_msg(&pfvf->mbox);
@@ -615,6 +615,138 @@ void otx2_get_mac_from_af(struct net_device *netdev)
}
EXPORT_SYMBOL(otx2_get_mac_from_af);
+static int
+otx2_nix_tmq_reg_write(struct otx2_nic *pfvf, int cnt,
+ u64 reg_addr[MAX_REGS_PER_MBOX_MSG],
+ u64 reg_val[MAX_REGS_PER_MBOX_MSG])
+{
+ struct mbox *mbox = &pfvf->mbox;
+ struct nix_txschq_config *req;
+ int i, err;
+
+ mutex_lock(&mbox->lock);
+ req = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox);
+ if (!req) {
+ mutex_unlock(&mbox->lock);
+ return -ENOMEM;
+ }
+
+ req->lvl = NIX_TXSCH_LVL_MDQ;
+ req->num_regs = cnt;
+
+ for (i = 0; i < cnt; i++) {
+ req->reg[i] = reg_addr[i];
+ req->regval[i] = reg_val[i];
+ }
+
+ err = otx2_sync_mbox_msg(mbox);
+ mutex_unlock(&mbox->lock);
+
+ return err;
+}
+
+int otx2_nix_tm_clear_queue_shaper(struct otx2_nic *pfvf)
+{
+ u64 reg_addr[MAX_REGS_PER_MBOX_MSG];
+ u64 reg_val[MAX_REGS_PER_MBOX_MSG];
+ int err, smq, i, cnt = 0;
+
+ for (i = 0; i < pfvf->hw.txschq_cnt[NIX_TXSCH_LVL_SMQ]; i++) {
+ smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][i];
+
+ reg_addr[cnt] = NIX_AF_MDQX_PIR(smq);
+ reg_val[cnt] = 0;
+ cnt++;
+
+ reg_addr[cnt] = NIX_AF_MDQX_CIR(smq);
+ reg_val[cnt] = 0;
+ cnt++;
+
+ if (cnt < MAX_REGS_PER_MBOX_MSG - 1)
+ continue;
+
+ err = otx2_nix_tmq_reg_write(pfvf, cnt,
+ reg_addr, reg_val);
+ if (err)
+ goto fail;
+ cnt = 0;
+ }
+
+ if (cnt) {
+ err = otx2_nix_tmq_reg_write(pfvf, cnt,
+ reg_addr, reg_val);
+ if (err)
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return err;
+}
+
+int otx2_nix_tm_set_queue_shaper(struct otx2_nic *pfvf,
+ int txq, u64 minrate, u64 maxrate)
+{
+ struct mbox *mbox = &pfvf->mbox;
+ struct nix_txschq_config *req;
+ int err, smq, n = 0;
+ u64 reg_addr[2];
+ u64 reg_val[2];
+ u64 rate;
+
+ if (!maxrate && !minrate) {
+ smq = otx2_get_smq_idx(pfvf, txq);
+ reg_addr[0] = NIX_AF_MDQX_PIR(smq);
+ reg_val[0] = 0;
+ reg_addr[1] = NIX_AF_MDQX_CIR(smq);
+ reg_val[1] = 0;
+ return otx2_nix_tmq_reg_write(pfvf, 2, reg_addr, reg_val);
+ }
+
+ smq = otx2_get_smq_idx(pfvf, txq);
+
+ mutex_lock(&mbox->lock);
+ req = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox);
+ if (!req) {
+ mutex_unlock(&mbox->lock);
+ return -ENOMEM;
+ }
+
+ req->lvl = NIX_TXSCH_LVL_MDQ;
+
+ /* MQPRIO exposes only min/max rate, not burst. Use the same 65536
+ * byte default as the HTB shaper path.
+ *
+ * mqprio setup restarts the netdev (otx2_mqprio_restart_netdev),
+ * which resets MDQ shapers to zero. Program both PIR and CIR on
+ * every update so omitted rates are applied explicitly rather than
+ * relying on stale hardware state.
+ */
+ req->reg[n] = NIX_AF_MDQX_PIR(smq);
+ if (maxrate) {
+ rate = otx2_convert_rate(maxrate);
+ req->regval[n] = otx2_get_txschq_rate_regval(pfvf, rate, 65536);
+ } else {
+ req->regval[n] = 0;
+ }
+ n++;
+
+ /* CIR+PIR support is required and checked at mqprio setup. */
+ req->reg[n] = NIX_AF_MDQX_CIR(smq);
+ if (minrate) {
+ rate = otx2_convert_rate(minrate);
+ req->regval[n] = otx2_get_txschq_rate_regval(pfvf, rate, 65536);
+ } else {
+ req->regval[n] = 0;
+ }
+ n++;
+ req->num_regs = n;
+
+ err = otx2_sync_mbox_msg(mbox);
+ mutex_unlock(&mbox->lock);
+ return err;
+}
+
int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for_pfc)
{
u16 (*schq_list)[MAX_TXSCHQ_PER_FUNC];
@@ -651,7 +783,11 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for
(u64)hw->smq_link_type);
req->num_regs++;
/* MDQ config */
- parent = schq_list[NIX_TXSCH_LVL_TL4][prio];
+ if (pfvf->mqprio.rate_limit)
+ parent = schq_list[NIX_TXSCH_LVL_TL4][0];
+ else
+ parent = schq_list[NIX_TXSCH_LVL_TL4][prio];
+
req->reg[1] = NIX_AF_MDQX_PARENT(schq);
req->regval[1] = parent << 16;
req->num_regs++;
@@ -779,6 +915,9 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf)
req->schq[NIX_TXSCH_LVL_TL4] = chan_cnt;
}
+ if (pfvf->mqprio.rate_limit)
+ req->schq[NIX_TXSCH_LVL_SMQ] = pfvf->hw.non_qos_queues;
+
rc = otx2_sync_mbox_msg(&pfvf->mbox);
if (rc)
return rc;
@@ -844,6 +983,7 @@ void otx2_txschq_stop(struct otx2_nic *pfvf)
/* Clear the txschq list */
for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ pfvf->hw.txschq_cnt[lvl] = 0;
for (schq = 0; schq < MAX_TXSCHQ_PER_FUNC; schq++)
pfvf->hw.txschq_list[lvl][schq] = 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
index 5850bc1870a1d..7bbb162fdffa7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
@@ -17,6 +17,7 @@
#include <linux/soc/marvell/silicons.h>
#include <linux/soc/marvell/octeontx2/asm.h>
#include <net/macsec.h>
+#include <uapi/linux/pkt_sched.h>
#include <net/pkt_cls.h>
#include <net/devlink.h>
#include <linux/time64.h>
@@ -482,6 +483,61 @@ struct pf_irq_data {
int mdevs;
};
+enum otx2_flag_bits {
+ OTX2_FLAG_RX_TSTAMP_ENABLED,
+ OTX2_FLAG_TX_TSTAMP_ENABLED,
+ OTX2_FLAG_INTF_DOWN,
+ OTX2_FLAG_MCAM_ENTRIES_ALLOC,
+ OTX2_FLAG_NTUPLE_SUPPORT,
+ OTX2_FLAG_UCAST_FLTR_SUPPORT,
+ OTX2_FLAG_RX_VLAN_SUPPORT,
+ OTX2_FLAG_VF_VLAN_SUPPORT,
+ OTX2_FLAG_PF_SHUTDOWN,
+ OTX2_FLAG_RX_PAUSE_ENABLED,
+ OTX2_FLAG_TX_PAUSE_ENABLED,
+ OTX2_FLAG_TC_FLOWER_SUPPORT,
+ OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED,
+ OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED,
+ OTX2_FLAG_DMACFLTR_SUPPORT,
+ OTX2_FLAG_PTP_ONESTEP_SYNC,
+ OTX2_FLAG_ADPTV_INT_COAL_ENABLED,
+ OTX2_FLAG_TC_MARK_ENABLED,
+ OTX2_FLAG_REP_MODE_ENABLED,
+ OTX2_FLAG_PORT_UP,
+ OTX2_FLAG_IPSEC_OFFLOAD_ENABLED,
+ OTX2_FLAG_REP_VF_INITIALIZED,
+ OTX2_FLAG_MAX,
+};
+
+/* Representor-owned flags copied onto the PF mailbox context in
+ * rvu_rep_setup_tc_cb(). All other bits are owned by the PF/VF netdev.
+ */
+#define OTX2_REP_SYNC_FLAGS_MASK \
+ (BIT(OTX2_FLAG_MCAM_ENTRIES_ALLOC) | \
+ BIT(OTX2_FLAG_NTUPLE_SUPPORT) | \
+ BIT(OTX2_FLAG_TC_FLOWER_SUPPORT) | \
+ BIT(OTX2_FLAG_REP_VF_INITIALIZED))
+
+struct mq_offload_snap {
+ u64 min_rate[TC_QOPT_MAX_QUEUE];
+ u64 max_rate[TC_QOPT_MAX_QUEUE];
+ u32 flags;
+ __u8 num_tc;
+ __u16 count[TC_QOPT_MAX_QUEUE];
+ __u16 offset[TC_QOPT_MAX_QUEUE];
+ __u8 prio_tc_map[TC_QOPT_BITMASK + 1];
+};
+
+struct otx2_mqprio {
+ u32 flags;
+ u64 *min_rate;
+ u64 *max_rate;
+ bool rate_limit;
+ bool replace_setup_done;
+ bool replace_graft_done;
+ struct work_struct netdev_tc_work;
+};
+
struct otx2_nic {
void __iomem *reg_base;
struct net_device *netdev;
@@ -490,30 +546,13 @@ struct otx2_nic {
u16 tx_max_pktlen;
u16 rbsize; /* Receive buffer size */
-#define OTX2_FLAG_RX_TSTAMP_ENABLED BIT_ULL(0)
-#define OTX2_FLAG_TX_TSTAMP_ENABLED BIT_ULL(1)
-#define OTX2_FLAG_INTF_DOWN BIT_ULL(2)
-#define OTX2_FLAG_MCAM_ENTRIES_ALLOC BIT_ULL(3)
-#define OTX2_FLAG_NTUPLE_SUPPORT BIT_ULL(4)
-#define OTX2_FLAG_UCAST_FLTR_SUPPORT BIT_ULL(5)
-#define OTX2_FLAG_RX_VLAN_SUPPORT BIT_ULL(6)
-#define OTX2_FLAG_VF_VLAN_SUPPORT BIT_ULL(7)
-#define OTX2_FLAG_PF_SHUTDOWN BIT_ULL(8)
-#define OTX2_FLAG_RX_PAUSE_ENABLED BIT_ULL(9)
-#define OTX2_FLAG_TX_PAUSE_ENABLED BIT_ULL(10)
-#define OTX2_FLAG_TC_FLOWER_SUPPORT BIT_ULL(11)
-#define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED BIT_ULL(12)
-#define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED BIT_ULL(13)
-#define OTX2_FLAG_DMACFLTR_SUPPORT BIT_ULL(14)
-#define OTX2_FLAG_PTP_ONESTEP_SYNC BIT_ULL(15)
-#define OTX2_FLAG_ADPTV_INT_COAL_ENABLED BIT_ULL(16)
-#define OTX2_FLAG_TC_MARK_ENABLED BIT_ULL(17)
-#define OTX2_FLAG_REP_MODE_ENABLED BIT_ULL(18)
-#define OTX2_FLAG_PORT_UP BIT_ULL(19)
-#define OTX2_FLAG_IPSEC_OFFLOAD_ENABLED BIT_ULL(20)
- u64 flags;
+ unsigned long flags;
u64 *cq_op_addr;
+ struct otx2_mqprio mqprio;
+ struct mq_offload_snap *cur_mq_snap;
+ struct mq_offload_snap *old_mq_snap;
+
struct bpf_prog *xdp_prog;
struct otx2_qset qset;
struct otx2_hw hw;
@@ -593,6 +632,32 @@ struct otx2_nic {
unsigned long *af_xdp_zc_qidx;
};
+static inline void otx2_set_flag(struct otx2_nic *nic, unsigned int flag)
+{
+ set_bit(flag, &nic->flags);
+}
+
+static inline void otx2_clear_flag(struct otx2_nic *nic, unsigned int flag)
+{
+ clear_bit(flag, &nic->flags);
+}
+
+static inline bool otx2_test_flag(struct otx2_nic *nic, unsigned int flag)
+{
+ return test_bit(flag, &nic->flags);
+}
+
+static inline void otx2_sync_flags_from_rep(struct otx2_nic *dst,
+ unsigned long *src_flags)
+{
+ unsigned long src = READ_ONCE(*src_flags);
+ unsigned long new_flags;
+
+ new_flags = (READ_ONCE(dst->flags) & ~OTX2_REP_SYNC_FLAGS_MASK) |
+ (src & OTX2_REP_SYNC_FLAGS_MASK);
+ WRITE_ONCE(dst->flags, new_flags);
+}
+
static inline bool is_otx2_lbkvf(struct pci_dev *pdev)
{
return (pdev->device == PCI_DEVID_OCTEONTX2_RVU_AFVF) ||
@@ -996,6 +1061,8 @@ static inline u16 otx2_get_smq_idx(struct otx2_nic *pfvf, u16 qidx)
if (qidx >= pfvf->hw.non_qos_queues) {
smq = pfvf->qos.qid_to_sqmap[qidx - pfvf->hw.non_qos_queues];
} else {
+ if (!pfvf->hw.txschq_cnt[NIX_TXSCH_LVL_SMQ])
+ return 0;
idx = qidx % pfvf->hw.txschq_cnt[NIX_TXSCH_LVL_SMQ];
smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][idx];
}
@@ -1245,6 +1312,11 @@ dma_addr_t otx2_dma_map_skb_frag(struct otx2_nic *pfvf,
struct sk_buff *skb, int seg, int *len);
void otx2_dma_unmap_skb_frags(struct otx2_nic *pfvf, struct sg_list *sg);
int otx2_read_free_sqe(struct otx2_nic *pfvf, u16 qidx);
+int otx2_nix_tm_set_queue_shaper(struct otx2_nic *pfvf, int txq,
+ u64 minrate, u64 maxrate);
+int otx2_nix_tm_clear_queue_shaper(struct otx2_nic *pfvf);
+int otx2_mqprio_down(struct otx2_nic *pfvf);
+int otx2_mqprio_up(struct otx2_nic *pfvf);
void otx2_queue_vf_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
int first, int mdevs, u64 intr);
int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry,
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c
index 91d346d114af5..b7bd08129fb64 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c
@@ -413,6 +413,12 @@ static int otx2_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc)
u8 old_pfc_en;
int err;
+ if (pfvf->mqprio.rate_limit && pfc->pfc_en) {
+ netdev_err(dev,
+ "PFC: cannot enable while mqprio bandwidth offload is active\n");
+ return -EOPNOTSUPP;
+ }
+
old_pfc_en = pfvf->pfc_en;
pfvf->pfc_en = pfc->pfc_en;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
index 4a5ce0e67dda8..863a5ced9a26b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
@@ -104,7 +104,7 @@ static int otx2_dl_ucast_flt_cnt_validate(struct devlink *devlink, u32 id,
struct otx2_nic *pfvf = otx2_dl->pfvf;
/* Check for UNICAST filter support*/
- if (!(pfvf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT)) {
+ if (!otx2_test_flag(pfvf, OTX2_FLAG_UCAST_FLTR_SUPPORT)) {
NL_SET_ERR_MSG_MOD(extack,
"Unicast filter not enabled");
return -EINVAL;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
index a05dee0085a39..5428b3d1b3329 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
@@ -287,6 +287,14 @@ static int otx2_set_channels(struct net_device *dev,
return -EINVAL;
}
+ if (pfvf->mqprio.rate_limit &&
+ (channel->tx_count != pfvf->hw.tx_queues ||
+ channel->rx_count != pfvf->hw.rx_queues)) {
+ netdev_info(dev,
+ "Not permitted to change channel count while MQ prio is active\n");
+ return -EINVAL;
+ }
+
if (if_up)
dev->netdev_ops->ndo_stop(dev);
@@ -354,14 +362,14 @@ static int otx2_set_pauseparam(struct net_device *netdev,
return -EOPNOTSUPP;
if (pause->rx_pause)
- pfvf->flags |= OTX2_FLAG_RX_PAUSE_ENABLED;
+ otx2_set_flag(pfvf, OTX2_FLAG_RX_PAUSE_ENABLED);
else
- pfvf->flags &= ~OTX2_FLAG_RX_PAUSE_ENABLED;
+ otx2_clear_flag(pfvf, OTX2_FLAG_RX_PAUSE_ENABLED);
if (pause->tx_pause)
- pfvf->flags |= OTX2_FLAG_TX_PAUSE_ENABLED;
+ otx2_set_flag(pfvf, OTX2_FLAG_TX_PAUSE_ENABLED);
else
- pfvf->flags &= ~OTX2_FLAG_TX_PAUSE_ENABLED;
+ otx2_clear_flag(pfvf, OTX2_FLAG_TX_PAUSE_ENABLED);
return otx2_config_pause_frm(pfvf);
}
@@ -470,8 +478,7 @@ static int otx2_get_coalesce(struct net_device *netdev,
cmd->rx_max_coalesced_frames = hw->cq_ecount_wait;
cmd->tx_coalesce_usecs = hw->cq_time_wait;
cmd->tx_max_coalesced_frames = hw->cq_ecount_wait;
- if ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) ==
- OTX2_FLAG_ADPTV_INT_COAL_ENABLED) {
+ if (otx2_test_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED)) {
cmd->use_adaptive_rx_coalesce = 1;
cmd->use_adaptive_tx_coalesce = 1;
} else {
@@ -502,15 +509,14 @@ static int otx2_set_coalesce(struct net_device *netdev,
}
/* Check and update coalesce status */
- if ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) ==
- OTX2_FLAG_ADPTV_INT_COAL_ENABLED) {
+ if (otx2_test_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED)) {
priv_coalesce_status = 1;
if (!ec->use_adaptive_rx_coalesce)
- pfvf->flags &= ~OTX2_FLAG_ADPTV_INT_COAL_ENABLED;
+ otx2_clear_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED);
} else {
priv_coalesce_status = 0;
if (ec->use_adaptive_rx_coalesce)
- pfvf->flags |= OTX2_FLAG_ADPTV_INT_COAL_ENABLED;
+ otx2_set_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED);
}
/* 'cq_time_wait' is 8bit and is in multiple of 100ns,
@@ -556,8 +562,7 @@ static int otx2_set_coalesce(struct net_device *netdev,
* 'on' to 'off'.
*/
if (priv_coalesce_status &&
- ((pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED) !=
- OTX2_FLAG_ADPTV_INT_COAL_ENABLED)) {
+ (!otx2_test_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED))) {
hw->cq_time_wait = CQ_TIMER_THRESH_DEFAULT;
hw->cq_ecount_wait = CQ_CQE_THRESH_DEFAULT;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
index 99d78fc5a2c4a..b8ff49f0f6e3b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
@@ -270,9 +270,9 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
flow_cfg->max_flows = allocated;
if (allocated) {
- pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
- pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
- pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
+ otx2_set_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC);
+ otx2_set_flag(pfvf, OTX2_FLAG_NTUPLE_SUPPORT);
+ otx2_set_flag(pfvf, OTX2_FLAG_TC_FLOWER_SUPPORT);
}
if (allocated != count)
@@ -376,7 +376,7 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
flow_cfg->unicast_offset = vf_vlan_max_flows;
flow_cfg->rx_vlan_offset = flow_cfg->unicast_offset +
flow_cfg->ucast_flt_cnt;
- pfvf->flags |= OTX2_FLAG_UCAST_FLTR_SUPPORT;
+ otx2_set_flag(pfvf, OTX2_FLAG_UCAST_FLTR_SUPPORT);
/* Check if NPC_DMAC field is supported
* by the mkex profile before setting VLAN support flag.
@@ -401,11 +401,11 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
}
if (frsp->enable) {
- pfvf->flags |= OTX2_FLAG_RX_VLAN_SUPPORT;
- pfvf->flags |= OTX2_FLAG_VF_VLAN_SUPPORT;
+ otx2_set_flag(pfvf, OTX2_FLAG_RX_VLAN_SUPPORT);
+ otx2_set_flag(pfvf, OTX2_FLAG_VF_VLAN_SUPPORT);
}
- pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
+ otx2_set_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC);
mutex_unlock(&pfvf->mbox.lock);
/* Allocate entries for Ntuple filters */
@@ -415,7 +415,7 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
return 0;
}
- pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
+ otx2_set_flag(pfvf, OTX2_FLAG_TC_FLOWER_SUPPORT);
refcount_set(&flow_cfg->mark_flows, 1);
return 0;
@@ -479,7 +479,7 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
return err;
/* Check if MCAM entries are allocate or not */
- if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
+ if (!otx2_test_flag(pf, OTX2_FLAG_UCAST_FLTR_SUPPORT))
return 0;
pf->mac_table = devm_kzalloc(pf->dev, sizeof(struct otx2_mac_table)
@@ -501,7 +501,7 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
if (!pf->flow_cfg->bmap_to_dmacindex)
return -ENOMEM;
- pf->flags |= OTX2_FLAG_DMACFLTR_SUPPORT;
+ otx2_set_flag(pf, OTX2_FLAG_DMACFLTR_SUPPORT);
return 0;
}
@@ -521,7 +521,7 @@ static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac)
struct npc_install_flow_req *req;
int err, i;
- if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
+ if (!otx2_test_flag(pf, OTX2_FLAG_UCAST_FLTR_SUPPORT))
return -ENOMEM;
/* dont have free mcam entries or uc list is greater than alloted */
@@ -1167,7 +1167,7 @@ static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
u64 ring_cookie = fsp->ring_cookie;
u32 flow_type;
- if (!(pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT))
+ if (!otx2_test_flag(pfvf, OTX2_FLAG_DMACFLTR_SUPPORT))
return false;
flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
@@ -1364,7 +1364,7 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
}
ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
- if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
+ if (!otx2_test_flag(pfvf, OTX2_FLAG_NTUPLE_SUPPORT))
return -ENOMEM;
/* Number of queues on a VF can be greater or less than
@@ -1596,7 +1596,7 @@ int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf)
struct otx2_flow *iter, *tmp;
int err;
- if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
+ if (!otx2_test_flag(pfvf, OTX2_FLAG_NTUPLE_SUPPORT))
return 0;
if (!flow_cfg->max_flows)
@@ -1629,7 +1629,7 @@ int otx2_destroy_mcam_flows(struct otx2_nic *pfvf)
struct otx2_flow *iter, *tmp;
int err;
- if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
+ if (!otx2_test_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC))
return 0;
/* remove all flows */
@@ -1658,7 +1658,7 @@ int otx2_destroy_mcam_flows(struct otx2_nic *pfvf)
return err;
}
- pfvf->flags &= ~OTX2_FLAG_MCAM_ENTRIES_ALLOC;
+ otx2_clear_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC);
flow_cfg->max_flows = 0;
mutex_unlock(&pfvf->mbox.lock);
@@ -1721,7 +1721,7 @@ int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable)
int err;
/* Dont have enough mcam entries */
- if (!(pf->flags & OTX2_FLAG_RX_VLAN_SUPPORT))
+ if (!otx2_test_flag(pf, OTX2_FLAG_RX_VLAN_SUPPORT))
return -ENOMEM;
if (enable) {
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index c0e2100de1d93..5f1d8287b00e4 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -879,7 +879,7 @@ static void otx2_handle_link_event(struct otx2_nic *pf)
struct cgx_link_user_info *linfo = &pf->linfo;
struct net_device *netdev = pf->netdev;
- if (pf->flags & OTX2_FLAG_PORT_UP)
+ if (otx2_test_flag(pf, OTX2_FLAG_PORT_UP))
return;
pr_info("%s NIC Link is %s %d Mbps %s duplex\n", netdev->name,
@@ -907,11 +907,11 @@ static int otx2_mbox_up_handler_rep_event_up_notify(struct otx2_nic *pf,
if (info->event == RVU_EVENT_PORT_STATE) {
if (info->evt_data.port_state) {
- pf->flags |= OTX2_FLAG_PORT_UP;
+ otx2_set_flag(pf, OTX2_FLAG_PORT_UP);
netif_carrier_on(netdev);
netif_tx_start_all_queues(netdev);
} else {
- pf->flags &= ~OTX2_FLAG_PORT_UP;
+ otx2_clear_flag(pf, OTX2_FLAG_PORT_UP);
netif_tx_stop_all_queues(netdev);
netif_carrier_off(netdev);
}
@@ -953,7 +953,7 @@ int otx2_mbox_up_handler_cgx_link_event(struct otx2_nic *pf,
}
/* interface has not been fully configured yet */
- if (pf->flags & OTX2_FLAG_INTF_DOWN)
+ if (otx2_test_flag(pf, OTX2_FLAG_INTF_DOWN))
return 0;
otx2_handle_link_event(pf);
@@ -1828,7 +1828,7 @@ void otx2_free_hw_resources(struct otx2_nic *pf)
free_req = otx2_mbox_alloc_msg_nix_lf_free(mbox);
if (free_req) {
free_req->flags = NIX_LF_DISABLE_FLOWS | NIX_LF_DONT_FREE_DFT_IDXS;
- if (!(pf->flags & OTX2_FLAG_PF_SHUTDOWN))
+ if (!otx2_test_flag(pf, OTX2_FLAG_PF_SHUTDOWN))
free_req->flags |= NIX_LF_DONT_FREE_TX_VTAG;
if (otx2_sync_mbox_msg(mbox))
dev_err(pf->dev, "%s failed to free nixlf\n", __func__);
@@ -2007,6 +2007,15 @@ int otx2_open(struct net_device *netdev)
if (err)
goto err_free_mem;
+ /* Fail closed: abort open if cached mqprio shapers cannot be restored. */
+ err = otx2_mqprio_up(pf);
+ if (err) {
+ netdev_err(pf->netdev,
+ "mqprio: failed to restore shapers during open: %d\n",
+ err);
+ goto err_free_hw;
+ }
+
/* Register NAPI handler */
for (qidx = 0; qidx < pf->hw.cint_cnt; qidx++) {
cq_poll = &qset->napi[qidx];
@@ -2135,21 +2144,21 @@ int otx2_open(struct net_device *netdev)
}
otx2_write64(pf, NIX_LF_RAS_ENA_W1S, NIX_LF_RAS_MASK);
- if (pf->flags & OTX2_FLAG_RX_VLAN_SUPPORT)
+ if (otx2_test_flag(pf, OTX2_FLAG_RX_VLAN_SUPPORT))
otx2_enable_rxvlan(pf, true);
/* When reinitializing enable time stamping if it is enabled before */
- if (pf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED) {
- pf->flags &= ~OTX2_FLAG_TX_TSTAMP_ENABLED;
+ if (otx2_test_flag(pf, OTX2_FLAG_TX_TSTAMP_ENABLED)) {
+ otx2_clear_flag(pf, OTX2_FLAG_TX_TSTAMP_ENABLED);
otx2_config_hw_tx_tstamp(pf, true);
}
- if (pf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED) {
- pf->flags &= ~OTX2_FLAG_RX_TSTAMP_ENABLED;
+ if (otx2_test_flag(pf, OTX2_FLAG_RX_TSTAMP_ENABLED)) {
+ otx2_clear_flag(pf, OTX2_FLAG_RX_TSTAMP_ENABLED);
otx2_config_hw_rx_tstamp(pf, true);
}
- pf->flags &= ~OTX2_FLAG_INTF_DOWN;
- pf->flags &= ~OTX2_FLAG_PORT_UP;
+ otx2_clear_flag(pf, OTX2_FLAG_INTF_DOWN);
+ otx2_clear_flag(pf, OTX2_FLAG_PORT_UP);
/* 'intf_down' may be checked on any cpu */
smp_wmb();
@@ -2161,7 +2170,7 @@ int otx2_open(struct net_device *netdev)
otx2_handle_link_event(pf);
/* Install DMAC Filters */
- if (pf->flags & OTX2_FLAG_DMACFLTR_SUPPORT)
+ if (otx2_test_flag(pf, OTX2_FLAG_DMACFLTR_SUPPORT))
otx2_dmacflt_reinstall_flows(pf);
otx2_tc_apply_ingress_police_rules(pf);
@@ -2186,7 +2195,7 @@ int otx2_open(struct net_device *netdev)
err_tx_stop_queues:
netif_tx_stop_all_queues(netdev);
netif_carrier_off(netdev);
- pf->flags |= OTX2_FLAG_INTF_DOWN;
+ otx2_set_flag(pf, OTX2_FLAG_INTF_DOWN);
/* free NIXLF POISON irq */
vec = pci_irq_vector(pf->pdev,
pf->hw.nix_msixoff + NIX_LF_POISON_VEC);
@@ -2205,6 +2214,7 @@ int otx2_open(struct net_device *netdev)
free_irq(vec, pf);
err_disable_napi:
otx2_disable_napi(pf);
+err_free_hw:
otx2_free_hw_resources(pf);
err_free_mem:
otx2_free_queue_mem(qset);
@@ -2220,13 +2230,13 @@ int otx2_stop(struct net_device *netdev)
int qidx, vec, wrk;
/* If the DOWN flag is set resources are already freed */
- if (pf->flags & OTX2_FLAG_INTF_DOWN)
+ if (otx2_test_flag(pf, OTX2_FLAG_INTF_DOWN))
return 0;
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
- pf->flags |= OTX2_FLAG_INTF_DOWN;
+ otx2_set_flag(pf, OTX2_FLAG_INTF_DOWN);
/* 'intf_down' may be checked on any cpu */
smp_wmb();
@@ -2280,6 +2290,7 @@ int otx2_stop(struct net_device *netdev)
for (qidx = 0; qidx < netdev->num_tx_queues; qidx++)
netdev_tx_reset_queue(netdev_get_tx_queue(netdev, qidx));
+ synchronize_net();
otx2_free_queue_mem(qset);
/* Do not clear RQ/SQ ringsize settings */
memset_startat(qset, 0, sqe_cnt);
@@ -2457,7 +2468,7 @@ static int otx2_config_hw_rx_tstamp(struct otx2_nic *pfvf, bool enable)
struct msg_req *req;
int err;
- if (pfvf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED && enable)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_RX_TSTAMP_ENABLED) && enable)
return 0;
mutex_lock(&pfvf->mbox.lock);
@@ -2478,9 +2489,9 @@ static int otx2_config_hw_rx_tstamp(struct otx2_nic *pfvf, bool enable)
mutex_unlock(&pfvf->mbox.lock);
if (enable)
- pfvf->flags |= OTX2_FLAG_RX_TSTAMP_ENABLED;
+ otx2_set_flag(pfvf, OTX2_FLAG_RX_TSTAMP_ENABLED);
else
- pfvf->flags &= ~OTX2_FLAG_RX_TSTAMP_ENABLED;
+ otx2_clear_flag(pfvf, OTX2_FLAG_RX_TSTAMP_ENABLED);
return 0;
}
@@ -2489,7 +2500,7 @@ static int otx2_config_hw_tx_tstamp(struct otx2_nic *pfvf, bool enable)
struct msg_req *req;
int err;
- if (pfvf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED && enable)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_TX_TSTAMP_ENABLED) && enable)
return 0;
mutex_lock(&pfvf->mbox.lock);
@@ -2510,9 +2521,9 @@ static int otx2_config_hw_tx_tstamp(struct otx2_nic *pfvf, bool enable)
mutex_unlock(&pfvf->mbox.lock);
if (enable)
- pfvf->flags |= OTX2_FLAG_TX_TSTAMP_ENABLED;
+ otx2_set_flag(pfvf, OTX2_FLAG_TX_TSTAMP_ENABLED);
else
- pfvf->flags &= ~OTX2_FLAG_TX_TSTAMP_ENABLED;
+ otx2_clear_flag(pfvf, OTX2_FLAG_TX_TSTAMP_ENABLED);
return 0;
}
@@ -2537,8 +2548,8 @@ int otx2_config_hwtstamp_set(struct net_device *netdev,
switch (config->tx_type) {
case HWTSTAMP_TX_OFF:
- if (pfvf->flags & OTX2_FLAG_PTP_ONESTEP_SYNC)
- pfvf->flags &= ~OTX2_FLAG_PTP_ONESTEP_SYNC;
+ if (otx2_test_flag(pfvf, OTX2_FLAG_PTP_ONESTEP_SYNC))
+ otx2_clear_flag(pfvf, OTX2_FLAG_PTP_ONESTEP_SYNC);
cancel_delayed_work(&pfvf->ptp->synctstamp_work);
otx2_config_hw_tx_tstamp(pfvf, false);
@@ -2549,7 +2560,7 @@ int otx2_config_hwtstamp_set(struct net_device *netdev,
"One-step time stamping is not supported");
return -ERANGE;
}
- pfvf->flags |= OTX2_FLAG_PTP_ONESTEP_SYNC;
+ otx2_set_flag(pfvf, OTX2_FLAG_PTP_ONESTEP_SYNC);
schedule_delayed_work(&pfvf->ptp->synctstamp_work,
msecs_to_jiffies(500));
fallthrough;
@@ -2835,7 +2846,7 @@ static int otx2_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos,
if (proto != htons(ETH_P_8021Q))
return -EPROTONOSUPPORT;
- if (!(pf->flags & OTX2_FLAG_VF_VLAN_SUPPORT))
+ if (!otx2_test_flag(pf, OTX2_FLAG_VF_VLAN_SUPPORT))
return -EOPNOTSUPP;
return otx2_do_set_vf_vlan(pf, vf, vlan, qos, proto);
@@ -2923,6 +2934,12 @@ static int otx2_xdp_setup(struct otx2_nic *pf, struct bpf_prog *prog)
bool if_up = netif_running(pf->netdev);
struct bpf_prog *old_prog;
+ if (prog && pf->mqprio.rate_limit) {
+ netdev_err(dev,
+ "XDP: cannot attach while mqprio bandwidth offload is active\n");
+ return -EOPNOTSUPP;
+ }
+
if (prog && dev->mtu > MAX_XDP_MTU) {
netdev_warn(dev, "Jumbo frames not yet supported with XDP\n");
return -EOPNOTSUPP;
@@ -3086,7 +3103,7 @@ int otx2_realloc_msix_vectors(struct otx2_nic *pf)
* interrupt range (QINT, CINT, GINT, ERR and POISON vectors).
*/
num_vec = hw->nix_msixoff;
- if (pf->flags & OTX2_FLAG_REP_MODE_ENABLED)
+ if (otx2_test_flag(pf, OTX2_FLAG_REP_MODE_ENABLED))
num_vec += NIX_LF_CINT_VEC_START + hw->max_queues;
else
num_vec += NIX_LF_POISON_VEC + 1;
@@ -3273,7 +3290,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pf->pdev = pdev;
pf->dev = dev;
pf->total_vfs = pci_sriov_get_totalvfs(pdev);
- pf->flags |= OTX2_FLAG_INTF_DOWN;
+ otx2_set_flag(pf, OTX2_FLAG_INTF_DOWN);
hw = &pf->hw;
hw->pdev = pdev;
@@ -3328,24 +3345,26 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto err_del_mcam_entries;
- if (pf->flags & OTX2_FLAG_NTUPLE_SUPPORT)
+ if (otx2_test_flag(pf, OTX2_FLAG_NTUPLE_SUPPORT))
netdev->hw_features |= NETIF_F_NTUPLE;
- if (pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT)
+ if (otx2_test_flag(pf, OTX2_FLAG_UCAST_FLTR_SUPPORT))
netdev->priv_flags |= IFF_UNICAST_FLT;
/* Support TSO on tag interface */
netdev->vlan_features |= netdev->features;
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_TX;
- if (pf->flags & OTX2_FLAG_RX_VLAN_SUPPORT)
+ if (otx2_test_flag(pf, OTX2_FLAG_RX_VLAN_SUPPORT))
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_STAG_RX;
netdev->features |= netdev->hw_features;
/* HW supports tc offload but mutually exclusive with n-tuple filters */
- if (pf->flags & OTX2_FLAG_TC_FLOWER_SUPPORT)
+ if (otx2_test_flag(pf, OTX2_FLAG_TC_FLOWER_SUPPORT)) {
netdev->hw_features |= NETIF_F_HW_TC;
+ netdev->features |= NETIF_F_HW_TC;
+ }
netdev->hw_features |= NETIF_F_LOOPBACK | NETIF_F_RXALL;
@@ -3368,10 +3387,14 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto err_mcs_free;
+ err = otx2_init_tc(pf);
+ if (err)
+ goto err_ipsec_clean;
+
err = register_netdev(netdev);
if (err) {
dev_err(dev, "Failed to register netdevice\n");
- goto err_ipsec_clean;
+ goto err_shutdown_tc;
}
err = otx2_wq_init(pf);
@@ -3380,10 +3403,6 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
otx2_set_ethtool_ops(netdev);
- err = otx2_init_tc(pf);
- if (err)
- goto err_mcam_flow_del;
-
err = otx2_register_dl(pf);
if (err)
goto err_mcam_flow_del;
@@ -3420,11 +3439,13 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
otx2_sriov_vfcfg_cleanup(pf);
err_pf_sriov_init:
otx2_unregister_dl(pf);
- otx2_shutdown_tc(pf);
err_mcam_flow_del:
otx2_mcam_flow_del(pf);
err_unreg_netdev:
+ otx2_shutdown_tc(pf);
unregister_netdev(netdev);
+err_shutdown_tc:
+ otx2_shutdown_tc(pf);
err_ipsec_clean:
cn10k_ipsec_clean(pf);
err_mcs_free:
@@ -3595,18 +3616,18 @@ static void otx2_remove(struct pci_dev *pdev)
pf = netdev_priv(netdev);
- pf->flags |= OTX2_FLAG_PF_SHUTDOWN;
+ otx2_set_flag(pf, OTX2_FLAG_PF_SHUTDOWN);
- if (pf->flags & OTX2_FLAG_TX_TSTAMP_ENABLED)
+ if (otx2_test_flag(pf, OTX2_FLAG_TX_TSTAMP_ENABLED))
otx2_config_hw_tx_tstamp(pf, false);
- if (pf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED)
+ if (otx2_test_flag(pf, OTX2_FLAG_RX_TSTAMP_ENABLED))
otx2_config_hw_rx_tstamp(pf, false);
/* Disable 802.3x pause frames */
- if (pf->flags & OTX2_FLAG_RX_PAUSE_ENABLED ||
- (pf->flags & OTX2_FLAG_TX_PAUSE_ENABLED)) {
- pf->flags &= ~OTX2_FLAG_RX_PAUSE_ENABLED;
- pf->flags &= ~OTX2_FLAG_TX_PAUSE_ENABLED;
+ if (otx2_test_flag(pf, OTX2_FLAG_RX_PAUSE_ENABLED) ||
+ otx2_test_flag(pf, OTX2_FLAG_TX_PAUSE_ENABLED)) {
+ otx2_clear_flag(pf, OTX2_FLAG_RX_PAUSE_ENABLED);
+ otx2_clear_flag(pf, OTX2_FLAG_TX_PAUSE_ENABLED);
otx2_config_pause_frm(pf);
}
@@ -3622,6 +3643,7 @@ static void otx2_remove(struct pci_dev *pdev)
otx2_cgx_config_linkevents(pf, false);
otx2_unregister_dl(pf);
+ otx2_shutdown_tc(pf);
unregister_netdev(netdev);
cn10k_ipsec_clean(pf);
cn10k_mcs_free(pf);
@@ -3632,7 +3654,6 @@ static void otx2_remove(struct pci_dev *pdev)
otx2_ptp_destroy(pf);
otx2_mcam_flow_del(pf);
- otx2_shutdown_tc(pf);
otx2_shutdown_qos(pf);
otx2_ndc_sync(pf);
otx2_detach_resources(&pf->mbox);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
index 039fd47ebf522..453c598c6c5db 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
@@ -6,6 +6,8 @@
*/
#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/string.h>
#include <linux/etherdevice.h>
#include <linux/inetdevice.h>
#include <linux/rhashtable.h>
@@ -16,6 +18,7 @@
#include <net/tc_act/tc_mirred.h>
#include <net/tc_act/tc_vlan.h>
#include <net/ipv6.h>
+#include <net/pkt_sched.h>
#include "cn10k.h"
#include "otx2_common.h"
@@ -31,6 +34,19 @@
#define MCAST_INVALID_GRP (-1U)
#define RATE_MANTISSA_BITS 8
+/* Min per-queue egress shaping rate the NIX TLX encoder supports (2 Mbps). */
+#define OTX2_MQPRIO_MIN_RATE_BYTES_PS 250000ULL
+
+static u64 otx2_mqprio_max_rate_bytes_ps(void)
+{
+ u64 max_mbps;
+
+ /* NIX TLX maximum rate (Mbps), not the burst bucket cap. */
+ max_mbps = 2ULL * ((256ULL + MAX_RATE_MANTISSA) << MAX_RATE_EXPONENT) /
+ 256ULL;
+
+ return div_u64(max_mbps * 1000000ULL, 8ULL);
+}
static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
u32 *burst_exp, u32 *burst_mantissa)
@@ -61,6 +77,9 @@ static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
*burst_mantissa = tmp / (1ULL << (*burst_exp - 7));
}
} else {
+ /* burst 0: largest encodable burst (CN10K_MAX_BURST_SIZE on
+ * CN10K), not a minimal burst.
+ */
*burst_exp = MAX_BURST_EXPONENT;
*burst_mantissa = max_mantissa;
}
@@ -159,7 +178,7 @@ static int otx2_tc_validate_flow(struct otx2_nic *nic,
struct flow_action *actions,
struct netlink_ext_ack *extack)
{
- if (nic->flags & OTX2_FLAG_INTF_DOWN) {
+ if (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN)) {
NL_SET_ERR_MSG_MOD(extack, "Interface not initialized");
return -EINVAL;
}
@@ -223,7 +242,7 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,
if (err)
return err;
- if (nic->flags & OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED) {
+ if (otx2_test_flag(nic, OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED)) {
NL_SET_ERR_MSG_MOD(extack,
"Only one Egress MATCHALL ratelimiter can be offloaded");
return -ENOMEM;
@@ -244,7 +263,7 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,
otx2_convert_rate(entry->police.rate_bytes_ps));
if (err)
return err;
- nic->flags |= OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED;
+ otx2_set_flag(nic, OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED);
break;
default:
NL_SET_ERR_MSG_MOD(extack,
@@ -261,13 +280,13 @@ static int otx2_tc_egress_matchall_delete(struct otx2_nic *nic,
struct netlink_ext_ack *extack = cls->common.extack;
int err;
- if (nic->flags & OTX2_FLAG_INTF_DOWN) {
+ if (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN)) {
NL_SET_ERR_MSG_MOD(extack, "Interface not initialized");
return -EINVAL;
}
err = otx2_set_matchall_egress_rate(nic, 0, 0);
- nic->flags &= ~OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED;
+ otx2_clear_flag(nic, OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED);
return err;
}
@@ -505,7 +524,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
mark = act->mark;
req->match_id = mark & OTX2_RX_MATCH_ID_MASK;
req->op = NIX_RX_ACTION_DEFAULT;
- nic->flags |= OTX2_FLAG_TC_MARK_ENABLED;
+ otx2_set_flag(nic, OTX2_FLAG_TC_MARK_ENABLED);
refcount_inc(&nic->flow_cfg->mark_flows);
break;
@@ -942,7 +961,7 @@ static void otx2_destroy_tc_flow_list(struct otx2_nic *pfvf)
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct otx2_tc_flow *iter, *tmp;
- if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
+ if (!otx2_test_flag(pfvf, OTX2_FLAG_MCAM_ENTRIES_ALLOC))
return;
list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list_tc, list) {
@@ -1195,12 +1214,12 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
/* Disable TC MARK flag if they are no rules with skbedit mark action */
if (flow_node->req.match_id)
if (!refcount_dec_and_test(&flow_cfg->mark_flows))
- nic->flags &= ~OTX2_FLAG_TC_MARK_ENABLED;
+ otx2_clear_flag(nic, OTX2_FLAG_TC_MARK_ENABLED);
if (flow_node->is_act_police) {
__clear_bit(flow_node->rq, &nic->rq_bmap);
- if (nic->flags & OTX2_FLAG_INTF_DOWN)
+ if (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN))
goto free_mcam_flow;
mutex_lock(&nic->mbox.lock);
@@ -1246,10 +1265,10 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
struct npc_install_flow_req *req, dummy;
int rc, err, entry;
- if (!(nic->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
+ if (!otx2_test_flag(nic, OTX2_FLAG_TC_FLOWER_SUPPORT))
return -ENOMEM;
- if (nic->flags & OTX2_FLAG_INTF_DOWN) {
+ if (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN)) {
NL_SET_ERR_MSG_MOD(extack, "Interface not initialized");
return -EINVAL;
}
@@ -1444,7 +1463,7 @@ static int otx2_tc_ingress_matchall_install(struct otx2_nic *nic,
if (err)
return err;
- if (nic->flags & OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED) {
+ if (otx2_test_flag(nic, OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED)) {
NL_SET_ERR_MSG_MOD(extack,
"Only one ingress MATCHALL ratelimitter can be offloaded");
return -ENOMEM;
@@ -1469,7 +1488,7 @@ static int otx2_tc_ingress_matchall_install(struct otx2_nic *nic,
err = cn10k_set_matchall_ipolicer_rate(nic, entry->police.burst, rate);
if (err)
return err;
- nic->flags |= OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED;
+ otx2_set_flag(nic, OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED);
break;
default:
NL_SET_ERR_MSG_MOD(extack,
@@ -1486,13 +1505,13 @@ static int otx2_tc_ingress_matchall_delete(struct otx2_nic *nic,
struct netlink_ext_ack *extack = cls->common.extack;
int err;
- if (nic->flags & OTX2_FLAG_INTF_DOWN) {
+ if (otx2_test_flag(nic, OTX2_FLAG_INTF_DOWN)) {
NL_SET_ERR_MSG_MOD(extack, "Interface not initialized");
return -EINVAL;
}
err = cn10k_free_matchall_ipolicer(nic);
- nic->flags &= ~OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED;
+ otx2_clear_flag(nic, OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED);
return err;
}
@@ -1600,14 +1619,827 @@ static int otx2_setup_tc_block(struct net_device *netdev,
nic, nic, ingress);
}
+/* Free the per-queue min/max rate caches. */
+static void otx2_mqprio_free_cache(struct otx2_nic *pfvf)
+{
+ devm_kfree(pfvf->dev, pfvf->mqprio.min_rate);
+ devm_kfree(pfvf->dev, pfvf->mqprio.max_rate);
+ pfvf->mqprio.min_rate = NULL;
+ pfvf->mqprio.max_rate = NULL;
+ pfvf->mqprio.flags = 0;
+}
+
+static int otx2_mqprio_alloc_cache(struct otx2_nic *pfvf, bool replacing)
+{
+ u16 num_txq = pfvf->hw.non_qos_queues;
+ u64 *min_rate, *max_rate;
+
+ if (replacing && pfvf->mqprio.min_rate && pfvf->mqprio.max_rate) {
+ memset(pfvf->mqprio.min_rate, 0,
+ num_txq * sizeof(*pfvf->mqprio.min_rate));
+ memset(pfvf->mqprio.max_rate, 0,
+ num_txq * sizeof(*pfvf->mqprio.max_rate));
+ pfvf->mqprio.flags = 0;
+ return 0;
+ }
+
+ min_rate = devm_kcalloc(pfvf->dev, num_txq, sizeof(*min_rate), GFP_KERNEL);
+ max_rate = devm_kcalloc(pfvf->dev, num_txq, sizeof(*max_rate), GFP_KERNEL);
+ if (!min_rate || !max_rate) {
+ devm_kfree(pfvf->dev, min_rate);
+ devm_kfree(pfvf->dev, max_rate);
+ return -ENOMEM;
+ }
+
+ otx2_mqprio_free_cache(pfvf);
+ pfvf->mqprio.min_rate = min_rate;
+ pfvf->mqprio.max_rate = max_rate;
+
+ return 0;
+}
+
+static void otx2_mqprio_snap_free(struct otx2_nic *pfvf,
+ struct mq_offload_snap **snap)
+{
+ if (!*snap)
+ return;
+
+ devm_kfree(pfvf->dev, *snap);
+ *snap = NULL;
+}
+
+static int otx2_mqprio_snap_copy(struct otx2_nic *pfvf,
+ struct mq_offload_snap **dst,
+ const struct tc_mqprio_qopt_offload *mqprio)
+{
+ const struct tc_mqprio_qopt *qopt = &mqprio->qopt;
+ struct mq_offload_snap *snap;
+ int tc;
+
+ if (!*dst) {
+ snap = devm_kzalloc(pfvf->dev, sizeof(*snap), GFP_KERNEL);
+ if (!snap)
+ return -ENOMEM;
+ *dst = snap;
+ } else {
+ snap = *dst;
+ }
+
+ snap->num_tc = qopt->num_tc;
+ snap->flags = mqprio->flags;
+ for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++) {
+ snap->count[tc] = qopt->count[tc];
+ snap->offset[tc] = qopt->offset[tc];
+ snap->min_rate[tc] = 0;
+ snap->max_rate[tc] = 0;
+ }
+
+ for (tc = 0; tc < qopt->num_tc; tc++) {
+ if (mqprio->flags & TC_MQPRIO_F_MIN_RATE)
+ snap->min_rate[tc] = mqprio->min_rate[tc];
+ if (mqprio->flags & TC_MQPRIO_F_MAX_RATE)
+ snap->max_rate[tc] = mqprio->max_rate[tc];
+ }
+ memcpy(snap->prio_tc_map, qopt->prio_tc_map, sizeof(snap->prio_tc_map));
+
+ return 0;
+}
+
+static int otx2_mqprio_stage_cur(struct otx2_nic *pfvf,
+ const struct tc_mqprio_qopt_offload *mqprio)
+{
+ return otx2_mqprio_snap_copy(pfvf, &pfvf->cur_mq_snap, mqprio);
+}
+
+static void otx2_mqprio_snap_commit(struct otx2_nic *pfvf)
+{
+ otx2_mqprio_snap_free(pfvf, &pfvf->old_mq_snap);
+ pfvf->old_mq_snap = pfvf->cur_mq_snap;
+ pfvf->cur_mq_snap = NULL;
+}
+
+static void otx2_mqprio_clear_replace_state(struct otx2_nic *pfvf)
+{
+ pfvf->mqprio.replace_setup_done = false;
+ pfvf->mqprio.replace_graft_done = false;
+}
+
+static bool otx2_mqprio_mdq_allocated(struct otx2_nic *pfvf)
+{
+ return pfvf->hw.txschq_cnt[NIX_TXSCH_LVL_MDQ] != 0;
+}
+
+static int otx2_mqprio_restart_netdev(struct net_device *netdev, bool rate_limit);
+
+static void otx2_mqprio_apply_snap_netdev(struct net_device *netdev,
+ const struct mq_offload_snap *snap)
+{
+ int tc;
+
+ if (!snap)
+ return;
+
+ netdev_set_num_tc(netdev, snap->num_tc);
+ for (tc = 0; tc < snap->num_tc; tc++)
+ netdev_set_tc_queue(netdev, tc, snap->count[tc],
+ snap->offset[tc]);
+ for (tc = 0; tc < TC_QOPT_BITMASK + 1; tc++)
+ netdev_set_prio_tc_map(netdev, tc, snap->prio_tc_map[tc]);
+}
+
+static void otx2_mqprio_netdev_tc_work(struct work_struct *work)
+{
+ struct otx2_mqprio *mqprio = container_of(work, struct otx2_mqprio,
+ netdev_tc_work);
+ struct otx2_nic *pfvf = container_of(mqprio, struct otx2_nic, mqprio);
+
+ rtnl_lock();
+ if (pfvf->mqprio.rate_limit && pfvf->old_mq_snap)
+ otx2_mqprio_apply_snap_netdev(pfvf->netdev, pfvf->old_mq_snap);
+ rtnl_unlock();
+}
+
+static void otx2_mqprio_defer_netdev_tc_restore(struct otx2_nic *pfvf)
+{
+ schedule_work(&pfvf->mqprio.netdev_tc_work);
+}
+
+static int otx2_mqprio_restore_old(struct otx2_nic *pfvf)
+{
+ struct mq_offload_snap *snap = pfvf->old_mq_snap;
+ struct net_device *netdev = pfvf->netdev;
+ u16 num_txq = pfvf->hw.non_qos_queues;
+ int tc, txq, err;
+
+ if (!snap)
+ return 0;
+
+ err = otx2_mqprio_alloc_cache(pfvf, false);
+ if (err)
+ return err;
+
+ memset(pfvf->mqprio.min_rate, 0, num_txq * sizeof(*pfvf->mqprio.min_rate));
+ memset(pfvf->mqprio.max_rate, 0, num_txq * sizeof(*pfvf->mqprio.max_rate));
+ pfvf->mqprio.flags = snap->flags;
+
+ for (tc = 0; tc < snap->num_tc; tc++) {
+ u64 min_rate = snap->min_rate[tc];
+ u64 max_rate = snap->max_rate[tc];
+
+ for (txq = snap->offset[tc];
+ txq < snap->offset[tc] + snap->count[tc]; txq++) {
+ pfvf->mqprio.min_rate[txq] = min_rate;
+ pfvf->mqprio.max_rate[txq] = max_rate;
+ }
+ }
+
+ otx2_mqprio_apply_snap_netdev(netdev, snap);
+
+ if (otx2_mqprio_mdq_allocated(pfvf)) {
+ err = otx2_nix_tm_clear_queue_shaper(pfvf);
+ if (err)
+ return err;
+ }
+
+ /* Rebuild the TX scheduler via netdev restart when running; otx2_mqprio_up()
+ * alone is insufficient after a failed replace that already bounced the
+ * interface. If open failed, TX schedulers were freed; defer shaper restore
+ * to the next successful ndo_open() via otx2_mqprio_up().
+ */
+ pfvf->mqprio.rate_limit = true;
+
+ if (netif_running(netdev)) {
+ err = otx2_mqprio_restart_netdev(netdev, true);
+ if (err)
+ return err;
+ } else if (pfvf->hw.txschq_cnt[NIX_TXSCH_LVL_SMQ]) {
+ err = otx2_mqprio_up(pfvf);
+ if (err)
+ return err;
+ }
+
+ otx2_mqprio_snap_free(pfvf, &pfvf->cur_mq_snap);
+
+ return 0;
+}
+
+static void otx2_mqprio_snap_destroy(struct otx2_nic *pfvf)
+{
+ otx2_mqprio_snap_free(pfvf, &pfvf->cur_mq_snap);
+ otx2_mqprio_snap_free(pfvf, &pfvf->old_mq_snap);
+}
+
+/* Offloaded mqprio replaced by software mqprio installs netdev TC layout in
+ * mqprio_init() before the old offload instance is destroyed during graft.
+ */
+static bool otx2_mqprio_keep_netdev_tc(struct otx2_nic *pfvf)
+{
+ struct Qdisc *qdisc = rtnl_dereference(pfvf->netdev->qdisc);
+
+ return qdisc && qdisc->ops && !strcmp(qdisc->ops->id, "mqprio");
+}
+
+static void otx2_mqprio_clear_sw(struct otx2_nic *pfvf)
+{
+ struct net_device *netdev = pfvf->netdev;
+
+ pfvf->mqprio.rate_limit = false;
+ otx2_mqprio_clear_replace_state(pfvf);
+ if (!otx2_mqprio_keep_netdev_tc(pfvf))
+ netdev_set_num_tc(netdev, 0);
+ otx2_mqprio_free_cache(pfvf);
+}
+
+/* Tear down mqprio bandwidth offload: clear per-queue shapers,
+ * mqprio_rate_limit, netdev TC mappings, and the cached rates. Called on
+ * explicit mqprio teardown (tc qdisc del) and error cleanup, not on
+ * routine netdev stop/open cycles where the offload stays active.
+ */
+int otx2_mqprio_down(struct otx2_nic *pfvf)
+{
+ int err = 0;
+
+ if (!pfvf->mqprio.rate_limit)
+ return 0;
+
+ if (netif_running(pfvf->netdev) &&
+ otx2_mqprio_mdq_allocated(pfvf))
+ err = otx2_nix_tm_clear_queue_shaper(pfvf);
+
+ if (err) {
+ netdev_warn(pfvf->netdev,
+ "mqprio: failed to clear hardware shapers: %d; keeping offload state\n",
+ err);
+ return err;
+ }
+
+ otx2_mqprio_clear_sw(pfvf);
+
+ return 0;
+}
+
+/* Restore cached mqprio MDQ shapers after ndo_open() reprograms the TX
+ * scheduler. Called from otx2_open() when bandwidth offload stays active
+ * across admin down/up or an mqprio netdev bounce.
+ *
+ * Returns an error if any shaper mailbox operation fails. otx2_open()
+ * fail-closes on that error: it aborts open and leaves the interface down
+ * rather than running with partial or missing bandwidth limits.
+ */
+int otx2_mqprio_up(struct otx2_nic *pfvf)
+{
+ struct net_device *netdev = pfvf->netdev;
+ int txq, err;
+
+ if (!pfvf->mqprio.rate_limit)
+ return 0;
+
+ if (!pfvf->mqprio.min_rate || !pfvf->mqprio.max_rate)
+ return 0;
+
+ for (txq = 0; txq < pfvf->hw.non_qos_queues; txq++) {
+ u64 min_rate = 0, max_rate = 0;
+
+ if (pfvf->mqprio.flags & TC_MQPRIO_F_MIN_RATE)
+ min_rate = pfvf->mqprio.min_rate[txq];
+ if (pfvf->mqprio.flags & TC_MQPRIO_F_MAX_RATE)
+ max_rate = pfvf->mqprio.max_rate[txq];
+
+ if (!min_rate && !max_rate)
+ continue;
+
+ err = otx2_nix_tm_set_queue_shaper(pfvf, txq, min_rate,
+ max_rate);
+ if (err) {
+ netdev_err(netdev,
+ "mqprio: failed to restore shaper for txq %d: %d\n",
+ txq, err);
+ if (otx2_mqprio_mdq_allocated(pfvf) &&
+ otx2_nix_tm_clear_queue_shaper(pfvf))
+ netdev_warn(netdev,
+ "mqprio: failed to clear shapers after partial restore\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/* Restart the netdev to reprogram the TX scheduler hierarchy for mqprio
+ * bandwidth offload. Both mqprio add and delete (when offload was active)
+ * take this path via ndo_stop()/ndo_open() so VF-specific open logic (e.g.
+ * LBK carrier on) runs correctly.
+ *
+ * Intentional behaviour: this full stop/open cycle drops in-flight traffic
+ * (carrier off, IRQ/NAPI teardown, queue drain). The NIX TX scheduler must
+ * be reallocated (e.g. one SMQ per non-QoS queue) and cannot be reprogrammed
+ * live today, so a netdev bounce is required on every mqprio add, replace,
+ * delete, and rollback. Users see a brief connectivity blip; this is not a
+ * bug to "fix" without implementing the live-reprogramming path noted below.
+ * If open fails, the interface is left administratively down without calling
+ * ndo_stop() again on resources already torn down by the open error path.
+ *
+ * Do not call dev_deactivate()/dev_activate() here. On replace,
+ * qdisc_graft() already deactivates qdiscs around offload teardown;
+ * dev_activate() from ndo_setup_tc() would republish qdiscs before graft
+ * completes and race __qdisc_run() on the old root qdisc. After
+ * ndo_open(), carrier and TX queues are restored via otx2_handle_link_event()
+ * when link is up, same as otx2_change_mtu(), not via dev_activate().
+ *
+ * Clear __LINK_STATE_START before ndo_stop() so netif_running() is false
+ * for the duration of the bounce.
+ */
+static int otx2_mqprio_restart_netdev(struct net_device *netdev, bool rate_limit)
+{
+ struct otx2_nic *pfvf = netdev_priv(netdev);
+ const struct net_device_ops *ops = netdev->netdev_ops;
+ bool running = netif_running(netdev);
+ int err;
+
+ /* TODO: Explore live TX scheduler reprogramming to avoid a full
+ * ndo_stop()/ndo_open() bounce on every mqprio change.
+ */
+ netdev_dbg(netdev,
+ "mqprio: restarting interface to reprogram TX scheduler; in-flight traffic will be dropped\n");
+
+ if (running) {
+ clear_bit(__LINK_STATE_START, &netdev->state);
+ smp_mb__after_atomic(); /* Commit netif_running(). */
+ }
+
+ err = ops->ndo_stop(netdev);
+ if (err) {
+ if (running)
+ set_bit(__LINK_STATE_START, &netdev->state);
+ return err;
+ }
+
+ /* Set before ndo_open() so otx2_txsch_alloc() widens SMQ allocation.
+ * On teardown, drop mqprio software state so ndo_open() does not
+ * re-apply bandwidth limits via otx2_mqprio_up() after the kernel
+ * removed the qdisc.
+ */
+ if (rate_limit)
+ pfvf->mqprio.rate_limit = true;
+ else
+ otx2_mqprio_clear_sw(pfvf);
+
+ err = ops->ndo_open(netdev);
+ if (!err && running) {
+ set_bit(__LINK_STATE_START, &netdev->state);
+ } else if (err) {
+ netdev_err(netdev,
+ "Failed to restart device after mqprio change: %d\n",
+ err);
+ /* ndo_open() already freed the TX schedulers on failure while
+ * netif_running() may still be true; drop mqprio software state
+ * only instead of sending shaper clears to freed queues.
+ */
+ otx2_mqprio_clear_sw(pfvf);
+ /* ndo_open() rolls back on failure; mark the interface down so
+ * netif_close() does not invoke ndo_stop() on freed NAPI/queue
+ * state. Caller holds RTNL; dev_close() would deadlock.
+ */
+ otx2_set_flag(pfvf, OTX2_FLAG_INTF_DOWN);
+ /* visible to otx2_stop() on other cpus */
+ smp_wmb();
+ netif_close(netdev);
+ }
+
+ return err;
+}
+
+static int otx2_mqprio_validate_tc_rate(struct net_device *netdev,
+ struct netlink_ext_ack *extack,
+ u64 rate, u32 qcount, int tc,
+ const char *name)
+{
+ if (!rate)
+ return 0;
+
+ if (qcount <= 1)
+ return 0;
+
+ /* TODO: per-TC TL4 shapers or equal per-queue MDQ split for multi-queue TC rates. */
+ netdev_err(netdev,
+ "mqprio: %s rate for tc %d not supported with %u queues\n",
+ name, tc, qcount);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "mqprio: %s rate for tc %d not supported with %u queues",
+ name, tc, qcount);
+ return -EOPNOTSUPP;
+}
+
+static int otx2_mqprio_validate_txqs(struct net_device *netdev,
+ struct netlink_ext_ack *extack,
+ struct tc_mqprio_qopt *qopt)
+{
+ struct otx2_nic *pfvf = netdev_priv(netdev);
+ u16 num_txq = pfvf->hw.non_qos_queues;
+ int tc, txq;
+
+ if (qopt->num_tc > num_txq) {
+ netdev_err(netdev, "Number of TCs (%u) exceeds hw queues %u\n",
+ qopt->num_tc, num_txq);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Number of TCs (%u) exceeds hw queues %u",
+ qopt->num_tc, num_txq);
+ return -EINVAL;
+ }
+
+ if (num_txq > MAX_TXSCHQ_PER_FUNC) {
+ netdev_err(netdev,
+ "Number of queues (%u) exceeds max scheduler queues %u\n",
+ num_txq, MAX_TXSCHQ_PER_FUNC);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Number of queues (%u) exceeds max scheduler queues %u",
+ num_txq, MAX_TXSCHQ_PER_FUNC);
+ return -EINVAL;
+ }
+
+ for (tc = 0; tc < qopt->num_tc; tc++) {
+ u32 qcount = qopt->count[tc];
+
+ for (txq = qopt->offset[tc];
+ txq < qopt->offset[tc] + qcount; txq++) {
+ if (txq >= num_txq) {
+ netdev_err(netdev,
+ "mqprio: txq %d exceeds offload queue count %u\n",
+ txq, num_txq);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "mqprio: txq %d exceeds offload queue count %u",
+ txq, num_txq);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static bool otx2_mqprio_rate_valid(struct otx2_nic *pfvf, u64 rate_bytes_ps)
+{
+ u64 mbps;
+
+ if (!rate_bytes_ps)
+ return true;
+
+ if (rate_bytes_ps < OTX2_MQPRIO_MIN_RATE_BYTES_PS)
+ return false;
+
+ if (rate_bytes_ps > otx2_mqprio_max_rate_bytes_ps())
+ return false;
+
+ if (rate_bytes_ps > div_u64(U64_MAX, 8))
+ return false;
+
+ mbps = otx2_convert_rate(rate_bytes_ps);
+ return ilog2(mbps / 2) <= MAX_RATE_EXPONENT;
+}
+
+static int otx2_teardown_tc_mqprio(struct otx2_nic *pfvf,
+ struct tc_mqprio_qopt_offload *mqprio)
+{
+ struct tc_mqprio_qopt *qopt = &mqprio->qopt;
+ bool had_mqprio = pfvf->mqprio.rate_limit;
+ struct net_device *netdev = pfvf->netdev;
+ bool if_up = netif_running(netdev);
+ int err;
+
+ qopt->hw = 0;
+
+ /* tc qdisc replace runs setup on the new mqprio before destroying the
+ * old one. replace_setup_done and TC_ROOT_GRAFT distinguish stale
+ * old-instance teardown from graft failure after setup.
+ */
+ if (pfvf->mqprio.replace_setup_done && pfvf->cur_mq_snap) {
+ err = 0;
+ if (pfvf->mqprio.replace_graft_done)
+ otx2_mqprio_snap_commit(pfvf);
+ else
+ err = otx2_mqprio_restore_old(pfvf);
+ otx2_mqprio_clear_replace_state(pfvf);
+ return err;
+ }
+
+ /* Skip the netdev restart when mqprio offload was not active. */
+ if (!had_mqprio)
+ return 0;
+
+ if (if_up) {
+ err = otx2_mqprio_down(pfvf);
+ if (err)
+ return err;
+
+ return otx2_mqprio_restart_netdev(netdev, false);
+ }
+
+ /* ndo_stop() already freed the TX scheduler TL nodes; drop software
+ * state only.
+ */
+ otx2_mqprio_clear_sw(pfvf);
+ return 0;
+}
+
+static int otx2_setup_tc_mqprio(struct net_device *netdev,
+ struct tc_mqprio_qopt_offload *mqprio)
+{
+ struct netlink_ext_ack *extack = mqprio->extack;
+ struct otx2_nic *pfvf = netdev_priv(netdev);
+ struct tc_mqprio_qopt *qopt = &mqprio->qopt;
+ bool replacing = pfvf->mqprio.rate_limit;
+ bool if_up = netif_running(netdev);
+ int tc, txq, err, i;
+
+ if (!qopt->hw)
+ return otx2_teardown_tc_mqprio(pfvf, mqprio);
+
+ if (!if_up) {
+ netdev_err(netdev, "mqprio: setup requires interface UP\n");
+ NL_SET_ERR_MSG_MOD(extack, "mqprio: setup requires interface UP");
+ err = -EOPNOTSUPP;
+ goto fail_validate;
+ }
+
+ if (!replacing && otx2_mqprio_keep_netdev_tc(pfvf)) {
+ netdev_err(netdev,
+ "mqprio: delete existing mqprio before re-enabling hw/sw offload\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "mqprio: delete existing mqprio before re-enabling hw/sw offload\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE) {
+ netdev_err(netdev, "Unsupported mqprio shaper %#x\n", mqprio->shaper);
+ NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported mqprio shaper %#x",
+ mqprio->shaper);
+ err = -EOPNOTSUPP;
+ goto fail_validate;
+ }
+
+ if (!test_bit(QOS_CIR_PIR_SUPPORT, &pfvf->hw.cap_flag)) {
+ netdev_err(netdev,
+ "mqprio: bandwidth offload requires CIR+PIR support\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "mqprio: bandwidth offload requires CIR+PIR support");
+ err = -EOPNOTSUPP;
+ goto fail_validate;
+ }
+
+ if (is_otx2_sdp_rep(pfvf->pdev)) {
+ netdev_err(netdev, "mqprio: bandwidth offload not supported on SDP rep\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "mqprio: bandwidth offload not supported on SDP rep");
+ err = -EOPNOTSUPP;
+ goto fail_validate;
+ }
+
+ if (pfvf->pfc_en) {
+ netdev_err(netdev,
+ "mqprio: cannot enable offload while PFC is enabled\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "mqprio: cannot enable offload while PFC is enabled");
+ err = -EOPNOTSUPP;
+ goto fail_validate;
+ }
+
+ if (pfvf->xdp_prog) {
+ netdev_err(netdev,
+ "mqprio: cannot enable offload while XDP is active\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "mqprio: cannot enable offload while XDP is active");
+ err = -EOPNOTSUPP;
+ goto fail_validate;
+ }
+
+ if (!list_empty(&pfvf->qos.qos_tree)) {
+ netdev_err(netdev,
+ "mqprio: cannot enable offload while HTB is active\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "mqprio: cannot enable offload while HTB is active");
+ err = -EOPNOTSUPP;
+ goto fail_validate;
+ }
+
+ for (tc = 0; tc < qopt->num_tc; tc++) {
+ u64 min_rate = 0, max_rate = 0;
+ u32 qcount = qopt->count[tc];
+
+ if (mqprio->flags & TC_MQPRIO_F_MIN_RATE)
+ min_rate = mqprio->min_rate[tc];
+ if (mqprio->flags & TC_MQPRIO_F_MAX_RATE)
+ max_rate = mqprio->max_rate[tc];
+
+ if (min_rate && max_rate && min_rate > max_rate) {
+ netdev_err(netdev,
+ "min_rate %llu exceeds max_rate %llu for tc %d\n",
+ min_rate, max_rate, tc);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "min_rate %llu exceeds max_rate %llu for tc %d",
+ min_rate, max_rate, tc);
+ err = -EINVAL;
+ goto fail_validate;
+ }
+
+ if (mqprio->flags & TC_MQPRIO_F_MIN_RATE) {
+ err = otx2_mqprio_validate_tc_rate(netdev, extack, min_rate,
+ qcount, tc, "min");
+ if (err)
+ goto fail_validate;
+ }
+
+ if (mqprio->flags & TC_MQPRIO_F_MAX_RATE) {
+ err = otx2_mqprio_validate_tc_rate(netdev, extack, max_rate,
+ qcount, tc, "max");
+ if (err)
+ goto fail_validate;
+ }
+
+ if (mqprio->flags & TC_MQPRIO_F_MIN_RATE &&
+ !otx2_mqprio_rate_valid(pfvf, min_rate)) {
+ netdev_err(netdev,
+ "mqprio: min_rate %llu for tc %d is outside hardware limits\n",
+ min_rate, tc);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "mqprio: min_rate %llu for tc %d is outside hardware limits",
+ min_rate, tc);
+ err = -EINVAL;
+ goto fail_validate;
+ }
+
+ if (mqprio->flags & TC_MQPRIO_F_MAX_RATE &&
+ !otx2_mqprio_rate_valid(pfvf, max_rate)) {
+ netdev_err(netdev,
+ "mqprio: max_rate %llu for tc %d is outside hardware limits\n",
+ max_rate, tc);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "mqprio: max_rate %llu for tc %d is outside hardware limits",
+ max_rate, tc);
+ err = -EINVAL;
+ goto fail_validate;
+ }
+ }
+
+ err = otx2_mqprio_validate_txqs(netdev, extack, qopt);
+ if (err)
+ goto fail_validate;
+
+ err = otx2_mqprio_stage_cur(pfvf, mqprio);
+ if (err)
+ goto fail_validate;
+
+ err = otx2_mqprio_restart_netdev(pfvf->netdev, true);
+ if (err)
+ goto cleanup;
+
+ err = otx2_mqprio_alloc_cache(pfvf, replacing);
+ if (err)
+ goto cleanup;
+
+ /* otx2_mqprio_up() may have restored the previous configuration during
+ * the restart above. Clear every MDQ shaper before applying the new
+ * mapping so queues dropped from the TC layout do not keep stale
+ * limits in hardware.
+ */
+ if (otx2_mqprio_mdq_allocated(pfvf)) {
+ err = otx2_nix_tm_clear_queue_shaper(pfvf);
+ if (err)
+ goto cleanup;
+ }
+
+ pfvf->mqprio.flags = mqprio->flags;
+
+ for (tc = 0; tc < qopt->num_tc; tc++) {
+ u64 min_rate = 0, max_rate = 0;
+ u32 qcount = qopt->count[tc];
+
+ /* Rates omitted from tc mqprio are passed as zero and both MDQ
+ * shaper registers are programmed; see
+ * otx2_nix_tm_set_queue_shaper().
+ * TODO: multi-queue TC rates need per-queue split; see
+ * otx2_mqprio_validate_tc_rate().
+ */
+ if (mqprio->flags & TC_MQPRIO_F_MIN_RATE)
+ min_rate = mqprio->min_rate[tc];
+ if (mqprio->flags & TC_MQPRIO_F_MAX_RATE)
+ max_rate = mqprio->max_rate[tc];
+
+ for (txq = qopt->offset[tc];
+ txq < qopt->offset[tc] + qcount; txq++) {
+ netdev_dbg(netdev,
+ "mqprio: tc %d txq %d min_rate %llu max_rate %llu\n",
+ tc, txq, min_rate, max_rate);
+
+ pfvf->mqprio.min_rate[txq] = min_rate;
+ pfvf->mqprio.max_rate[txq] = max_rate;
+
+ err = otx2_nix_tm_set_queue_shaper(pfvf, txq,
+ min_rate, max_rate);
+ if (err)
+ goto cleanup;
+ }
+ }
+
+ netdev_set_num_tc(netdev, pfvf->cur_mq_snap->num_tc);
+ for (i = 0; i < pfvf->cur_mq_snap->num_tc; i++)
+ netdev_set_tc_queue(netdev, i, pfvf->cur_mq_snap->count[i],
+ qopt->offset[i]);
+
+ qopt->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+
+ if (replacing) {
+ pfvf->mqprio.replace_setup_done = true;
+ pfvf->mqprio.replace_graft_done = false;
+ } else {
+ otx2_mqprio_snap_commit(pfvf);
+ }
+
+ return 0;
+
+fail_validate:
+ /* Failed replace destroys the new qdisc with hw_offload unset, so
+ * mqprio_destroy() clears netdev TC after we return. Re-apply the
+ * prior layout when validation fails before any hardware change.
+ */
+ if (replacing)
+ otx2_mqprio_defer_netdev_tc_restore(pfvf);
+ return err;
+
+cleanup:
+ qopt->hw = 0;
+ if (replacing) {
+ int restore_err = otx2_mqprio_restore_old(pfvf);
+
+ otx2_mqprio_clear_replace_state(pfvf);
+ if (restore_err) {
+ netdev_err(netdev,
+ "mqprio: replace failed and prior configuration rollback failed: %d\n",
+ restore_err);
+ if (extack)
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "mqprio: replace failed and prior configuration rollback failed: %d",
+ restore_err);
+ } else {
+ netdev_err(netdev,
+ "mqprio: replace failed; hardware limits restored, netdev TC layout restore deferred\n");
+ if (extack)
+ NL_SET_ERR_MSG_MOD(extack,
+ "mqprio: replace failed; hardware limits restored, netdev TC layout restore deferred");
+ /* Failed replace destroys the new qdisc with hw_offload
+ * unset, so mqprio_destroy() clears netdev TC after we
+ * return. Re-apply the restored layout once that unwind
+ * finishes.
+ */
+ otx2_mqprio_defer_netdev_tc_restore(pfvf);
+ }
+ return err ? err : -EIO;
+ }
+ otx2_mqprio_snap_free(pfvf, &pfvf->cur_mq_snap);
+ otx2_teardown_tc_mqprio(pfvf, mqprio);
+ return err;
+}
+
+static int otx2_setup_tc_root(struct otx2_nic *pfvf,
+ struct tc_root_qopt_offload *root)
+{
+ switch (root->command) {
+ case TC_ROOT_GRAFT:
+ if (pfvf->mqprio.replace_setup_done)
+ pfvf->mqprio.replace_graft_done = true;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int otx2_setup_tc_query_caps(void *type_data)
+{
+ struct tc_query_caps_base *base = type_data;
+ struct tc_mqprio_caps *caps;
+
+ if (base->type != TC_SETUP_QDISC_MQPRIO)
+ return -EOPNOTSUPP;
+
+ caps = base->caps;
+ caps->validate_queue_counts = true;
+
+ return 0;
+}
+
int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
switch (type) {
+ case TC_QUERY_CAPS:
+ return otx2_setup_tc_query_caps(type_data);
case TC_SETUP_BLOCK:
return otx2_setup_tc_block(netdev, type_data);
case TC_SETUP_QDISC_HTB:
return otx2_setup_tc_htb(netdev, type_data);
+ case TC_SETUP_QDISC_MQPRIO:
+ return otx2_setup_tc_mqprio(netdev, type_data);
+ case TC_SETUP_ROOT_QDISC:
+ return otx2_setup_tc_root(netdev_priv(netdev), type_data);
default:
return -EOPNOTSUPP;
}
@@ -1625,13 +2457,17 @@ int otx2_init_tc(struct otx2_nic *nic)
return -EINVAL;
}
+ INIT_WORK(&nic->mqprio.netdev_tc_work, otx2_mqprio_netdev_tc_work);
+
return 0;
}
EXPORT_SYMBOL(otx2_init_tc);
void otx2_shutdown_tc(struct otx2_nic *nic)
{
+ cancel_work_sync(&nic->mqprio.netdev_tc_work);
otx2_destroy_tc_flow_list(nic);
+ otx2_mqprio_snap_destroy(nic);
}
EXPORT_SYMBOL(otx2_shutdown_tc);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
index 8d2d607bc92f9..f65ba44db60b6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
@@ -171,7 +171,7 @@ static void otx2_set_rxtstamp(struct otx2_nic *pfvf,
u64 timestamp, tsns;
int err;
- if (!(pfvf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED))
+ if (!otx2_test_flag(pfvf, OTX2_FLAG_RX_TSTAMP_ENABLED))
return;
timestamp = pfvf->ptp->convert_rx_ptp_tstmp(*(u64 *)data);
@@ -374,13 +374,13 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf,
}
otx2_set_rxhash(pfvf, cqe, skb);
- if (!(pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED)) {
+ if (!otx2_test_flag(pfvf, OTX2_FLAG_REP_MODE_ENABLED)) {
skb_record_rx_queue(skb, cq->cq_idx);
if (pfvf->netdev->features & NETIF_F_RXCSUM)
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
- if (pfvf->flags & OTX2_FLAG_TC_MARK_ENABLED)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_TC_MARK_ENABLED))
skb->mark = parse->match_id;
skb_mark_for_recycle(skb);
@@ -513,7 +513,7 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf,
((u64)cq->cq_idx << 32) | processed_cqe);
#if IS_ENABLED(CONFIG_RVU_ESWITCH)
- if (pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_REP_MODE_ENABLED))
ndev = pfvf->reps[qidx]->netdev;
else
#endif
@@ -526,7 +526,7 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf,
if (qidx >= pfvf->hw.tx_queues)
qidx -= pfvf->hw.xdp_queues;
- if (pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_REP_MODE_ENABLED))
qidx = 0;
txq = netdev_get_tx_queue(ndev, qidx);
netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);
@@ -599,11 +599,11 @@ int otx2_napi_handler(struct napi_struct *napi, int budget)
if (workdone < budget && napi_complete_done(napi, workdone)) {
/* If interface is going down, don't re-enable IRQ */
- if (pfvf->flags & OTX2_FLAG_INTF_DOWN)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_INTF_DOWN))
return workdone;
/* Adjust irq coalese using net_dim */
- if (pfvf->flags & OTX2_FLAG_ADPTV_INT_COAL_ENABLED)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_ADPTV_INT_COAL_ENABLED))
otx2_adjust_adaptive_coalese(pfvf, cq_poll);
if (likely(cq))
@@ -1137,7 +1137,7 @@ static void otx2_set_txtstamp(struct otx2_nic *pfvf, struct sk_buff *skb,
if (unlikely(!skb_shinfo(skb)->gso_size &&
(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) {
- if (unlikely(pfvf->flags & OTX2_FLAG_PTP_ONESTEP_SYNC &&
+ if (unlikely(otx2_test_flag(pfvf, OTX2_FLAG_PTP_ONESTEP_SYNC) &&
otx2_ptp_is_sync(skb, &ptp_offset, &udp_csum_crt))) {
origin_tstamp = (struct ptpv2_tstamp *)
((u8 *)skb->data + ptp_offset +
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
index f7765e19d78a9..2837e19c780f6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
@@ -610,7 +610,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
vf->dev = dev;
vf->iommu_domain = iommu_get_domain_for_dev(dev);
- vf->flags |= OTX2_FLAG_INTF_DOWN;
+ otx2_set_flag(vf, OTX2_FLAG_INTF_DOWN);
hw = &vf->hw;
hw->pdev = vf->pdev;
hw->rx_queues = qcount;
@@ -703,6 +703,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
netdev->hw_features |= NETIF_F_NTUPLE;
netdev->hw_features |= NETIF_F_RXALL;
netdev->hw_features |= NETIF_F_HW_TC;
+ netdev->features |= NETIF_F_HW_TC;
netif_set_tso_max_segs(netdev, OTX2_MAX_GSO_SEGS);
netdev->watchdog_timeo = OTX2_TX_TIMEOUT;
@@ -740,25 +741,25 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto err_ipsec_clean;
+ err = otx2vf_mcam_flow_init(vf);
+ if (err)
+ goto err_wq_destroy;
+
+ err = otx2_init_tc(vf);
+ if (err)
+ goto err_wq_destroy;
+
err = register_netdev(netdev);
if (err) {
dev_err(dev, "Failed to register netdevice\n");
- goto err_wq_destroy;
+ goto err_shutdown_tc;
}
otx2vf_set_ethtool_ops(netdev);
- err = otx2vf_mcam_flow_init(vf);
- if (err)
- goto err_unreg_netdev;
-
- err = otx2_init_tc(vf);
- if (err)
- goto err_unreg_netdev;
-
err = otx2_register_dl(vf);
if (err)
- goto err_shutdown_tc;
+ goto err_unreg_netdev;
vf->af_xdp_zc_qidx = bitmap_zalloc(qcount, GFP_KERNEL);
if (!vf->af_xdp_zc_qidx) {
@@ -784,10 +785,11 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
#endif
err_unreg_devlink:
otx2_unregister_dl(vf);
-err_shutdown_tc:
- otx2_shutdown_tc(vf);
err_unreg_netdev:
+ otx2_shutdown_tc(vf);
unregister_netdev(netdev);
+err_shutdown_tc:
+ otx2_shutdown_tc(vf);
err_wq_destroy:
cancel_work_sync(&vf->reset_task);
cancel_work_sync(&vf->rx_mode_work);
@@ -824,10 +826,10 @@ static void otx2vf_remove(struct pci_dev *pdev)
vf = netdev_priv(netdev);
/* Disable 802.3x pause frames */
- if (vf->flags & OTX2_FLAG_RX_PAUSE_ENABLED ||
- (vf->flags & OTX2_FLAG_TX_PAUSE_ENABLED)) {
- vf->flags &= ~OTX2_FLAG_RX_PAUSE_ENABLED;
- vf->flags &= ~OTX2_FLAG_TX_PAUSE_ENABLED;
+ if (otx2_test_flag(vf, OTX2_FLAG_RX_PAUSE_ENABLED) ||
+ otx2_test_flag(vf, OTX2_FLAG_TX_PAUSE_ENABLED)) {
+ otx2_clear_flag(vf, OTX2_FLAG_RX_PAUSE_ENABLED);
+ otx2_clear_flag(vf, OTX2_FLAG_TX_PAUSE_ENABLED);
otx2_config_pause_frm(vf);
}
@@ -840,6 +842,7 @@ static void otx2vf_remove(struct pci_dev *pdev)
#endif
otx2_unregister_dl(vf);
+ otx2_shutdown_tc(vf);
unregister_netdev(netdev);
if (vf->otx2_wq) {
cancel_work_sync(&vf->reset_task);
@@ -849,7 +852,6 @@ static void otx2vf_remove(struct pci_dev *pdev)
cn10k_ipsec_clean(vf);
otx2_ptp_destroy(vf);
otx2_mcam_flow_del(vf);
- otx2_shutdown_tc(vf);
otx2_shutdown_qos(vf);
otx2_detach_resources(&vf->mbox);
otx2vf_disable_mbox_intr(vf);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_xsk.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_xsk.c
index 0e8a6a6486c4a..7808588a0234a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_xsk.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_xsk.c
@@ -96,7 +96,7 @@ static void otx2_clean_up_rq(struct otx2_nic *pfvf, int qidx)
u64 iova;
/* If the DOWN flag is set SQs are already freed */
- if (pfvf->flags & OTX2_FLAG_INTF_DOWN)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_INTF_DOWN))
return;
cq = &qset->cq[qidx];
@@ -172,7 +172,7 @@ int otx2_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
struct otx2_cq_poll *cq_poll = NULL;
struct otx2_qset *qset = &pf->qset;
- if (pf->flags & OTX2_FLAG_INTF_DOWN)
+ if (otx2_test_flag(pf, OTX2_FLAG_INTF_DOWN))
return -ENETDOWN;
if (queue_id >= pf->hw.rx_queues || queue_id >= pf->hw.tx_queues)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
index f160b1618efa2..9ef55a6db50b7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
@@ -118,6 +118,9 @@ static void otx2_config_sched_shaping(struct otx2_nic *pfvf,
/* configure PIR */
maxrate = (node->rate > node->ceil) ? node->rate : node->ceil;
+ /* 65536 is the kernel-side default burst when HTB does not supply an
+ * explicit value, not the NIX hardware maximum (CN10K_MAX_BURST_SIZE).
+ */
cfg->regval[*num_regs] =
otx2_get_txschq_rate_regval(pfvf, maxrate, 65536);
(*num_regs)++;
@@ -1088,6 +1091,14 @@ static int otx2_qos_root_add(struct otx2_nic *pfvf, u16 htb_maj_id, u16 htb_defc
"TC_HTB_CREATE: handle=0x%x defcls=0x%x\n",
htb_maj_id, htb_defcls);
+ if (pfvf->mqprio.rate_limit) {
+ netdev_err(pfvf->netdev,
+ "HTB: cannot enable while mqprio bandwidth offload is active\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "HTB: cannot enable while mqprio bandwidth offload is active");
+ return -EOPNOTSUPP;
+ }
+
root = otx2_qos_alloc_root(pfvf);
if (IS_ERR(root)) {
err = PTR_ERR(root);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c
index 2872adabc8305..5f09e29601441 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c
@@ -238,7 +238,7 @@ int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx)
struct otx2_hw *hw = &pfvf->hw;
int pool_id, sq_idx, err;
- if (pfvf->flags & OTX2_FLAG_INTF_DOWN)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_INTF_DOWN))
return -EPERM;
sq_idx = hw->non_qos_queues + qidx;
@@ -288,7 +288,7 @@ void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx)
sq_idx = hw->non_qos_queues + qidx;
/* If the DOWN flag is set SQs are already freed */
- if (pfvf->flags & OTX2_FLAG_INTF_DOWN)
+ if (otx2_test_flag(pfvf, OTX2_FLAG_INTF_DOWN))
return;
sq = &pfvf->qset.sq[sq_idx];
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
index 0f5d5642d3f7a..7df82c22cc12b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
@@ -93,9 +93,9 @@ static int rvu_rep_mcam_flow_init(struct rep_dev *rep)
rep->flow_cfg->max_flows = allocated;
if (allocated) {
- rep->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
- rep->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
- rep->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
+ set_bit(OTX2_FLAG_MCAM_ENTRIES_ALLOC, &rep->flags);
+ set_bit(OTX2_FLAG_NTUPLE_SUPPORT, &rep->flags);
+ set_bit(OTX2_FLAG_TC_FLOWER_SUPPORT, &rep->flags);
}
INIT_LIST_HEAD(&rep->flow_cfg->flow_list);
@@ -109,14 +109,14 @@ static int rvu_rep_setup_tc_cb(enum tc_setup_type type,
struct rep_dev *rep = cb_priv;
struct otx2_nic *priv = rep->mdev;
- if (!(rep->flags & RVU_REP_VF_INITIALIZED))
+ if (!test_bit(OTX2_FLAG_REP_VF_INITIALIZED, &rep->flags))
return -EINVAL;
- if (!(rep->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
+ if (!test_bit(OTX2_FLAG_TC_FLOWER_SUPPORT, &rep->flags))
rvu_rep_mcam_flow_init(rep);
priv->netdev = rep->netdev;
- priv->flags = rep->flags;
+ otx2_sync_flags_from_rep(priv, &rep->flags);
priv->pcifunc = rep->pcifunc;
priv->flow_cfg = rep->flow_cfg;
@@ -303,9 +303,9 @@ static void rvu_rep_state_evt_handler(struct otx2_nic *priv,
rep_id = rvu_rep_get_repid(priv, info->pcifunc);
rep = priv->reps[rep_id];
if (info->evt_data.vf_state)
- rep->flags |= RVU_REP_VF_INITIALIZED;
+ set_bit(OTX2_FLAG_REP_VF_INITIALIZED, &rep->flags);
else
- rep->flags &= ~RVU_REP_VF_INITIALIZED;
+ clear_bit(OTX2_FLAG_REP_VF_INITIALIZED, &rep->flags);
}
int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info)
@@ -382,7 +382,7 @@ static void rvu_rep_get_stats64(struct net_device *dev,
{
struct rep_dev *rep = netdev_priv(dev);
- if (!(rep->flags & RVU_REP_VF_INITIALIZED))
+ if (!test_bit(OTX2_FLAG_REP_VF_INITIALIZED, &rep->flags))
return;
stats->rx_packets = rep->stats.rx_frames;
@@ -453,7 +453,7 @@ static int rvu_rep_open(struct net_device *dev)
struct otx2_nic *priv = rep->mdev;
struct rep_event evt = {0};
- if (!(rep->flags & RVU_REP_VF_INITIALIZED))
+ if (!test_bit(OTX2_FLAG_REP_VF_INITIALIZED, &rep->flags))
return 0;
netif_carrier_on(dev);
@@ -472,7 +472,7 @@ static int rvu_rep_stop(struct net_device *dev)
struct otx2_nic *priv = rep->mdev;
struct rep_event evt = {0};
- if (!(rep->flags & RVU_REP_VF_INITIALIZED))
+ if (!test_bit(OTX2_FLAG_REP_VF_INITIALIZED, &rep->flags))
return 0;
netif_carrier_off(dev);
@@ -547,7 +547,7 @@ static int rvu_rep_napi_init(struct otx2_nic *priv,
otx2_write64(priv, NIX_LF_CINTX_INT(qidx), BIT_ULL(0));
otx2_write64(priv, NIX_LF_CINTX_ENA_W1S(qidx), BIT_ULL(0));
}
- priv->flags &= ~OTX2_FLAG_INTF_DOWN;
+ otx2_clear_flag(priv, OTX2_FLAG_INTF_DOWN);
return 0;
err_free_cints:
@@ -632,7 +632,7 @@ void rvu_rep_destroy(struct otx2_nic *priv)
int rep_id;
rvu_eswitch_config(priv, false);
- priv->flags |= OTX2_FLAG_INTF_DOWN;
+ otx2_set_flag(priv, OTX2_FLAG_INTF_DOWN);
rvu_rep_free_cq_rsrc(priv);
for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++) {
rep = priv->reps[rep_id];
@@ -801,8 +801,8 @@ static int rvu_rep_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, priv);
priv->pdev = pdev;
priv->dev = dev;
- priv->flags |= OTX2_FLAG_INTF_DOWN;
- priv->flags |= OTX2_FLAG_REP_MODE_ENABLED;
+ otx2_set_flag(priv, OTX2_FLAG_INTF_DOWN);
+ otx2_set_flag(priv, OTX2_FLAG_REP_MODE_ENABLED);
hw = &priv->hw;
hw->pdev = pdev;
@@ -845,7 +845,7 @@ static void rvu_rep_remove(struct pci_dev *pdev)
struct otx2_nic *priv = pci_get_drvdata(pdev);
otx2_unregister_dl(priv);
- if (!(priv->flags & OTX2_FLAG_INTF_DOWN))
+ if (!otx2_test_flag(priv, OTX2_FLAG_INTF_DOWN))
rvu_rep_destroy(priv);
otx2_detach_resources(&priv->mbox);
if (priv->hw.lmt_info)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
index 5bc9e2c7d800b..45707c434d89f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
@@ -37,8 +37,7 @@ struct rep_dev {
struct delayed_work stats_wrk;
struct devlink_port dl_port;
struct otx2_flow_config *flow_cfg;
-#define RVU_REP_VF_INITIALIZED BIT_ULL(0)
- u64 flags;
+ unsigned long flags;
u16 rep_id;
u16 pcifunc;
u8 mac[ETH_ALEN];
|
| 3/2 | 2026/09/25 08:57 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 39246 output: 41 thoughts: 885 Thoughts: **Initial Assessment of Git Commit Patch** Okay, so the user wants me to evaluate this git commit patch applied to the Linux kernel. First things first, I need to understand the scope. I'm seeing a substantial touch on files within the `drivers/net/ethernet/marvell/octeontx2/nic/` directory. That's a lot of changes, potentially impacting the Marvell OcteonTX2 NIC driver. Alright, before diving too deep into the code, I need to pause. Given the specific context, I know to apply a "reachability" gate. I need to make sure this code is, in principle, fuzzer-accessible. Specifically, the instructions emphasize that if the code is structurally unreachable within standard virtualized environments, then it shouldn't be fuzzed. My mind immediately goes to Section 2 of the instructions. The text clearly states that vendor-specific PCIe switches, SmartNICs, or GPU drivers requiring physical hardware are structurally unreachable for fuzzing. I need to figure out where Marvell OcteonTX2 fits into this picture. I know OcteonTX2 encompasses various SoCs and SmartNICs. Devices like CN93XX, CN96XX, CN98XX, and CN10K are often mentioned. Based on my existing knowledge, OcteonTX2 is a Cavium/Marvell SoC or a SmartNIC/PCIe device. So, the question becomes: can QEMU emulate the OcteonTX2 NIC in a standard way? No, I don't believe so. Standard QEMU environments typically employ virtio-net, e1000, e1000e, rtl8139, igb, etc. devices for network emulation. The Marvell OcteonTX2, as I recall, is physical silicon. It's a Network Interface Controller, RVU PF/VF. Okay, so given my current understanding, I'm leaning toward the conclusion that this code might be structurally unreachable for fuzzing purposes. However, I need to confirm this explicitly using `read-file` or `grepper` and by checking the driver details and `Kconfig`. I need to solidify this before proceeding. |
| 4/2 | 2026/09/25 08:57 | tool | grepper |
0mArgs:{
"Expression": "config OCTEONTX2",
"PathPrefix": "drivers/net/ethernet/marvell/octeontx2"
}Results: {
"Output": "drivers/net/ethernet/marvell/octeontx2/Kconfig-5-\ndrivers/net/ethernet/marvell/octeontx2/Kconfig:6:config OCTEONTX2_MBOX\ndrivers/net/ethernet/marvell/octeontx2/Kconfig-7-\ttristate\ndrivers/net/ethernet/marvell/octeontx2/Kconfig-8-\ndrivers/net/ethernet/marvell/octeontx2/Kconfig:9:config OCTEONTX2_AF\ndrivers/net/ethernet/marvell/octeontx2/Kconfig-10-\ttristate \"Marvell OcteonTX2 RVU Admin Function driver\"\n--\ndrivers/net/ethernet/marvell/octeontx2/Kconfig=22=config NDC_DIS_DYNAMIC_CACHING\n--\ndrivers/net/ethernet/marvell/octeontx2/Kconfig-30-\ndrivers/net/ethernet/marvell/octeontx2/Kconfig:31:config OCTEONTX2_PF\ndrivers/net/ethernet/marvell/octeontx2/Kconfig-32-\ttristate \"Marvell OcteonTX2 NIC Physical Function driver\"\n--\ndrivers/net/ethernet/marvell/octeontx2/Kconfig-44-\ndrivers/net/ethernet/marvell/octeontx2/Kconfig:45:config OCTEONTX2_VF\ndrivers/net/ethernet/marvell/octeontx2/Kconfig-46-\ttristate \"Marvell OcteonTX2 NIC Virtual Function driver\"\n"
} |
| 5/2 | 2026/09/25 08:57 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 41056 output: 44 thoughts: 24 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Diving into the Octeon TX2 Ethernet Driver Kconfig** Right, let's take a look at the `drivers/net/ethernet/marvell/octeontx2/Kconfig` file. I immediately recognize this as the configuration file for the Octeon TX2 ethernet driver – essential for setting up the build options and dependencies for these high-performance network interfaces. I'll need to scrutinize this to understand the possible configurations, dependencies on other drivers, and any specific hardware features that are enabled or disabled through these Kconfig options. I'll be particularly interested in: * **Any `CONFIG_` options related to specific NIC features**: Things like hardware offloads, flow control, QoS capabilities, VLAN support, RSS/RPS configuration, and any power management related configurations. * **Dependencies on other components**: I'll see what other subsystems this driver relies on, which will determine what other configurations need to be set in the overall kernel build. * **Conditional compilation**: I want to identify what parts of the driver are enabled based on specific hardware revisions, SoC variants, or other environmental factors, particularly if the options are tied to any specific features that are enabled by other Kconfig options. * **Defaults**: I will use these to understand the default behavior of the driver, and ensure they are aligned with the intended system setup. * **Help text**: These will provide valuable insights into what the options do, and what the user may be expected to choose. This file is the blueprint for how the Octeon TX2 ethernet driver interacts with the kernel build system and, ultimately, how it's integrated into the kernel image. Understanding this Kconfig file is critical for customizing and optimizing the network performance on any system using an Octeon TX2 based network device. |
| 6/2 | 2026/09/25 08:57 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/marvell/octeontx2/Kconfig",
"FirstLine": 1,
"LineCount": 80
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\t#\n 3:\t# Marvell RVU Network drivers configuration\n 4:\t#\n 5:\t\n 6:\tconfig OCTEONTX2_MBOX\n 7:\t\ttristate\n 8:\t\n 9:\tconfig OCTEONTX2_AF\n 10:\t\ttristate \"Marvell OcteonTX2 RVU Admin Function driver\"\n 11:\t\tselect OCTEONTX2_MBOX\n 12:\t\tselect NET_DEVLINK\n 13:\t\tdepends on (64BIT \u0026\u0026 COMPILE_TEST) || ARM64\n 14:\t\tdepends on PCI\n 15:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n 16:\t\thelp\n 17:\t\t This driver supports Marvell's OcteonTX2 Resource Virtualization\n 18:\t\t Unit's admin function manager which manages all RVU HW resources\n 19:\t\t and provides a medium to other PF/VFs to configure HW. Should be\n 20:\t\t enabled for other RVU device drivers to work.\n 21:\t\n 22:\tconfig NDC_DIS_DYNAMIC_CACHING\n 23:\t\tbool \"Disable caching of dynamic entries in NDC\"\n 24:\t\tdepends on OCTEONTX2_AF\n 25:\t\tdefault n\n 26:\t\thelp\n 27:\t\t This config option disables caching of dynamic entries such as NIX SQEs\n 28:\t\t , NPA stack pages etc in NDC. Also locks down NIX SQ/CQ/RQ/RSS and\n 29:\t\t NPA Aura/Pool contexts.\n 30:\t\n 31:\tconfig OCTEONTX2_PF\n 32:\t\ttristate \"Marvell OcteonTX2 NIC Physical Function driver\"\n 33:\t\tselect OCTEONTX2_MBOX\n 34:\t\tselect NET_DEVLINK\n 35:\t\tselect PAGE_POOL\n 36:\t\tselect CRYPTO_LIB_AES if MACSEC\n 37:\t\tdepends on (64BIT \u0026\u0026 COMPILE_TEST) || ARM64\n 38:\t\tselect DIMLIB\n 39:\t\tdepends on PCI\n 40:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n 41:\t\tdepends on MACSEC || !MACSEC\n 42:\t\thelp\n 43:\t\t This driver supports Marvell's OcteonTX2 NIC physical function.\n 44:\t\n 45:\tconfig OCTEONTX2_VF\n 46:\t\ttristate \"Marvell OcteonTX2 NIC Virtual Function driver\"\n 47:\t\tdepends on OCTEONTX2_PF\n 48:\t\thelp\n 49:\t\t This driver supports Marvell's OcteonTX2 NIC virtual function.\n 50:\t\n 51:\tconfig RVU_ESWITCH\n 52:\t\ttristate \"Marvell RVU E-Switch support\"\n 53:\t\tdepends on OCTEONTX2_PF\n 54:\t\tdefault m\n 55:\t\thelp\n 56:\t\t This driver supports Marvell's RVU E-Switch that\n 57:\t\t provides internal SRIOV packet steering and switching.\n"
} |
| 7/2 | 2026/09/25 08:57 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 42334 output: 48 thoughts: 302 Thoughts: **Analyzing the OcteonTX2 NIC Driver** Okay, let's break this down. First, I see dependencies: `(64BIT && COMPILE_TEST) || ARM64` and `PCI`. That already narrows things down a bit, and the description explicitly states this driver supports Marvell's OcteonTX2 NIC in both physical and virtual function modes. My target architecture is amd64, which is relevant, but the bigger question looms: does this OcteonTX2 silicon *require* specific hardware or an ASIC? The "structurally unreachable hardware" section is the key. It specifically calls out vendor-specific PCIe switches and SmartNICs, *exactly* like the Marvell OcteonTX2. We're talking about RVU AF/PF/VF on CN9K, CN10K, and similar Marvell silicon. My experience tells me that these often *do* depend on custom hardware. The crucial point is that standard QEMU or GCE doesn't emulate this type of NIC. The question now is: does *anything* emulate it? Is there any virtual or software emulation for OcteonTX2 within the kernel? Given the kernel's PCI binding, it appears to be a no. It's safe to say QEMU can't handle the Marvell OcteonTX2, and now it's time to check the PCI device IDs to confirm the specifics. |
| 8/2 | 2026/09/25 08:58 | tool | grepper |
0mArgs:{
"Expression": "PCI_DEVICE\\(PCI_VENDOR_ID_CAVIUM",
"PathPrefix": "drivers/net/ethernet/marvell/octeontx2"
}Results: {
"Output": "drivers/net/ethernet/marvell/octeontx2/af/cgx.c=66=static const struct pci_device_id cgx_id_table[] = {\ndrivers/net/ethernet/marvell/octeontx2/af/cgx.c:67:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_CGX) },\ndrivers/net/ethernet/marvell/octeontx2/af/cgx.c-68-\t{ PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_RPM,\n--\ndrivers/net/ethernet/marvell/octeontx2/af/mcs.c=20=static const struct pci_device_id mcs_id_table[] = {\ndrivers/net/ethernet/marvell/octeontx2/af/mcs.c:21:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_MCS) },\ndrivers/net/ethernet/marvell/octeontx2/af/mcs.c-22-\t{ 0, } /* end of table */\n--\ndrivers/net/ethernet/marvell/octeontx2/af/ptp.c=589=static const struct pci_device_id ptp_id_table[] = {\n--\ndrivers/net/ethernet/marvell/octeontx2/af/ptp.c-607-\t\t\t PCI_SUBSYS_DEVID_OCTX2_95XXO_PTP) },\ndrivers/net/ethernet/marvell/octeontx2/af/ptp.c:608:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_PTP) },\ndrivers/net/ethernet/marvell/octeontx2/af/ptp.c-609-\t{ 0, }\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c=44=static const struct pci_device_id rvu_id_table[] = {\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c:45:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_AF) },\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c-46-\t{ 0, } /* end of table */\n--\ndrivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c=36=static const struct pci_device_id otx2_pf_id_table[] = {\ndrivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c:37:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_PF) },\ndrivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c-38-\t{ 0, } /* end of table */\n--\ndrivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c=22=static const struct pci_device_id otx2_vf_id_table[] = {\ndrivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c:23:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_AFVF) },\ndrivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c:24:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_VF) },\ndrivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c:25:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_SDP_REP) },\ndrivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c-26-\t{ }\n--\ndrivers/net/ethernet/marvell/octeontx2/nic/rep.c=22=static const struct pci_device_id rvu_rep_id_table[] = {\ndrivers/net/ethernet/marvell/octeontx2/nic/rep.c:23:\t{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_RVU_REP) },\ndrivers/net/ethernet/marvell/octeontx2/nic/rep.c-24-\t{ }\n"
} |
| 9/2 | 2026/09/25 08:58 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 44202 output: 129 thoughts: 1153 Thoughts: **Analysis of Marvell OcteonTX2 NIC Driver for Fuzzing Suitability** Okay, let's break this down. First, the key here is `PCI_VENDOR_ID_CAVIUM = 0x177d`. Right away, that tells me we're dealing with Cavium (now Marvell) hardware. The device IDs further confirm this: `PCI_DEVID_OCTEONTX2_RVU_PF`, `PCI_DEVID_OCTEONTX2_RVU_VF`, etc. These are all OcteonTX2 specific. The crucial point is this dependency: `depends on (64BIT && COMPILE_TEST) || ARM64`. On x86 (amd64), it *only* builds if `COMPILE_TEST` is enabled. That's because, as we know, the Marvell OcteonTX2 is an ARM64 SoC, so the code targets an ARM64 architecture or PCIe add-in card. Even on ARM64, it *requires* physical Marvell OcteonTX2 hardware to be present. You can't emulate or instantiate these devices in standard QEMU or GCE environments. They're not supported. Now, let's look at the modified files: `drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c`, and so on, all the way through `rep.h`. The entire patch is contained within the `drivers/net/ethernet/marvell/octeontx2/nic/` directory. Absolutely nothing touches core networking, netlink, TC framework, or anything outside of that NIC driver. This is entirely self-contained. Now, based on the provided instructions, let's apply the negative criteria. Section 2, specifically, describes "Structurally unreachable hardware." It mentions "Vendor-specific PCIe switches, SmartNICs, or GPU drivers... requiring physical ASIC/PCIe cards not emulated in standard QEMU". That's a perfect match for the Marvell OcteonTX2 NIC driver. The OcteonTX2 is *exactly* that: a vendor-specific SmartNIC / PCIe device requiring physical Cavium / Marvell OcteonTX2 silicon, which, as stated, is not emulated. The amd64 dependency reinforces this: it will *not* build on amd64 without COMPILE_TEST because it's fundamentally targeting ARM64 hardware. Therefore, given the target hardware, the architecture, and the nature of the driver, this code is *structurally unreachable* for any reasonable fuzzing setup. Therefore: * `WorthFuzzing = false` * `EnableConfigs = []` * `FocusSymbols = []` * `Reasoning = "Changes are exclusive to the Marvell OcteonTX2 NIC driver, a vendor-specific SmartNIC / PCIe device that requires physical Cavium/Marvell OcteonTX2 hardware not emulated in standard QEMU/GCE environments. The code will also not build without COMPILE_TEST if not targetting ARM64."` That's rock solid. Everything is clear and verified. We're good to go. |
| 10/2 | 2026/09/25 08:58 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch series modifies only the Marvell OcteonTX2 NIC driver (drivers/net/ethernet/marvell/octeontx2/nic/). This driver requires vendor-specific Cavium/Marvell OcteonTX2 physical ASIC/PCIe hardware (primarily ARM64 SoC/SmartNIC silicon) that is not emulated in standard virtualized fuzzing environments (QEMU/GCE), making the modified code structurally unreachable for syzkaller.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series modifies only the Marvell OcteonTX2 NIC driver (drivers/net/ethernet/marvell/octeontx2/nic/). This driver requires vendor-specific Cavium/Marvell OcteonTX2 physical ASIC/PCIe hardware (primarily ARM64 SoC/SmartNIC silicon) that is not emulated in standard virtualized fuzzing environments (QEMU/GCE), making the modified code structurally unreachable for syzkaller.",
"WorthFuzzing": false
} |
| 11/1 | 2026/09/25 08:58 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|