AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/09/11 12:46 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch series exclusively modifies the Marvell OcteonTX2 RVU/NIC driver (drivers/net/ethernet/marvell/octeontx2/), adding mqprio bandwidth offload support and refactoring flag bitmask operations. This driver requires specific physical Marvell OcteonTX2 / CN10K hardware/ASICs and is not emulated in standard QEMU/GCE virtualization environments, making the code structurally unreachable for syzkaller fuzzing.",
  "WorthFuzzing": false
}

1/1 2026/09/11 12:46 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 92c1334cd9e5048e3c651f1735ad02018abc0d84\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Fri Sep 11 12:46:51 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c\nindex d80d2c00bd843..2d1ab8c761c40 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c\n@@ -331,8 +331,12 @@ static bool is_valid_txschq(struct rvu *rvu, int blkaddr,\n \t\t\treturn true;\n \t}\n \n-\tif (map_func != pcifunc)\n+\tif (map_func != pcifunc) {\n+\t\tdev_err_ratelimited(rvu-\u003edev,\n+\t\t\t\t    \"pcifunc %x map pcifunc %x not equal, lvl=%u schq=%u\\n\",\n+\t\t\t\t    pcifunc, map_func, lvl, schq);\n \t\treturn false;\n+\t}\n \n \treturn true;\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..5bad2466da0c5 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,142 @@ 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.  Pass burst 0 so\n+\t * otx2_get_egress_burst_cfg() programmes the largest burst the NIX\n+\t * encoding supports (CN10K_MAX_BURST_SIZE on CN10K).  This differs\n+\t * from the 65536 byte default used in the HTB path, which is a\n+\t * kernel-side default when no explicit burst is configured, not a\n+\t * hardware cap.\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, 0);\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, 0);\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 +787,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 +919,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 +987,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 eecee612b7b2c..6e7132f27b621 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@@ -483,6 +484,23 @@ struct pf_irq_data {\n \tint mdevs;\n };\n \n+struct mq_offload_snap {\n+\tu64 min_rate[TC_QOPT_MAX_QUEUE];\n+\tu64 max_rate[TC_QOPT_MAX_QUEUE];\n+\t__u8 num_tc;\n+\t__u16 count[TC_QOPT_MAX_QUEUE];\n+\t__u16 offset[TC_QOPT_MAX_QUEUE];\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+};\n+\n struct otx2_nic {\n \tvoid __iomem\t\t*reg_base;\n \tstruct net_device\t*netdev;\n@@ -491,30 +509,35 @@ 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+#define OTX2_FLAG_RX_TSTAMP_ENABLED\t\t0\n+#define OTX2_FLAG_TX_TSTAMP_ENABLED\t\t1\n+#define OTX2_FLAG_INTF_DOWN\t\t\t2\n+#define OTX2_FLAG_MCAM_ENTRIES_ALLOC\t\t3\n+#define OTX2_FLAG_NTUPLE_SUPPORT\t\t4\n+#define OTX2_FLAG_UCAST_FLTR_SUPPORT\t\t5\n+#define OTX2_FLAG_RX_VLAN_SUPPORT\t\t6\n+#define OTX2_FLAG_VF_VLAN_SUPPORT\t\t7\n+#define OTX2_FLAG_PF_SHUTDOWN\t\t\t8\n+#define OTX2_FLAG_RX_PAUSE_ENABLED\t\t9\n+#define OTX2_FLAG_TX_PAUSE_ENABLED\t\t10\n+#define OTX2_FLAG_TC_FLOWER_SUPPORT\t\t11\n+#define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED\t12\n+#define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED\t13\n+#define OTX2_FLAG_DMACFLTR_SUPPORT\t\t14\n+#define OTX2_FLAG_PTP_ONESTEP_SYNC\t\t15\n+#define OTX2_FLAG_ADPTV_INT_COAL_ENABLED\t16\n+#define OTX2_FLAG_TC_MARK_ENABLED\t\t17\n+#define OTX2_FLAG_REP_MODE_ENABLED\t\t18\n+#define OTX2_FLAG_PORT_UP\t\t\t19\n+#define OTX2_FLAG_IPSEC_OFFLOAD_ENABLED\t\t20\n+#define OTX2_REP_VF_INITIALIZED\t\t\t21\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@@ -594,6 +617,34 @@ 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 int flag;\n+\n+\tfor (flag = 0; flag \u003c= OTX2_REP_VF_INITIALIZED; flag++) {\n+\t\tif (test_bit(flag, src_flags))\n+\t\t\tset_bit(flag, \u0026dst-\u003eflags);\n+\t\telse\n+\t\t\tclear_bit(flag, \u0026dst-\u003eflags);\n+\t}\n+}\n+\n static inline bool is_otx2_lbkvf(struct pci_dev *pdev)\n {\n \treturn (pdev-\u003edevice == PCI_DEVID_OCTEONTX2_RVU_AFVF) ||\n@@ -1246,6 +1297,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 9bee1b91eeaa6..e63ead3b1113e 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..1e17f8d49fd44 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,14 @@ int otx2_open(struct net_device *netdev)\n \tif (err)\n \t\tgoto err_free_mem;\n \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 +2143,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 +2169,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 +2194,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 +2213,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 +2229,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 +2289,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 +2467,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 +2488,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 +2499,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 +2520,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 +2547,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 +2559,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 +2845,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 +2933,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 +3102,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 +3289,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,23 +3344,23 @@ 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 \n \tnetdev-\u003ehw_features |= NETIF_F_LOOPBACK | NETIF_F_RXALL;\n@@ -3595,18 +3611,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 \ndiff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c\nindex 039fd47ebf522..70d99ae3defb5 100644\n--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c\n+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c\n@@ -16,6 +16,8 @@\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+#include \u003cnet/sch_generic.h\u003e\n \n #include \"cn10k.h\"\n #include \"otx2_common.h\"\n@@ -31,6 +33,10 @@\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+/* Max egress shaping rate the NIX TLX encoder supports (130816 Mbps). */\n+#define OTX2_MQPRIO_MAX_RATE_BYTES_PS\t((MAX_BURST_SIZE * 1000000ULL) / 8ULL)\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 +67,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 +168,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 +232,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 +253,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 +270,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 +514,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 +951,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 +1204,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 +1255,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 +1453,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 +1478,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 +1495,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 +1609,750 @@ 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+\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+\totx2_mqprio_free_cache(pfvf);\n+\n+\tpfvf-\u003emqprio.min_rate = devm_kcalloc(pfvf-\u003edev, num_txq,\n+\t\t\t\t\t     sizeof(*pfvf-\u003emqprio.min_rate),\n+\t\t\t\t\t     GFP_KERNEL);\n+\tpfvf-\u003emqprio.max_rate = devm_kcalloc(pfvf-\u003edev, num_txq,\n+\t\t\t\t\t     sizeof(*pfvf-\u003emqprio.max_rate),\n+\t\t\t\t\t     GFP_KERNEL);\n+\tif (!pfvf-\u003emqprio.min_rate || !pfvf-\u003emqprio.max_rate) {\n+\t\totx2_mqprio_free_cache(pfvf);\n+\t\treturn -ENOMEM;\n+\t}\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+\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+\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 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 = 0;\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\tif (min_rate)\n+\t\t\tpfvf-\u003emqprio.flags |= TC_MQPRIO_F_MIN_RATE;\n+\t\tif (max_rate)\n+\t\t\tpfvf-\u003emqprio.flags |= TC_MQPRIO_F_MAX_RATE;\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+\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+\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+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+\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; clearing software state\\n\",\n+\t\t\t    err);\n+\t\totx2_mqprio_clear_sw(pfvf);\n+\t\treturn err;\n+\t}\n+\n+\totx2_mqprio_clear_sw(pfvf);\n+\n+\treturn 0;\n+}\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\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+ * Quiesce the transmit path like __dev_close_many() before ndo_stop() so\n+ * otx2_xmit() cannot race otx2_free_queue_mem().\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_info(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+\tdev_deactivate(netdev, true);\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\t\tdev_activate(netdev);\n+\t\t}\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\tdev_activate(netdev);\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: mqprio min_rate/max_rate are per traffic class, but bandwidth\n+\t * offload shapes on per-queue MDQ nodes parented under a single TL4.\n+\t * Without per-TC TL4 shapers the driver cannot honor TC-level limits\n+\t * for a traffic class that spans multiple queues without either\n+\t * dividing the rate across queues (uAPI mismatch) or exceeding the TC\n+\t * cap when every member queue is active. Reject until per-TC TL4\n+\t * shaping can be implemented without allocating additional TL4 nodes\n+\t * beyond the existing hierarchy.\n+\t */\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(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\tint down_err, err;\n+\n+\t\tdown_err = otx2_mqprio_down(pfvf);\n+\t\terr = otx2_mqprio_restart_netdev(netdev, false);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t\treturn down_err;\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\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\treturn -EOPNOTSUPP;\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\treturn -EOPNOTSUPP;\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\treturn -EOPNOTSUPP;\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\treturn -EOPNOTSUPP;\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\treturn -EOPNOTSUPP;\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\treturn -EOPNOTSUPP;\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\treturn -EINVAL;\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\treturn err;\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\treturn err;\n+\t\t}\n+\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MIN_RATE \u0026\u0026\n+\t\t    !otx2_mqprio_rate_valid(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\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_MAX_RATE \u0026\u0026\n+\t\t    !otx2_mqprio_rate_valid(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\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\terr = otx2_mqprio_validate_txqs(netdev, extack, qopt);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = otx2_mqprio_stage_cur(pfvf, mqprio);\n+\tif (err)\n+\t\treturn err;\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(). Multi-queue TCs with rates\n+\t\t * are rejected above.\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+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; prior configuration restored\\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; prior configuration restored\");\n+\t\t}\n+\t\treturn err ? err : -EIO;\n+\t}\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@@ -1632,6 +2377,7 @@ EXPORT_SYMBOL(otx2_init_tc);\n void otx2_shutdown_tc(struct otx2_nic *nic)\n {\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..5f7915231ca3a 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@@ -824,10 +824,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 \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..8a8c0088fd204 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_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_REP_VF_INITIALIZED, \u0026rep-\u003eflags);\n \telse\n-\t\trep-\u003eflags \u0026= ~RVU_REP_VF_INITIALIZED;\n+\t\tclear_bit(OTX2_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_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_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_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/11 12:46 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch series exclusively modifies the Marvell OcteonTX2 RVU/NIC driver (drivers/net/ethernet/marvell/octeontx2/), adding mqprio bandwidth offload support and refactoring flag bitmask operations. This driver requires specific physical Marvell OcteonTX2 / CN10K hardware/ASICs and is not emulated in standard QEMU/GCE virtualization environments, making the code structurally unreachable for syzkaller fuzzing.",
  "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 92c1334cd9e5048e3c651f1735ad02018abc0d84
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Sep 11 12:46:51 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index d80d2c00bd843..2d1ab8c761c40 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -331,8 +331,12 @@ static bool is_valid_txschq(struct rvu *rvu, int blkaddr,
 			return true;
 	}
 
-	if (map_func != pcifunc)
+	if (map_func != pcifunc) {
+		dev_err_ratelimited(rvu->dev,
+				    "pcifunc %x map pcifunc %x not equal, lvl=%u schq=%u\n",
+				    pcifunc, map_func, lvl, schq);
 		return false;
+	}
 
 	return true;
 }
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..5bad2466da0c5 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,142 @@ 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.  Pass burst 0 so
+	 * otx2_get_egress_burst_cfg() programmes the largest burst the NIX
+	 * encoding supports (CN10K_MAX_BURST_SIZE on CN10K).  This differs
+	 * from the 65536 byte default used in the HTB path, which is a
+	 * kernel-side default when no explicit burst is configured, not a
+	 * hardware cap.
+	 *
+	 * 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, 0);
+	} 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, 0);
+	} 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 +787,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 +919,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 +987,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 eecee612b7b2c..6e7132f27b621 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>
@@ -483,6 +484,23 @@ struct pf_irq_data {
 	int mdevs;
 };
 
+struct mq_offload_snap {
+	u64 min_rate[TC_QOPT_MAX_QUEUE];
+	u64 max_rate[TC_QOPT_MAX_QUEUE];
+	__u8 num_tc;
+	__u16 count[TC_QOPT_MAX_QUEUE];
+	__u16 offset[TC_QOPT_MAX_QUEUE];
+};
+
+struct otx2_mqprio {
+	u32	flags;
+	u64	*min_rate;
+	u64	*max_rate;
+	bool	rate_limit;
+	bool	replace_setup_done;
+	bool	replace_graft_done;
+};
+
 struct otx2_nic {
 	void __iomem		*reg_base;
 	struct net_device	*netdev;
@@ -491,30 +509,35 @@ 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;
+#define OTX2_FLAG_RX_TSTAMP_ENABLED		0
+#define OTX2_FLAG_TX_TSTAMP_ENABLED		1
+#define OTX2_FLAG_INTF_DOWN			2
+#define OTX2_FLAG_MCAM_ENTRIES_ALLOC		3
+#define OTX2_FLAG_NTUPLE_SUPPORT		4
+#define OTX2_FLAG_UCAST_FLTR_SUPPORT		5
+#define OTX2_FLAG_RX_VLAN_SUPPORT		6
+#define OTX2_FLAG_VF_VLAN_SUPPORT		7
+#define OTX2_FLAG_PF_SHUTDOWN			8
+#define OTX2_FLAG_RX_PAUSE_ENABLED		9
+#define OTX2_FLAG_TX_PAUSE_ENABLED		10
+#define OTX2_FLAG_TC_FLOWER_SUPPORT		11
+#define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED	12
+#define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED	13
+#define OTX2_FLAG_DMACFLTR_SUPPORT		14
+#define OTX2_FLAG_PTP_ONESTEP_SYNC		15
+#define OTX2_FLAG_ADPTV_INT_COAL_ENABLED	16
+#define OTX2_FLAG_TC_MARK_ENABLED		17
+#define OTX2_FLAG_REP_MODE_ENABLED		18
+#define OTX2_FLAG_PORT_UP			19
+#define OTX2_FLAG_IPSEC_OFFLOAD_ENABLED		20
+#define OTX2_REP_VF_INITIALIZED			21
+	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;
@@ -594,6 +617,34 @@ 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 int flag;
+
+	for (flag = 0; flag <= OTX2_REP_VF_INITIALIZED; flag++) {
+		if (test_bit(flag, src_flags))
+			set_bit(flag, &dst->flags);
+		else
+			clear_bit(flag, &dst->flags);
+	}
+}
+
 static inline bool is_otx2_lbkvf(struct pci_dev *pdev)
 {
 	return (pdev->device == PCI_DEVID_OCTEONTX2_RVU_AFVF) ||
@@ -1246,6 +1297,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 9bee1b91eeaa6..e63ead3b1113e 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..1e17f8d49fd44 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,14 @@ int otx2_open(struct net_device *netdev)
 	if (err)
 		goto err_free_mem;
 
+	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 +2143,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 +2169,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 +2194,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 +2213,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 +2229,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 +2289,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 +2467,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 +2488,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 +2499,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 +2520,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 +2547,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 +2559,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 +2845,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 +2933,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 +3102,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 +3289,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,23 +3344,23 @@ 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->hw_features |= NETIF_F_LOOPBACK | NETIF_F_RXALL;
@@ -3595,18 +3611,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);
 	}
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
index 039fd47ebf522..70d99ae3defb5 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
@@ -16,6 +16,8 @@
 #include <net/tc_act/tc_mirred.h>
 #include <net/tc_act/tc_vlan.h>
 #include <net/ipv6.h>
+#include <net/pkt_sched.h>
+#include <net/sch_generic.h>
 
 #include "cn10k.h"
 #include "otx2_common.h"
@@ -31,6 +33,10 @@
 
 #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
+/* Max egress shaping rate the NIX TLX encoder supports (130816 Mbps). */
+#define OTX2_MQPRIO_MAX_RATE_BYTES_PS	((MAX_BURST_SIZE * 1000000ULL) / 8ULL)
 
 static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
 				      u32 *burst_exp, u32 *burst_mantissa)
@@ -61,6 +67,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 +168,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 +232,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 +253,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 +270,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 +514,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 +951,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 +1204,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 +1255,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 +1453,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 +1478,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 +1495,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 +1609,750 @@ 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;
+
+	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;
+	}
+
+	otx2_mqprio_free_cache(pfvf);
+
+	pfvf->mqprio.min_rate = devm_kcalloc(pfvf->dev, num_txq,
+					     sizeof(*pfvf->mqprio.min_rate),
+					     GFP_KERNEL);
+	pfvf->mqprio.max_rate = devm_kcalloc(pfvf->dev, num_txq,
+					     sizeof(*pfvf->mqprio.max_rate),
+					     GFP_KERNEL);
+	if (!pfvf->mqprio.min_rate || !pfvf->mqprio.max_rate) {
+		otx2_mqprio_free_cache(pfvf);
+		return -ENOMEM;
+	}
+
+	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;
+	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];
+	}
+
+	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 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 = 0;
+
+	for (tc = 0; tc < snap->num_tc; tc++) {
+		u64 min_rate = snap->min_rate[tc];
+		u64 max_rate = snap->max_rate[tc];
+
+		if (min_rate)
+			pfvf->mqprio.flags |= TC_MQPRIO_F_MIN_RATE;
+		if (max_rate)
+			pfvf->mqprio.flags |= TC_MQPRIO_F_MAX_RATE;
+
+		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;
+		}
+	}
+
+	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]);
+
+	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);
+}
+
+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);
+	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; clearing software state\n",
+			    err);
+		otx2_mqprio_clear_sw(pfvf);
+		return err;
+	}
+
+	otx2_mqprio_clear_sw(pfvf);
+
+	return 0;
+}
+
+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);
+			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.
+ *
+ * Quiesce the transmit path like __dev_close_many() before ndo_stop() so
+ * otx2_xmit() cannot race otx2_free_queue_mem().
+ */
+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_info(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(). */
+	}
+	dev_deactivate(netdev, true);
+
+	err = ops->ndo_stop(netdev);
+	if (err) {
+		if (running) {
+			set_bit(__LINK_STATE_START, &netdev->state);
+			dev_activate(netdev);
+		}
+		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);
+		dev_activate(netdev);
+	} 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: mqprio min_rate/max_rate are per traffic class, but bandwidth
+	 * offload shapes on per-queue MDQ nodes parented under a single TL4.
+	 * Without per-TC TL4 shapers the driver cannot honor TC-level limits
+	 * for a traffic class that spans multiple queues without either
+	 * dividing the rate across queues (uAPI mismatch) or exceeding the TC
+	 * cap when every member queue is active. Reject until per-TC TL4
+	 * shaping can be implemented without allocating additional TL4 nodes
+	 * beyond the existing hierarchy.
+	 */
+	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(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) {
+		int down_err, err;
+
+		down_err = otx2_mqprio_down(pfvf);
+		err = otx2_mqprio_restart_netdev(netdev, false);
+		if (err)
+			return err;
+		return down_err;
+	}
+
+	/* 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");
+		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);
+		return -EOPNOTSUPP;
+	}
+
+	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");
+		return -EOPNOTSUPP;
+	}
+
+	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");
+		return -EOPNOTSUPP;
+	}
+
+	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");
+		return -EOPNOTSUPP;
+	}
+
+	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");
+		return -EOPNOTSUPP;
+	}
+
+	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");
+		return -EOPNOTSUPP;
+	}
+
+	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);
+			return -EINVAL;
+		}
+
+		if (mqprio->flags & TC_MQPRIO_F_MIN_RATE) {
+			err = otx2_mqprio_validate_tc_rate(netdev, extack, min_rate,
+							   qcount, tc, "min");
+			if (err)
+				return err;
+		}
+
+		if (mqprio->flags & TC_MQPRIO_F_MAX_RATE) {
+			err = otx2_mqprio_validate_tc_rate(netdev, extack, max_rate,
+							   qcount, tc, "max");
+			if (err)
+				return err;
+		}
+
+		if (mqprio->flags & TC_MQPRIO_F_MIN_RATE &&
+		    !otx2_mqprio_rate_valid(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);
+			return -EINVAL;
+		}
+
+		if (mqprio->flags & TC_MQPRIO_F_MAX_RATE &&
+		    !otx2_mqprio_rate_valid(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);
+			return -EINVAL;
+		}
+	}
+
+	err = otx2_mqprio_validate_txqs(netdev, extack, qopt);
+	if (err)
+		return err;
+
+	err = otx2_mqprio_stage_cur(pfvf, mqprio);
+	if (err)
+		return err;
+
+	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(). Multi-queue TCs with rates
+		 * are rejected above.
+		 */
+		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;
+
+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; prior configuration restored\n");
+			if (extack)
+				NL_SET_ERR_MSG_MOD(extack,
+						   "mqprio: replace failed; prior configuration restored");
+		}
+		return err ? err : -EIO;
+	}
+	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;
 	}
@@ -1632,6 +2377,7 @@ EXPORT_SYMBOL(otx2_init_tc);
 void otx2_shutdown_tc(struct otx2_nic *nic)
 {
 	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..5f7915231ca3a 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;
@@ -824,10 +824,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);
 	}
 
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..8a8c0088fd204 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_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_REP_VF_INITIALIZED, &rep->flags);
 	else
-		rep->flags &= ~RVU_REP_VF_INITIALIZED;
+		clear_bit(OTX2_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_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_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_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/11 12:46 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 35994
							output: 36
							thoughts: 760
						

Thoughts:
**Fuzzing Decision for the OcteonTX2 NIC Patch**

Okay, let's break this down. My initial assessment is focused on whether this patch is a good candidate for fuzzing, and I need to apply the established guidelines. First, I need to understand the scope of the changes. The patch touches a lot of files within the Marvell OcteonTX2 networking driver. Specifically, it seems to modify code within the `drivers/net/ethernet/marvell/octeontx2` directory. This is interesting, as this likely is a driver for a vendor-specific hardware, a SmartNIC or potentially a SoC.

Now, the crucial question is whether this hardware is realistically reachable for fuzzing, which means the hardware must be emulated in standard QEMU or directly accessible. The guidelines, specifically Section 2, are very clear on this. The "structurally unreachable hardware" clause jumps out, and I'm looking to check to confirm whether OcteonTX2 falls into that category. The rule specifically calls out SmartNICs and vendor-specific PCIe switches as potential exclusions. I need to figure out the nature of the OcteonTX2. Is it a proprietary ASIC, a NIC that requires a specific hardware setup, or can it be simulated or accessed in a way that aligns with the fuzzing infrastructure? This is critical.

I'll need to research what the `octeontx2` refers to, and what the hardware entails. I'll need to check the Kconfig, or search for information to understand what it is and how accessible it is. If it's something like an mlxsw, or ionic, I'll need to strongly consider whether this is worth pursuing, or if it is unfeasible given that I don't have direct access to that hardware.



4/2 2026/09/11 12:46 tool grepper
0m Args:
{
  "Expression": "config OCTEONTX2",
  "PathPrefix": "drivers/net/ethernet/marvell/"
}

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/11 12:46 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 37582
							output: 44
							thoughts: 24
						

Thoughts:
Here's a summary of my thought process, as if I were analyzing that Kconfig file:

**Diving into the Marvell Octeon TX2 Ethernet Driver Configuration**

Okay, so I'm about to dissect `drivers/net/ethernet/marvell/octeontx2/Kconfig`. This is where the core configuration options for the Marvell Octeon TX2 Ethernet driver are defined, which is crucial for understanding how it can be tailored for different systems and use cases. I expect to find dependencies on other parts of the kernel, hardware-specific settings, and the usual conditional compilation logic. I'll be looking for the fundamental building blocks - the features that can be enabled or disabled, and the implications of those choices. I'll need to pay close attention to the dependencies – what other drivers or kernel features are required for various Octeon TX2 Ethernet functionalities. Are there specific board configurations or PHY options I need to consider? I'll also be scanning for any unusual or vendor-specific options that might indicate unique Marvell optimizations or hardware features. My goal is to grasp the configurability of this driver and how it interfaces with the overall networking stack. I need to get a clear picture of what the key configurable elements are and their potential impacts on performance, power consumption, and supported hardware. Finally, I'll be looking for any hints about potential configuration pitfalls or common issues that might arise during deployment. Let's see what we can find!



6/2 2026/09/11 12:47 tool read-file
0m Args:
{
  "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/11 12:47 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 38767
							output: 131
							thoughts: 948
						

Thoughts:
**Analysis of the OcteonTX2 Driver for Fuzzing Eligibility**

Okay, let's break this down. These `OCTEONTX2` drivers are, as I understand, specific to Marvell's OcteonTX2 RVU/SmartNIC/SoC hardware. They're physical drivers for ARM64 or, in some cases, 64-bit compilation tests. The key here is *physical* hardware; these drivers are tied to Marvell's PCIe devices. Standard QEMU or GCE VMs simply won't cut it. They can't emulate this hardware.

My immediate thought is to verify the scope of the modifications. A quick scan of the changed files confirms this. It looks like the patch touches a comprehensive set of files within `drivers/net/ethernet/marvell/octeontx2/`. It includes things like `af/rvu_nix.c`, `nic/cn10k_ipsec.c`, `nic/otx2_common.c`, and so on. No core networking, socket code, or Netlink core have been modified, so that's a good sign. The changes are all self-contained within this driver's specific directory.

Now, let's apply the criteria. We're looking for structurally unreachable hardware. Looking at section 2, the examples provided there, `mlxsw`, `pds_core`, `qed`, etc., are all vendor-specific PCIe switches or SmartNIC drivers.  These require physical ASICs or PCIe cards that aren't emulated in standard QEMU. That is exactly what we have here. The OcteonTX2 is a vendor-specific SmartNIC/SoC network driver, and it needs physical Marvell hardware / ASICs to work.  This is critical.

This patch series modifies code that is inherently unreachable in any typical fuzzing setup like the one in syzkaller. The hardware dependency renders it moot.

Therefore, the `WorthFuzzing` flag should be set to `false`. There's no point in trying to fuzz code that won't ever execute in the fuzzing environment.

Finally, let's prepare the tool call:

*   `WorthFuzzing: false`
*   `FocusSymbols: []` (We don't need any focused symbols)
*   `EnableConfigs: []` (We don't need to enable anything)
*   `Reasoning: The modifications are exclusively within the Marvell OcteonTX2 NIC driver, requiring physical Marvell OcteonTX2 / CN10K ASIC/PCIe hardware, which is not emulated in standard virtualized environments (QEMU/GCE), making the modified code structurally unreachable for fuzzing.`



8/2 2026/09/11 12:47 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch series exclusively modifies the Marvell OcteonTX2 RVU/NIC driver (drivers/net/ethernet/marvell/octeontx2/), adding mqprio bandwidth offload support and refactoring flag bitmask operations. This driver requires specific physical Marvell OcteonTX2 / CN10K hardware/ASICs and is not emulated in standard QEMU/GCE virtualization environments, making the code structurally unreachable for syzkaller fuzzing.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch series exclusively modifies the Marvell OcteonTX2 RVU/NIC driver (drivers/net/ethernet/marvell/octeontx2/), adding mqprio bandwidth offload support and refactoring flag bitmask operations. This driver requires specific physical Marvell OcteonTX2 / CN10K hardware/ASICs and is not emulated in standard QEMU/GCE virtualization environments, making the code structurally unreachable for syzkaller fuzzing.",
  "WorthFuzzing": false
}

9/1 2026/09/11 12:47 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

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