* [PATCH net-next v13 1/2] net: mana: refactor mana_get_strings() and mana_get_sset_count() to use switch
From: Dipayaan Roy @ 2026-07-29 6:21 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, linux-hyperv, netdev, linux-kernel, linux-rdma,
stephen, jacob.e.keller, dipayanroy, leitao, kees, john.fastabend,
hawk, bpf, daniel, ast, sdf, yury.norov, pavan.chebbi,
schakrabarti, gargaditya
In-Reply-To: <20260729063347.3388035-1-dipayanroy@linux.microsoft.com>
Refactor mana_get_strings() and mana_get_sset_count() from if/else to
switch statements in preparation for adding ethtool private flags
support which requires handling ETH_SS_PRIV_FLAGS.
No functional change.
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
.../ethernet/microsoft/mana/mana_ethtool.c | 75 ++++++++++++-------
1 file changed, 46 insertions(+), 29 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 9e31e2595ae3..482cd16009ab 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -138,53 +138,70 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset)
struct mana_port_context *apc = netdev_priv(ndev);
unsigned int num_queues = apc->num_queues;
- if (stringset != ETH_SS_STATS)
+ switch (stringset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(mana_eth_stats) +
+ ARRAY_SIZE(mana_phy_stats) +
+ ARRAY_SIZE(mana_hc_stats) +
+ num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
+ default:
return -EINVAL;
-
- return ARRAY_SIZE(mana_eth_stats) + ARRAY_SIZE(mana_phy_stats) + ARRAY_SIZE(mana_hc_stats) +
- num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
+ }
}
-static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
+static void mana_get_strings_stats(struct mana_port_context *apc, u8 **data)
{
- struct mana_port_context *apc = netdev_priv(ndev);
unsigned int num_queues = apc->num_queues;
int i, j;
- if (stringset != ETH_SS_STATS)
- return;
for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++)
- ethtool_puts(&data, mana_eth_stats[i].name);
+ ethtool_puts(data, mana_eth_stats[i].name);
for (i = 0; i < ARRAY_SIZE(mana_hc_stats); i++)
- ethtool_puts(&data, mana_hc_stats[i].name);
+ ethtool_puts(data, mana_hc_stats[i].name);
for (i = 0; i < ARRAY_SIZE(mana_phy_stats); i++)
- ethtool_puts(&data, mana_phy_stats[i].name);
+ ethtool_puts(data, mana_phy_stats[i].name);
for (i = 0; i < num_queues; i++) {
- ethtool_sprintf(&data, "rx_%d_packets", i);
- ethtool_sprintf(&data, "rx_%d_bytes", i);
- ethtool_sprintf(&data, "rx_%d_xdp_drop", i);
- ethtool_sprintf(&data, "rx_%d_xdp_tx", i);
- ethtool_sprintf(&data, "rx_%d_xdp_redirect", i);
- ethtool_sprintf(&data, "rx_%d_pkt_len0_err", i);
+ ethtool_sprintf(data, "rx_%d_packets", i);
+ ethtool_sprintf(data, "rx_%d_bytes", i);
+ ethtool_sprintf(data, "rx_%d_xdp_drop", i);
+ ethtool_sprintf(data, "rx_%d_xdp_tx", i);
+ ethtool_sprintf(data, "rx_%d_xdp_redirect", i);
+ ethtool_sprintf(data, "rx_%d_pkt_len0_err", i);
for (j = 0; j < MANA_RXCOMP_OOB_NUM_PPI - 1; j++)
- ethtool_sprintf(&data, "rx_%d_coalesced_cqe_%d", i, j + 2);
+ ethtool_sprintf(data,
+ "rx_%d_coalesced_cqe_%d",
+ i,
+ j + 2);
}
for (i = 0; i < num_queues; i++) {
- ethtool_sprintf(&data, "tx_%d_packets", i);
- ethtool_sprintf(&data, "tx_%d_bytes", i);
- ethtool_sprintf(&data, "tx_%d_xdp_xmit", i);
- ethtool_sprintf(&data, "tx_%d_tso_packets", i);
- ethtool_sprintf(&data, "tx_%d_tso_bytes", i);
- ethtool_sprintf(&data, "tx_%d_tso_inner_packets", i);
- ethtool_sprintf(&data, "tx_%d_tso_inner_bytes", i);
- ethtool_sprintf(&data, "tx_%d_long_pkt_fmt", i);
- ethtool_sprintf(&data, "tx_%d_short_pkt_fmt", i);
- ethtool_sprintf(&data, "tx_%d_csum_partial", i);
- ethtool_sprintf(&data, "tx_%d_mana_map_err", i);
+ ethtool_sprintf(data, "tx_%d_packets", i);
+ ethtool_sprintf(data, "tx_%d_bytes", i);
+ ethtool_sprintf(data, "tx_%d_xdp_xmit", i);
+ ethtool_sprintf(data, "tx_%d_tso_packets", i);
+ ethtool_sprintf(data, "tx_%d_tso_bytes", i);
+ ethtool_sprintf(data, "tx_%d_tso_inner_packets", i);
+ ethtool_sprintf(data, "tx_%d_tso_inner_bytes", i);
+ ethtool_sprintf(data, "tx_%d_long_pkt_fmt", i);
+ ethtool_sprintf(data, "tx_%d_short_pkt_fmt", i);
+ ethtool_sprintf(data, "tx_%d_csum_partial", i);
+ ethtool_sprintf(data, "tx_%d_mana_map_err", i);
+ }
+}
+
+static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
+{
+ struct mana_port_context *apc = netdev_priv(ndev);
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ mana_get_strings_stats(apc, &data);
+ break;
+ default:
+ break;
}
}
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v13 2/2] net: mana: force full-page RX buffers via ethtool private flag
From: Dipayaan Roy @ 2026-07-29 6:21 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, linux-hyperv, netdev, linux-kernel, linux-rdma,
stephen, jacob.e.keller, dipayanroy, leitao, kees, john.fastabend,
hawk, bpf, daniel, ast, sdf, yury.norov, pavan.chebbi,
schakrabarti, gargaditya
In-Reply-To: <20260729063347.3388035-1-dipayanroy@linux.microsoft.com>
On some ARM64 platforms with 4K PAGE_SIZE, page_pool fragment
allocation in the RX refill path can cause 15-20% throughput
regression under high connection counts (>16 TCP streams).
Add an ethtool private flag "full-page-rx" that allows the user to
force one RX buffer per page, bypassing the page_pool fragment path.
This restores line-rate (180+ Gbps) performance on affected platforms.
Usage:
ethtool --set-priv-flags eth0 full-page-rx on
There is no behavioral change by default. The flag must be explicitly
enabled by the user or udev rule.
The existing single-buffer-per-page logic for XDP and jumbo frames is
consolidated into a new helper mana_use_single_rxbuf_per_page() which
is now the single decision point for both the automatic and
user-controlled paths.
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 22 ++++-
.../ethernet/microsoft/mana/mana_ethtool.c | 94 +++++++++++++++++++
include/net/mana/mana.h | 8 ++
3 files changed, 122 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 89e7f59f635d..d859c2eae0a5 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -755,6 +755,25 @@ static void *mana_get_rxbuf_pre(struct mana_rxq *rxq, dma_addr_t *da)
return va;
}
+static bool
+mana_use_single_rxbuf_per_page(struct mana_port_context *apc, u32 mtu)
+{
+ /* On some platforms with 4K PAGE_SIZE, page_pool fragment allocation
+ * in the RX refill path (~2kB buffer) can cause significant throughput
+ * regression under high connection counts. Allow user to force one RX
+ * buffer per page via ethtool private flag to bypass the fragment
+ * path.
+ */
+ if (apc->priv_flags & BIT(MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF))
+ return true;
+
+ /* For xdp and jumbo frames make sure only one packet fits per page. */
+ if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc))
+ return true;
+
+ return false;
+}
+
/* Get RX buffer's data size, alloc size, XDP headroom based on MTU */
static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
int mtu, u32 *datasize, u32 *alloc_size,
@@ -765,8 +784,7 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
/* Calculate datasize first (consistent across all cases) */
*datasize = mtu + ETH_HLEN;
- /* For xdp and jumbo frames make sure only one packet fits per page */
- if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc)) {
+ if (mana_use_single_rxbuf_per_page(apc, mtu)) {
if (mana_xdp_get(apc)) {
*headroom = XDP_PACKET_HEADROOM;
*alloc_size = PAGE_SIZE;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 482cd16009ab..7e441d6ae5dc 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -133,6 +133,10 @@ static const struct mana_stats_desc mana_phy_stats[] = {
{ "hc_tc7_tx_pause_phy", offsetof(struct mana_ethtool_phy_stats, tx_pause_tc7_phy) },
};
+static const char mana_priv_flags[MANA_PRIV_FLAG_MAX][ETH_GSTRING_LEN] = {
+ [MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF] = "full-page-rx"
+};
+
static int mana_get_sset_count(struct net_device *ndev, int stringset)
{
struct mana_port_context *apc = netdev_priv(ndev);
@@ -144,6 +148,10 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset)
ARRAY_SIZE(mana_phy_stats) +
ARRAY_SIZE(mana_hc_stats) +
num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
+
+ case ETH_SS_PRIV_FLAGS:
+ return MANA_PRIV_FLAG_MAX;
+
default:
return -EINVAL;
}
@@ -192,6 +200,14 @@ static void mana_get_strings_stats(struct mana_port_context *apc, u8 **data)
}
}
+static void mana_get_strings_priv_flags(u8 **data)
+{
+ int i;
+
+ for (i = 0; i < MANA_PRIV_FLAG_MAX; i++)
+ ethtool_puts(data, mana_priv_flags[i]);
+}
+
static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
{
struct mana_port_context *apc = netdev_priv(ndev);
@@ -200,6 +216,9 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
case ETH_SS_STATS:
mana_get_strings_stats(apc, &data);
break;
+ case ETH_SS_PRIV_FLAGS:
+ mana_get_strings_priv_flags(&data);
+ break;
default:
break;
}
@@ -756,6 +775,78 @@ static int mana_get_link_ksettings(struct net_device *ndev,
return 0;
}
+static u32 mana_get_priv_flags(struct net_device *ndev)
+{
+ struct mana_port_context *apc = netdev_priv(ndev);
+
+ return apc->priv_flags;
+}
+
+static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags)
+{
+ struct mana_port_context *apc = netdev_priv(ndev);
+ u32 changed = apc->priv_flags ^ priv_flags;
+ u32 old_priv_flags = apc->priv_flags;
+ int err = 0;
+
+ if (!changed)
+ return 0;
+
+ /* Reject unknown bits */
+ if (priv_flags & ~GENMASK(MANA_PRIV_FLAG_MAX - 1, 0))
+ return -EINVAL;
+
+ apc->priv_flags = priv_flags;
+
+ if (changed & BIT(MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF)) {
+ if (!apc->port_is_up)
+ return 0;
+
+ /* If XDP is attached or MTU is jumbo, single-buffer-per-page
+ * is already forced regardless of this flag. Skip the
+ * expensive detach/attach cycle since nothing changes.
+ */
+ if (ndev->mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 ||
+ mana_xdp_get(apc))
+ return 0;
+
+ /* Block RDMA from grabbing the vport during detach/attach */
+ mutex_lock(&apc->vport_mutex);
+ apc->channel_changing = true;
+ mutex_unlock(&apc->vport_mutex);
+
+ err = mana_pre_alloc_rxbufs(apc, ndev->mtu, apc->num_queues);
+ if (err) {
+ netdev_err(ndev,
+ "Insufficient memory for new allocations\n");
+ apc->priv_flags = old_priv_flags;
+ goto clear_flag;
+ }
+
+ err = mana_detach(ndev, false);
+ if (err) {
+ netdev_err(ndev, "mana_detach failed: %d\n", err);
+ apc->priv_flags = old_priv_flags;
+ goto out;
+ }
+
+ err = mana_attach(ndev);
+ if (err) {
+ netdev_err(ndev, "mana_attach failed: %d\n", err);
+ apc->priv_flags = old_priv_flags;
+ }
+ }
+
+out:
+ mana_pre_dealloc_rxbufs(apc);
+clear_flag:
+ mutex_lock(&apc->vport_mutex);
+ apc->channel_changing = false;
+ mutex_unlock(&apc->vport_mutex);
+
+ return err;
+}
+
const struct ethtool_ops mana_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES |
ETHTOOL_COALESCE_RX_USECS |
@@ -766,6 +857,7 @@ const struct ethtool_ops mana_ethtool_ops = {
ETHTOOL_COALESCE_USE_ADAPTIVE_TX,
.op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS |
ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM |
+ ETHTOOL_OP_NEEDS_RTNL_SPFLAGS |
ETHTOOL_OP_NEEDS_RTNL_GLINK,
.get_ethtool_stats = mana_get_ethtool_stats,
.get_sset_count = mana_get_sset_count,
@@ -783,4 +875,6 @@ const struct ethtool_ops mana_ethtool_ops = {
.set_ringparam = mana_set_ringparam,
.get_link_ksettings = mana_get_link_ksettings,
.get_link = ethtool_op_get_link,
+ .get_priv_flags = mana_get_priv_flags,
+ .set_priv_flags = mana_set_priv_flags,
};
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 226b61504596..768d9f9bf167 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -31,6 +31,12 @@ enum TRI_STATE {
TRI_STATE_TRUE = 1
};
+/* MANA ethtool private flag bit positions */
+enum mana_priv_flag_bits {
+ MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF = 0,
+ MANA_PRIV_FLAG_MAX,
+};
+
/* Number of entries for hardware indirection table must be in power of 2 */
#define MANA_INDIRECT_TABLE_MAX_SIZE 512
#define MANA_INDIRECT_TABLE_DEF_SIZE 64
@@ -565,6 +571,8 @@ struct mana_port_context {
u32 rxbpre_headroom;
u32 rxbpre_frag_count;
+ u32 priv_flags;
+
struct bpf_prog *bpf_prog;
/* Create num_queues EQs, SQs, SQ-CQs, RQs and RQ-CQs, respectively. */
--
2.43.0
^ permalink raw reply related
* [PATCH net-next] net: mana: Extend RX CQE coalescing up to 8 packets
From: Haiyang Zhang @ 2026-07-29 22:52 UTC (permalink / raw)
To: linux-hyperv, netdev, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Konstantin Taranov, Simon Horman,
Erni Sri Satya Vennela, Dipayaan Roy, Aditya Garg, Breno Leitao,
linux-kernel, linux-rdma
Cc: paulros
From: Haiyang Zhang <haiyangz@microsoft.com>
To support up to 8 packets per CQE, put two packet lengths and
hash values into one PPI entry by using the reserved fields.
Update ethtool handlers to set this feature.
Update per queue stat to show the coalesced CQE counters.
This feature is supported on NIC hardware showing the relevant
PF flag.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 137 ++++++++++++------
.../ethernet/microsoft/mana/mana_ethtool.c | 30 +++-
include/net/mana/gdma.h | 4 +
include/net/mana/mana.h | 43 ++++--
4 files changed, 150 insertions(+), 64 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index a8c329bdbacf..720d22e6aea9 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1241,6 +1241,9 @@ int mana_gd_query_device_cfg(struct gdma_context *gc, u32 proto_major_ver,
return err;
}
+ if (resp.pf_cap_flags1 & MANA_PF_FLAG_1_CQE_8_COALESCING_SUPPORTED)
+ gc->cqe8_coalescing_sup = true;
+
*max_num_vports = resp.max_num_vports;
if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) {
@@ -1426,7 +1429,11 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc,
mana_gd_init_req_hdr(&req->hdr, MANA_CONFIG_VPORT_RX, req_buf_size,
sizeof(resp));
- req->hdr.req.msg_version = GDMA_MESSAGE_V2;
+ /* Request & response versions can be different.
+ * HW can handle newer msg versions, by skipping
+ * new fields.
+ */
+ req->hdr.req.msg_version = GDMA_MESSAGE_V5;
req->hdr.resp.msg_version = GDMA_MESSAGE_V2;
req->vport = apc->port_handle;
@@ -1440,8 +1447,13 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc,
req->update_indir_tab = update_tab;
req->default_rxobj = apc->default_rxobj;
- if (rx != TRI_STATE_FALSE)
+ /* Request-msg v5 requires this field */
+ req->rss_hash_types = MANA_HASH_ENABLE_SUPPORTED;
+
+ if (rx != TRI_STATE_FALSE) {
req->cqe_coalescing_enable = apc->cqe_coalescing_enable;
+ req->cqe8_coalescing_enable = apc->cqe8_coalescing_enable;
+ }
if (update_key)
memcpy(&req->hashkey, apc->hashkey, MANA_HASH_KEY_SIZE);
@@ -2046,16 +2058,14 @@ static struct sk_buff *mana_build_skb(struct mana_rxq *rxq, void *buf_va,
static void mana_rx_skb(void *buf_va, bool from_pool,
struct mana_rxcomp_oob *cqe, struct mana_rxq *rxq,
- int i)
+ u32 pkt_len, u32 pkt_hash)
{
struct mana_stats_rx *rx_stats = &rxq->stats;
struct net_device *ndev = rxq->ndev;
- uint pkt_len = cqe->ppi[i].pkt_len;
u16 rxq_idx = rxq->rxq_idx;
struct napi_struct *napi;
struct xdp_buff xdp = {};
struct sk_buff *skb;
- u32 hash_value;
u32 act;
rxq->rx_cq.work_done++;
@@ -2094,12 +2104,10 @@ static void mana_rx_skb(void *buf_va, bool from_pool,
}
if (cqe->rx_hashtype != 0 && (ndev->features & NETIF_F_RXHASH)) {
- hash_value = cqe->ppi[i].pkt_hash;
-
if (cqe->rx_hashtype & MANA_HASH_L4)
- skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L4);
+ skb_set_hash(skb, pkt_hash, PKT_HASH_TYPE_L4);
else
- skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L3);
+ skb_set_hash(skb, pkt_hash, PKT_HASH_TYPE_L3);
}
if (cqe->rx_vlantag_present) {
@@ -2240,6 +2248,43 @@ static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq,
rxoob->dma_sync_offset = dma_sync_offset;
}
+static void mana_process_one_rx_pkt(struct device *dev, struct mana_rxq *rxq,
+ struct mana_rxcomp_oob *oob,
+ u32 pktlen, u32 pkt_hash)
+{
+ struct mana_recv_buf_oob *rxbuf_oob;
+ struct net_device *ndev = rxq->ndev;
+ void *old_buf = NULL;
+ bool old_fp;
+
+ rxbuf_oob = &rxq->rx_oobs[rxq->buf_index];
+ WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
+
+ if (unlikely(pktlen > rxq->datasize)) {
+ /* Increase it even if mana_rx_skb() isn't called. */
+ rxq->rx_cq.work_done++;
+
+ ++ndev->stats.rx_dropped;
+ netdev_warn_once(ndev,
+ "Dropped oversized RX packet: len=%u, datasize=%u\n",
+ pktlen, rxq->datasize);
+
+ /* Reuse the RX buffer since rxbuf_oob is unchanged. */
+ } else {
+ mana_refill_rx_oob(dev, rxq, rxbuf_oob, pktlen,
+ &old_buf, &old_fp);
+
+ /* Unsuccessful refill will have old_buf == NULL.
+ * In this case, mana_rx_skb() will drop the packet.
+ */
+ mana_rx_skb(old_buf, old_fp, oob, rxq, pktlen, pkt_hash);
+ }
+
+ mana_move_wq_tail(rxq->gdma_rq, rxbuf_oob->wqe_inf.wqe_size_in_bu);
+
+ mana_post_pkt_rxq(rxq);
+}
+
static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
struct gdma_comp *cqe)
{
@@ -2249,10 +2294,10 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
struct mana_recv_buf_oob *rxbuf_oob;
struct mana_port_context *apc;
struct device *dev = gc->dev;
+ bool coalesced_8 = false;
bool coalesced = false;
- void *old_buf = NULL;
- u32 curr, pktlen;
- bool old_fp;
+ u32 pktlen;
+ int pkt_i;
int i;
apc = netdev_priv(ndev);
@@ -2275,6 +2320,11 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
coalesced = true;
break;
+ case CQE_RX_COALESCED_8:
+ coalesced = true;
+ coalesced_8 = true;
+ break;
+
case CQE_RX_OBJECT_FENCE:
complete(&rxq->fence_event);
return;
@@ -2286,54 +2336,48 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
return;
}
+ pkt_i = 0;
for (i = 0; i < MANA_RXCOMP_OOB_NUM_PPI; i++) {
- old_buf = NULL;
- pktlen = oob->ppi[i].pkt_len;
- if (pktlen == 0)
- break;
-
- curr = rxq->buf_index;
- rxbuf_oob = &rxq->rx_oobs[curr];
- WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
-
- if (unlikely(pktlen > rxq->datasize)) {
- /* Increase it even if mana_rx_skb() isn't called. */
- rxq->rx_cq.work_done++;
+ u32 pkt_hash;
- ++ndev->stats.rx_dropped;
- netdev_warn_once(ndev,
- "Dropped oversized RX packet: len=%u, datasize=%u\n",
- pktlen, rxq->datasize);
-
- /* Reuse the RX buffer since rxbuf_oob is unchanged. */
+ if (coalesced_8) {
+ /* 8-pkt mode: 2 packets per PPI entry */
+ pktlen = oob->ppi[i].pkt_len0;
+ pkt_hash = oob->ppi[i].pkt_hash0;
} else {
-
- mana_refill_rx_oob(dev, rxq, rxbuf_oob, pktlen,
- &old_buf, &old_fp);
-
- /* Unsuccessful refill will have old_buf == NULL.
- * In this case, mana_rx_skb() will drop the packet.
- */
- mana_rx_skb(old_buf, old_fp, oob, rxq, i);
+ pktlen = oob->ppi[i].pkt_len;
+ pkt_hash = oob->ppi[i].pkt_hash;
}
+ if (pktlen == 0)
+ break;
- mana_move_wq_tail(rxq->gdma_rq,
- rxbuf_oob->wqe_inf.wqe_size_in_bu);
-
- mana_post_pkt_rxq(rxq);
+ mana_process_one_rx_pkt(dev, rxq, oob, pktlen, pkt_hash);
+ pkt_i++;
if (!coalesced)
break;
+
+ /* Process 2nd packet from the same PPI in 8-pkt mode */
+ if (coalesced_8) {
+ pktlen = oob->ppi[i].pkt_len1;
+ pkt_hash = oob->ppi[i].pkt_hash1;
+ if (pktlen == 0)
+ break;
+
+ mana_process_one_rx_pkt(dev, rxq, oob, pktlen,
+ pkt_hash);
+ pkt_i++;
+ }
}
/* Collect coalesced CQE count based on packets processed.
- * Coalesced CQEs have at least 2 packets, so index is i - 2.
+ * Coalesced CQEs have at least 2 packets, so index is pkt_i - 2.
*/
- if (i > 1) {
+ if (pkt_i > 1) {
u64_stats_update_begin(&rxq->stats.syncp);
- rxq->stats.coalesced_cqe[i - 2]++;
+ rxq->stats.coalesced_cqe[pkt_i - 2]++;
u64_stats_update_end(&rxq->stats.syncp);
- } else if (!i && !pktlen) {
+ } else if (!pkt_i && !pktlen) {
u64_stats_update_begin(&rxq->stats.syncp);
rxq->stats.pkt_len0_err++;
u64_stats_update_end(&rxq->stats.syncp);
@@ -3763,6 +3807,7 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
apc->port_idx = port_idx;
apc->link_cfg_error = 1;
apc->cqe_coalescing_enable = 0;
+ apc->cqe8_coalescing_enable = 0;
/* Initialize interrupt moderation settings if supported by HW */
if (gc->pf_cap_flags1 & GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION) {
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 9e31e2595ae3..8743f7edecbb 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -169,7 +169,7 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
ethtool_sprintf(&data, "rx_%d_xdp_tx", i);
ethtool_sprintf(&data, "rx_%d_xdp_redirect", i);
ethtool_sprintf(&data, "rx_%d_pkt_len0_err", i);
- for (j = 0; j < MANA_RXCOMP_OOB_NUM_PPI - 1; j++)
+ for (j = 0; j < MANA_CQE_COAL_PKTS_8 - 1; j++)
ethtool_sprintf(&data, "rx_%d_coalesced_cqe_%d", i, j + 2);
}
@@ -205,7 +205,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
u64 xdp_drop;
u64 xdp_tx;
u64 pkt_len0_err;
- u64 coalesced_cqe[MANA_RXCOMP_OOB_NUM_PPI - 1];
+ u64 coalesced_cqe[MANA_CQE_COAL_PKTS_8 - 1];
u64 tso_packets;
u64 tso_bytes;
u64 tso_inner_packets;
@@ -245,7 +245,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
xdp_tx = rx_stats->xdp_tx;
xdp_redirect = rx_stats->xdp_redirect;
pkt_len0_err = rx_stats->pkt_len0_err;
- for (j = 0; j < MANA_RXCOMP_OOB_NUM_PPI - 1; j++)
+ for (j = 0; j < MANA_CQE_COAL_PKTS_8 - 1; j++)
coalesced_cqe[j] = rx_stats->coalesced_cqe[j];
} while (u64_stats_fetch_retry(&rx_stats->syncp, start));
@@ -255,7 +255,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
data[i++] = xdp_tx;
data[i++] = xdp_redirect;
data[i++] = pkt_len0_err;
- for (j = 0; j < MANA_RXCOMP_OOB_NUM_PPI - 1; j++)
+ for (j = 0; j < MANA_CQE_COAL_PKTS_8 - 1; j++)
data[i++] = coalesced_cqe[j];
}
@@ -408,6 +408,7 @@ static int mana_get_coalesce(struct net_device *ndev,
struct mana_port_context *apc = netdev_priv(ndev);
kernel_coal->rx_cqe_frames =
+ apc->cqe8_coalescing_enable ? MANA_CQE_COAL_PKTS_8 :
apc->cqe_coalescing_enable ? MANA_RXCOMP_OOB_NUM_PPI : 1;
kernel_coal->rx_cqe_nsecs = apc->cqe_coalescing_timeout_ns;
@@ -443,6 +444,7 @@ static int mana_set_coalesce(struct net_device *ndev,
u16 intr_modr_tx_usec;
u16 intr_modr_tx_comp;
u8 cqe_coalescing_enable;
+ u8 cqe8_coalescing_enable;
bool rx_dim_enabled;
bool tx_dim_enabled;
} saved;
@@ -466,10 +468,12 @@ static int mana_set_coalesce(struct net_device *ndev,
}
if (kernel_coal->rx_cqe_frames != 1 &&
- kernel_coal->rx_cqe_frames != MANA_RXCOMP_OOB_NUM_PPI) {
+ kernel_coal->rx_cqe_frames != MANA_RXCOMP_OOB_NUM_PPI &&
+ kernel_coal->rx_cqe_frames != MANA_CQE_COAL_PKTS_8) {
NL_SET_ERR_MSG_FMT(extack,
- "rx-frames must be 1 or %u, got %u",
+ "rx-frames must be 1, %u, or %u, got %u",
MANA_RXCOMP_OOB_NUM_PPI,
+ MANA_CQE_COAL_PKTS_8,
kernel_coal->rx_cqe_frames);
return -EINVAL;
}
@@ -514,8 +518,15 @@ static int mana_set_coalesce(struct net_device *ndev,
saved.tx_dim_enabled = apc->tx_dim_enabled;
saved.cqe_coalescing_enable = apc->cqe_coalescing_enable;
+ saved.cqe8_coalescing_enable = apc->cqe8_coalescing_enable;
apc->cqe_coalescing_enable =
- kernel_coal->rx_cqe_frames == MANA_RXCOMP_OOB_NUM_PPI;
+ kernel_coal->rx_cqe_frames >= MANA_RXCOMP_OOB_NUM_PPI;
+
+ if (gc->cqe8_coalescing_sup)
+ apc->cqe8_coalescing_enable =
+ kernel_coal->rx_cqe_frames == MANA_CQE_COAL_PKTS_8;
+ else if (kernel_coal->rx_cqe_frames == MANA_CQE_COAL_PKTS_8)
+ netdev_info(ndev, "Fall back to RX-CQE x4 coalescing\n");
if (!apc->port_is_up) {
WRITE_ONCE(apc->rx_dim_enabled, !!ec->use_adaptive_rx_coalesce);
@@ -523,7 +534,8 @@ static int mana_set_coalesce(struct net_device *ndev,
return 0;
}
- if (apc->cqe_coalescing_enable != saved.cqe_coalescing_enable) {
+ if (apc->cqe_coalescing_enable != saved.cqe_coalescing_enable ||
+ apc->cqe8_coalescing_enable != saved.cqe8_coalescing_enable) {
/* CQE coalescing setting is applied via RSS configuration. */
err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
if (err) {
@@ -531,6 +543,8 @@ static int mana_set_coalesce(struct net_device *ndev,
err);
apc->cqe_coalescing_enable =
saved.cqe_coalescing_enable;
+ apc->cqe8_coalescing_enable =
+ saved.cqe8_coalescing_enable;
apc->intr_modr_rx_usec = saved.intr_modr_rx_usec;
apc->intr_modr_rx_comp = saved.intr_modr_rx_comp;
apc->intr_modr_tx_usec = saved.intr_modr_tx_usec;
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 8529cef0d7c4..70a7f1fee5d3 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -182,6 +182,7 @@ struct gdma_general_req {
#define GDMA_MESSAGE_V2 2
#define GDMA_MESSAGE_V3 3
#define GDMA_MESSAGE_V4 4
+#define GDMA_MESSAGE_V5 5
struct gdma_general_resp {
struct gdma_resp_hdr hdr;
@@ -428,6 +429,9 @@ struct gdma_context {
/* L2 MTU */
u16 adapter_mtu;
+ /* NIC supports CQE x8 coalescing */
+ bool cqe8_coalescing_sup;
+
/* This maps a CQ index to the queue structure. */
unsigned int max_num_cqs;
struct gdma_queue **cq_table;
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 4d041fb8437f..3ca1399a2faf 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -62,9 +62,12 @@ enum TRI_STATE {
#define MAX_PORTS_IN_MANA_DEV 256
-/* Maximum number of packets per coalesced CQE */
+/* Maximum number of PPIs per coalesced CQE */
#define MANA_RXCOMP_OOB_NUM_PPI 4
+/* 8-pkt mode packs up to 2 packets per PPI entry */
+#define MANA_CQE_COAL_PKTS_8 8
+
/* Default/max interrupt moderation settings */
#define MANA_INTR_MODR_USEC_DEF 0
#define MANA_INTR_MODR_COMP_DEF 0
@@ -79,7 +82,7 @@ enum TRI_STATE {
#define MANA_INTR_MODR_COMP_MASK GENMASK(23, 16)
/* Update this count whenever the respective structures are changed */
-#define MANA_STATS_RX_COUNT (6 + MANA_RXCOMP_OOB_NUM_PPI - 1)
+#define MANA_STATS_RX_COUNT (6 + MANA_CQE_COAL_PKTS_8 - 1)
#define MANA_STATS_TX_COUNT 11
#define MANA_RX_FRAG_ALIGNMENT 64
@@ -91,7 +94,7 @@ struct mana_stats_rx {
u64 xdp_tx;
u64 xdp_redirect;
u64 pkt_len0_err;
- u64 coalesced_cqe[MANA_RXCOMP_OOB_NUM_PPI - 1];
+ u64 coalesced_cqe[MANA_CQE_COAL_PKTS_8 - 1];
struct u64_stats_sync syncp;
};
@@ -202,6 +205,7 @@ enum mana_cqe_type {
CQE_RX_COALESCED_4 = 2,
CQE_RX_OBJECT_FENCE = 3,
CQE_RX_TRUNCATED = 4,
+ CQE_RX_COALESCED_8 = 7,
CQE_TX_OKAY = 32,
CQE_TX_SA_DROP = 33,
@@ -238,12 +242,25 @@ struct mana_cqe_header {
#define MANA_HASH_L4 \
(NDIS_HASH_TCP_IPV4 | NDIS_HASH_UDP_IPV4 | NDIS_HASH_TCP_IPV6 | \
NDIS_HASH_UDP_IPV6 | NDIS_HASH_TCP_IPV6_EX | NDIS_HASH_UDP_IPV6_EX)
+#define MANA_HASH_ENABLE_SUPPORTED \
+ (NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 | NDIS_HASH_UDP_IPV4 | \
+ NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6 | NDIS_HASH_UDP_IPV6)
+
+union mana_rxcomp_perpkt_info {
+ struct {
+ u32 pkt_len : 16;
+ u32 reserved1 : 16;
+ u32 reserved2;
+ u32 pkt_hash;
+ };
-struct mana_rxcomp_perpkt_info {
- u32 pkt_len : 16;
- u32 reserved1 : 16;
- u32 reserved2;
- u32 pkt_hash;
+ /* Up to two pkts per PPI entry */
+ struct {
+ u32 pkt_hash0;
+ u16 pkt_len0;
+ u16 pkt_len1;
+ u32 pkt_hash1;
+ };
}; /* HW DATA */
/* Receive completion OOB */
@@ -264,7 +281,7 @@ struct mana_rxcomp_oob {
u32 rx_udp_csum_fail : 1;
u32 reserved2 : 1;
- struct mana_rxcomp_perpkt_info ppi[MANA_RXCOMP_OOB_NUM_PPI];
+ union mana_rxcomp_perpkt_info ppi[MANA_RXCOMP_OOB_NUM_PPI];
u32 rx_wqe_offset;
}; /* HW DATA */
@@ -607,6 +624,7 @@ struct mana_port_context {
bool port_st_save; /* Saved port state */
u8 cqe_coalescing_enable;
+ u8 cqe8_coalescing_enable;
u32 cqe_coalescing_timeout_ns;
/* Interrupt moderation settings */
@@ -751,6 +769,8 @@ struct mana_query_device_cfg_req {
u32 reserved;
}; /* HW DATA */
+#define MANA_PF_FLAG_1_CQE_8_COALESCING_SUPPORTED BIT(5)
+
struct mana_query_device_cfg_resp {
struct gdma_resp_hdr hdr;
@@ -986,7 +1006,10 @@ struct mana_cfg_rx_steer_req_v2 {
mana_handle_t default_rxobj;
u8 hashkey[MANA_HASH_KEY_SIZE];
u8 cqe_coalescing_enable;
- u8 reserved2[7];
+ u8 reserved2[3];
+ u16 rss_hash_types;
+ u8 cqe8_coalescing_enable; /* v5 message */
+ u8 reserved3;
mana_handle_t indir_tab[] __counted_by(num_indir_entries);
}; /* HW DATA */
--
2.34.1
^ permalink raw reply related
* [PATCH] x86/hyperv: reserve more vectors
From: wei.liu @ 2026-07-30 0:50 UTC (permalink / raw)
To: Linux on Hyper-V List
Cc: mukeshrathor, Wei Liu, K. Y. Srinivasan, Haiyang Zhang,
Dexuan Cui, Long Li, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen,
maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT), H. Peter Anvin,
open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)
From: Wei Liu <wei.liu@kernel.org>
Microsoft Hypervisor delivers three vectors to the NT HAL running in the
root partition and refuses to map a device interrupt to any of them when
interrupt remapping is not available in the system. As of writing, the
nested MSHV setup has no interrupt remapping capability.
The three vectors are:
HAL_NT_APC_VECTOR 0x1F
HAL_NT_DPC_VECTOR 0x2F
HAL_NT_CLOCK_IPI_VECTOR 0xD2
0x1F is below FIRST_EXTERNAL_VECTOR so the vector allocator never hands
it out, but 0x2F and 0xD2 are both inside the allocatable range and are
handed out once enough vectors are in use. Mapping such an interrupt
then fails with HV_STATUS_INVALID_PARAMETER, and the interrupt is never
delivered.
Reserve all three next to the hypervisor debug vectors that are already
kept out of the allocator's hands.
Signed-off-by: Wei Liu <wei.liu@kernel.org>
---
arch/x86/kernel/cpu/mshyperv.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 185d4f677ec0..229c7377a980 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -502,17 +502,32 @@ static void hv_reserve_irq_vectors(void)
#define HYPERV_DBG_ASSERT_VECTOR 0x2C
#define HYPERV_DBG_SERVICE_VECTOR 0x2D
+ /*
+ * The hypervisor delivers these three to the NT HAL and refuses to
+ * map a device interrupt to any of them.
+ *
+ * The hypervisor will provide a hint in the future when these
+ * vectors become available to use.
+ */
+ #define HAL_NT_APC_VECTOR 0x1F
+ #define HAL_NT_DPC_VECTOR 0x2F
+ #define HAL_NT_CLOCK_IPI_VECTOR 0xD2
+
if (cpu_feature_enabled(X86_FEATURE_FRED))
return;
if (test_and_set_bit(HYPERV_DBG_ASSERT_VECTOR, system_vectors) ||
test_and_set_bit(HYPERV_DBG_SERVICE_VECTOR, system_vectors) ||
- test_and_set_bit(HYPERV_DBG_FASTFAIL_VECTOR, system_vectors))
+ test_and_set_bit(HYPERV_DBG_FASTFAIL_VECTOR, system_vectors) ||
+ test_and_set_bit(HAL_NT_APC_VECTOR, system_vectors) ||
+ test_and_set_bit(HAL_NT_DPC_VECTOR, system_vectors) ||
+ test_and_set_bit(HAL_NT_CLOCK_IPI_VECTOR, system_vectors))
BUG();
- pr_info("Hyper-V: reserve vectors: 0x%x 0x%x 0x%x\n",
+ pr_info("Hyper-V: reserve vectors: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
HYPERV_DBG_ASSERT_VECTOR, HYPERV_DBG_SERVICE_VECTOR,
- HYPERV_DBG_FASTFAIL_VECTOR);
+ HYPERV_DBG_FASTFAIL_VECTOR, HAL_NT_APC_VECTOR,
+ HAL_NT_DPC_VECTOR, HAL_NT_CLOCK_IPI_VECTOR);
}
static void __init ms_hyperv_init_platform(void)
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net v2] net: mana: Return error code from mana_create_rxq()
From: patchwork-bot+netdevbpf @ 2026-07-30 1:00 UTC (permalink / raw)
To: Aditya Garg
Cc: kys, haiyangz, wei.liu, decui, longli, andrew+netdev, davem,
edumazet, kuba, pabeni, ernis, horms, dipayanroy, shacharr,
stephen, linux-hyperv, netdev, linux-kernel, ssengar, gargaditya
In-Reply-To: <20260727113759.2881500-1-gargaditya@linux.microsoft.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Mon, 27 Jul 2026 04:37:59 -0700 you wrote:
> mana_create_rxq() returns a struct mana_rxq pointer and returns NULL on
> any failure. The caller, mana_add_rx_queues(), cannot tell what went
> wrong and hardcodes the error as -ENOMEM. As a result the actual failure
> reported by the lower layers (for example -EPROTO from a failed HW
> request) is masked and every RX queue creation failure looks like an
> out-of-memory error.
>
> [...]
Here is the summary with links:
- [net,v2] net: mana: Return error code from mana_create_rxq()
https://git.kernel.org/netdev/net/c/e67cc80b50f5
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] x86/hyperv: reserve more vectors
From: sashiko-bot @ 2026-07-30 1:25 UTC (permalink / raw)
To: wei.liu; +Cc: linux-hyperv
In-Reply-To: <20260730005020.2181875-1-wei.liu@kernel.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The patch fails to resolve the interrupt mapping failure on systems with X86_FEATURE_FRED enabled because an early return bypasses the newly added vector reservations.
--
--- Patch [1]: [PATCH] x86/hyperv: reserve more vectors ---
commit b0d2bc1fc2c7327b5574f796990f799e59f429b9
Author: Wei Liu <wei.liu@kernel.org>
x86/hyperv: reserve more vectors
This commit reserves three additional vectors used by the Microsoft
Hypervisor to prevent the kernel vector allocator from mapping device
interrupts to them when interrupt remapping is unavailable.
> diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
> --- a/arch/x86/kernel/cpu/mshyperv.c
> +++ b/arch/x86/kernel/cpu/mshyperv.c
> @@ -502,17 +502,32 @@ static void hv_reserve_irq_vectors(void)
[ ... ]
> if (cpu_feature_enabled(X86_FEATURE_FRED))
> return;
>
> if (test_and_set_bit(HYPERV_DBG_ASSERT_VECTOR, system_vectors) ||
> test_and_set_bit(HYPERV_DBG_SERVICE_VECTOR, system_vectors) ||
> - test_and_set_bit(HYPERV_DBG_FASTFAIL_VECTOR, system_vectors))
> + test_and_set_bit(HYPERV_DBG_FASTFAIL_VECTOR, system_vectors) ||
> + test_and_set_bit(HAL_NT_APC_VECTOR, system_vectors) ||
> + test_and_set_bit(HAL_NT_DPC_VECTOR, system_vectors) ||
> + test_and_set_bit(HAL_NT_CLOCK_IPI_VECTOR, system_vectors))
> BUG();
[Severity: High]
This is a pre-existing issue, but does placing these new vector reservations
after the FRED early return cause them to be bypassed on FRED-enabled
hardware?
Since the early return skips updating the system_vectors bitmap, vectors
0x2F and 0xD2 won't be reserved when X86_FEATURE_FRED is enabled.
Because the kernel's dynamic vector allocator still relies on the
system_vectors bitmap to avoid assigning device interrupts, won't the
allocator still hand these vectors out to drivers on FRED-enabled systems
and reproduce the mapping failure?
> - pr_info("Hyper-V: reserve vectors: 0x%x 0x%x 0x%x\n",
> + pr_info("Hyper-V: reserve vectors: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
> HYPERV_DBG_ASSERT_VECTOR, HYPERV_DBG_SERVICE_VECTOR,
> - HYPERV_DBG_FASTFAIL_VECTOR);
> + HYPERV_DBG_FASTFAIL_VECTOR, HAL_NT_APC_VECTOR,
> + HAL_NT_DPC_VECTOR, HAL_NT_CLOCK_IPI_VECTOR);
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730005020.2181875-1-wei.liu@kernel.org?part=1
^ permalink raw reply
* Re: [PATCH net-next v13 2/2] net: mana: force full-page RX buffers via ethtool private flag
From: sashiko-bot @ 2026-07-30 6:34 UTC (permalink / raw)
To: Dipayaan Roy; +Cc: bpf, linux-hyperv
In-Reply-To: <20260729063347.3388035-3-dipayanroy@linux.microsoft.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Use-after-free of BPF program when mana_pre_alloc_rxbufs fails during XDP setup
--
--- Patch [2]: [PATCH net-next v13 2/2] net: mana: force full-page RX buffers via ethtool private flag ---
commit 2ea505589c71d255969461add82f06436f8f8e80
Author: Dipayaan Roy <dipayanroy@linux.microsoft.com>
net: mana: force full-page RX buffers via ethtool private flag
This commit adds an ethtool private flag to force one RX buffer per page,
bypassing the page_pool fragment path. This is intended to restore
line-rate throughput on certain ARM64 platforms with 4K PAGE_SIZE.
> diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
> index 482cd16009abb..7e441d6ae5dce 100644
> --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
> +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
[ ... ]
> @@ -756,6 +775,78 @@ static int mana_get_link_ksettings(struct net_device *ndev,
[ ... ]
> +static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags)
> +{
[ ... ]
> + if (changed & BIT(MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF)) {
[ ... ]
> + err = mana_pre_alloc_rxbufs(apc, ndev->mtu, apc->num_queues);
> + if (err) {
> + netdev_err(ndev,
> + "Insufficient memory for new allocations\n");
> + apc->priv_flags = old_priv_flags;
> + goto clear_flag;
> + }
[Severity: High]
This isn't a bug introduced by this patch, but while reviewing the callers
of mana_pre_alloc_rxbufs(), does a failure during XDP setup leave a dangling
pointer?
In drivers/net/ethernet/microsoft/mana/mana_bpf.c:mana_xdp_set(),
apc->bpf_prog is updated before the allocation:
apc->bpf_prog = prog;
If the allocation fails, the function returns early without cleaning up:
err = mana_pre_alloc_rxbufs(apc, ndev->mtu, apc->num_queues);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"XDP: Insufficient memory ...");
return err;
}
The core network stack handles the error by releasing its reference to the
new BPF program, which may then be freed. Because the early return skips
the err_dealloc_rxbuffs label, apc->bpf_prog is never reverted to old_prog.
Could a subsequent interface flap execute mana_attach() and assign this
freed BPF program to the hardware RX queues, causing a use-after-free?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260729063347.3388035-1-dipayanroy@linux.microsoft.com?part=2
^ permalink raw reply
* Re: [PATCH 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
From: Naman Jain @ 2026-07-30 11:26 UTC (permalink / raw)
To: sashiko-reviews; +Cc: linux-pci, linux-hyperv
In-Reply-To: <20260728140324.690D11F000E9@smtp.kernel.org>
On 7/28/2026 7:33 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] The patch replaces the direct invocation of the outermost chip's irq_retrigger() callback with irq_chip_retrigger_hierarchy(). However, irq_chip_retrigger_hierarchy() initializes its loop with `data = data->parent_data`, completely skipping the outermost chip. This breaks interrupt retriggering for flat domains (like native lapic_controller) and any hierarchical domain where the outermost chip directly implements the retrigger callback.
> --
>
> --- Patch [2]: [PATCH 2/3] x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs() ---
> commit f97e883de2f6626561de48c426194caa41c3e062
> Author: Naman Jain <namjain@linux.microsoft.com>
> x86/irq: Use irq_chip_retrigger_hierarchy() in fixup_irqs()
>
> This commit modifies fixup_irqs() to use irq_chip_retrigger_hierarchy()
> instead of invoking the outermost domain chip's irq_retrigger() callback
> directly. It also refactors the loop to use scoped guards for the irq
> descriptor lock.
>
>> diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
>> index 30122f0b3af96..ef1bdd3c4659a 100644
>> --- a/arch/x86/kernel/irq.c
>> +++ b/arch/x86/kernel/irq.c
> [ ... ]
>> @@ -489,22 +484,18 @@ void fixup_irqs(void)
> [ ... ]
>> - for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
>> - if (IS_ERR_OR_NULL(__this_cpu_read(vector_irq[vector])))
>> + for (unsigned int vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
>> + struct irq_desc *desc = __this_cpu_read(vector_irq[vector]);
>> +
>> + if (IS_ERR_OR_NULL(desc))
>> continue;
>>
>> if (is_vector_pending(vector)) {
>> - desc = __this_cpu_read(vector_irq[vector]);
>> -
>> - raw_spin_lock(&desc->lock);
>> - data = irq_desc_get_irq_data(desc);
>> - chip = irq_data_get_irq_chip(data);
>> - if (chip->irq_retrigger) {
>> - chip->irq_retrigger(data);
>> + guard(raw_spinlock)(&desc->lock);
>> + if (irq_chip_retrigger_hierarchy(&desc->irq_data))
> [Severity: High]
> Will this skip the outermost chip and cause a regression for flat domains?
>
> Looking at kernel/irq/chip.c:irq_chip_retrigger_hierarchy(), the loop
> initializes by immediately moving to the parent_data:
>
> int irq_chip_retrigger_hierarchy(struct irq_data *data)
> {
> for (data = data->parent_data; data; data = data->parent_data)
> if (data->chip && data->chip->irq_retrigger)
> return data->chip->irq_retrigger(data);
>
> return 0;
> }
>
> By passing &desc->irq_data directly to this function, it seems any retrigger
> callback on the outermost chip itself will be bypassed.
>
> Could this lead to dropped hardware interrupts during CPU hot-unplug for
> flat domains (like native lapic_controller) or any hierarchical domain where
> the outermost chip implements the retrigger callback?
>
>> __this_cpu_write(vector_irq[vector], VECTOR_RETRIGGERED);
>> - }
>> - raw_spin_unlock(&desc->lock);
>> }
>
I think this is a false positive, considering we are not changing the
behavior for any of the existing chip->irq_retrigger(data) which come in
this path (irq_chip_retrigger_hierarchy()).
Regards,
Naman
^ permalink raw reply
* Re: [PATCH 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
From: Naman Jain @ 2026-07-30 11:26 UTC (permalink / raw)
To: sashiko-reviews; +Cc: linux-pci, linux-hyperv
In-Reply-To: <20260728140427.714311F000E9@smtp.kernel.org>
On 7/28/2026 7:34 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] The fix for dropped pending interrupts during CPU hot-unplug was missed in the sister Hyper-V root partition MSI domain.
> --
>
> --- Patch [1]: [PATCH 1/3] PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip ---
> commit b8b1c843c457dd145f0d360b44f4b1bf34bd8cf5
> Author: Naman Jain <namjain@linux.microsoft.com>
>
> PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
>
> The Hyper-V vPCI MSI irqchip never installs an irq_retrigger() callback.
> On CPU hot-unplug fixup_irqs() migrates the interrupts which are affine to
> the outgoing CPU to a new target. As the Hyper-V PCI/MSI chip does not
> provide that callback, the pending interrupt is silently dropped, which
> can result in lost interrupts, stalls and "No irq handler for vector"
> messages.
>
> Fixes: 4daace0d8ce85 ("PCI: hv: Add paravirtual PCI front-end for Microsoft Hyper-V VMs")
> Cc: stable@vger.kernel.org
> Suggested-by: Long Li <longli@microsoft.com>
> Suggested-by: Thomas Gleixner <tglx@kernel.org>
> Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
>
>> diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
>> index cfc8fa403dad6..89816a2bd7cd3 100644
>> --- a/drivers/pci/controller/pci-hyperv.c
>> +++ b/drivers/pci/controller/pci-hyperv.c
>> @@ -2119,6 +2119,7 @@ static bool hv_pcie_init_dev_msi_info(struct device *dev, struct irq_domain *dom
>> info->ops->msi_prepare = hv_msi_prepare;
>>
>> chip->irq_set_affinity = irq_chip_set_affinity_parent;
>> + chip->irq_retrigger = irq_chip_retrigger_hierarchy;
>
> [Severity: High]
> This isn't a bug introduced by this patch, but does the sister Hyper-V root
> partition MSI domain in arch/x86/hyperv/irqdomain.c also need this fix?
>
> Looking at hv_init_dev_msi_info(), it appears to be missing the exact same
> callback initialization for the root partition's top-level irq_chip:
>
> arch/x86/hyperv/irqdomain.c:hv_init_dev_msi_info() {
> ...
> if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
> return false;
>
> chip->flags |= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MOVE_DEFERRED;
>
> info->ops->msi_prepare = pci_msi_prepare;
>
> return true;
> }
>
> If a CPU is hot-unplugged while a device MSI interrupt is pending in its
> local APIC IRR, could fixup_irqs() fail to resend the pending interrupt
> to the new target CPU because this callback is NULL?
>
> This could potentially lead to the same lost interrupts and I/O stalls
> described in this commit message, just in the root partition MSI domain
> instead of the guest paravirtual MSI domain.
>
>>
>> if (IS_ENABLED(CONFIG_X86))
>> chip->flags |= IRQCHIP_MOVE_DEFERRED;
>>
>
I am not planning to include this in this series, since this issue is
not seen in root partition yet and I am not sure if it is applicable
here. Second patch would anyways fix it going forward, but I am OK
adding the change for this, if we need.
Regards,
Naman
^ permalink raw reply
* Re: [PATCH net-next] net: mana: Extend RX CQE coalescing up to 8 packets
From: Joe Damato @ 2026-07-30 15:54 UTC (permalink / raw)
To: Haiyang Zhang
Cc: linux-hyperv, netdev, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Konstantin Taranov, Simon Horman,
Erni Sri Satya Vennela, Dipayaan Roy, Aditya Garg, Breno Leitao,
linux-kernel, linux-rdma, paulros
In-Reply-To: <20260729225235.3573786-1-haiyangz@linux.microsoft.com>
On Wed, Jul 29, 2026 at 03:52:22PM -0700, Haiyang Zhang wrote:
> From: Haiyang Zhang <haiyangz@microsoft.com>
>
> To support up to 8 packets per CQE, put two packet lengths and
> hash values into one PPI entry by using the reserved fields.
> Update ethtool handlers to set this feature.
> Update per queue stat to show the coalesced CQE counters.
> This feature is supported on NIC hardware showing the relevant
> PF flag.
>
> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> ---
> drivers/net/ethernet/microsoft/mana/mana_en.c | 137 ++++++++++++------
> .../ethernet/microsoft/mana/mana_ethtool.c | 30 +++-
> include/net/mana/gdma.h | 4 +
> include/net/mana/mana.h | 43 ++++--
> 4 files changed, 150 insertions(+), 64 deletions(-)
>
> diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
> index a8c329bdbacf..720d22e6aea9 100644
> --- a/drivers/net/ethernet/microsoft/mana/mana_en.c
> +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
> @@ -1241,6 +1241,9 @@ int mana_gd_query_device_cfg(struct gdma_context *gc, u32 proto_major_ver,
[...]
>
> +static void mana_process_one_rx_pkt(struct device *dev, struct mana_rxq *rxq,
> + struct mana_rxcomp_oob *oob,
> + u32 pktlen, u32 pkt_hash)
> +{
> + struct mana_recv_buf_oob *rxbuf_oob;
> + struct net_device *ndev = rxq->ndev;
> + void *old_buf = NULL;
> + bool old_fp;
> +
> + rxbuf_oob = &rxq->rx_oobs[rxq->buf_index];
> + WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
> +
> + if (unlikely(pktlen > rxq->datasize)) {
> + /* Increase it even if mana_rx_skb() isn't called. */
> + rxq->rx_cq.work_done++;
> +
> + ++ndev->stats.rx_dropped;
It looks like this code was moved from mana_process_rx_cqe, so this is prob
out of scope, but I saw this and was wondering if maybe rx_length_errors is more
appropriate?
from if_link.h:
* @rx_length_errors: Number of packets dropped due to invalid length.
* Part of aggregate "frame" errors in `/proc/net/dev`.
^ permalink raw reply
page: | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox