* [PATCH net v3] net: mana: Add support to process throttled EQEs
@ 2026-10-22 14:53 Sahil Chandna
2026-10-22 19:42 ` Haiyang Zhang
2026-10-26 15:25 ` netdev-bot+sashiko
0 siblings, 2 replies; 4+ messages in thread
From: Sahil Chandna @ 2026-10-22 14:53 UTC (permalink / raw)
To: haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet, kuba,
pabeni, kotaranov, horms, ernis, gargaditya, mawasthi, leitao,
linux-hyperv, netdev, linux-kernel, linux-rdma
Cc: stable
When an event queue nears full, the hardware coalesces the per-CQ
GDMA_EQE_COMPLETION notifications into a single throttle EQE (type 4)
that carries no cq_id. The driver does not handle this event type, so
it falls through to the default case and is dropped. Any CQ whose
completion notification was replaced by the throttle EQE can remain
unserviced, causing its queue to stall.
The issue was observed internally and following Tx stall logs were
seen:
2026-10-03T05:29:01 hv_netvsc eth0: VF slot 0 removed
2026-10-03T05:29:23 mana 7870:00:00.0 ens1: NETDEV WATCHDOG: CPU: 45:
transmit queue 1 timed out 15133 ms
2026-10-03T05:31:05 mana 7870:00:00.0: HWC: Request timed out: 60000 ms
2026-10-03T05:31:05 mana 7870:00:00.0: Gf stats wk handler: gf stats
query timed out.
2026-10-03T05:31:21 ens1: NETDEV WATCHDOG: CPU: 20: transmit queue 0
timed out 15859 ms
2026-10-03T05:31:37 ens1: NETDEV WATCHDOG: CPU: 15: transmit queue 0
timed out 31731 ms
2026-10-03T05:31:53 ens1: NETDEV WATCHDOG: CPU: 21: transmit queue 0
timed out 47603 ms
2026-10-03T05:32:08 ens1: NETDEV WATCHDOG: CPU: 42: transmit queue 0
timed out 62451 ms
Add support to process the CQs which belong to a throttled EQE of type 4
advertise the capability bit, also add a counter to store the throttled
EQEs count.
Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
Cc: stable@vger.kernel.org
Signed-off-by: Sahil Chandna <sahilchandna@linux.microsoft.com>
---
Changes in v3:
- Resolve race for cq in mana_gd_destroy_cq and irq handler using cq.
- Rebase to net branch
Link to v2: https://lore.kernel.org/all/20261014134304.4177657-1-sahilchandna@linux.microsoft.com/
Changes in v2:
- Use WRITE_ONCE() when clearing max_num_cqs and add RCU
grace period wait during HWC teardown.
- Use synchronize_net() during CQ destroy only when the CQ was
attached to its parent EQ.
- Use WRITE_ONCE() and READ_ONCE() for the throttle-event counter.
- Add Fixes tag and net instead of net-next.
- Fix commit message to describe capability bit and counter.
Link to v1: https://lore.kernel.org/all/20261008083315.306076-1-sahilchandna@linux.microsoft.com/
.../net/ethernet/microsoft/mana/gdma_main.c | 62 +++++++++++++++++--
.../net/ethernet/microsoft/mana/hw_channel.c | 6 +-
.../ethernet/microsoft/mana/mana_ethtool.c | 9 +++
include/net/mana/gdma.h | 12 +++-
include/net/mana/mana.h | 1 +
5 files changed, 81 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 8e9bfc1d6a2a..d74ed00bb783 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -904,6 +904,27 @@ ssize_t mana_gd_read_ring(struct gdma_queue *q, char __user *buf,
return copied;
}
+static void mana_gd_schedule_eq_cqs(struct gdma_queue *eq)
+{
+ struct gdma_context *gc = eq->gdma_dev->gdma_context;
+ struct gdma_queue *cq;
+ u8 i;
+
+ for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
+ cq = rcu_dereference(eq->eq.child_cq[i]);
+
+ if (!cq)
+ continue;
+
+ if (cq->id >= READ_ONCE(gc->max_num_cqs) ||
+ !gc->cq_table || gc->cq_table[cq->id] != cq)
+ continue;
+
+ if (cq->cq.callback)
+ cq->cq.callback(cq->cq.context, cq);
+ }
+}
+
static void mana_gd_process_eqe(struct gdma_queue *eq)
{
u32 head = eq->head % (eq->queue_size / GDMA_EQE_SIZE);
@@ -934,6 +955,11 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)
break;
+ case GDMA_EQE_THROTTLE:
+ WRITE_ONCE(eq->eq.throttle_count, eq->eq.throttle_count + 1);
+ mana_gd_schedule_eq_cqs(eq);
+ break;
+
case GDMA_EQE_TEST_EVENT:
gc->test_event_eq_id = eq->id;
complete(&gc->eq_test_event);
@@ -1220,25 +1246,49 @@ static void mana_gd_create_cq(const struct gdma_queue_spec *spec,
struct gdma_queue *queue)
{
u32 log2_num_entries = ilog2(spec->queue_size / GDMA_CQE_SIZE);
+ struct gdma_queue *parent;
+ u8 i;
queue->head |= INITIALIZED_OWNER_BIT(log2_num_entries);
- queue->cq.parent = spec->cq.parent_eq;
+ parent = spec->cq.parent_eq;
+ queue->cq.parent = parent;
queue->cq.context = spec->cq.context;
queue->cq.callback = spec->cq.callback;
+
+ if (!parent)
+ return;
+
+ /* For throttled EQE store the child CQ */
+ for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++)
+ if (!rcu_access_pointer(parent->eq.child_cq[i])) {
+ rcu_assign_pointer(parent->eq.child_cq[i], queue);
+ return;
+ }
}
static void mana_gd_destroy_cq(struct gdma_context *gc,
struct gdma_queue *queue)
{
+ struct gdma_queue *eq = queue->cq.parent;
+ bool attached = false;
u32 id = queue->id;
+ u8 i;
- if (id >= gc->max_num_cqs)
- return;
+ if (eq) {
+ for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
+ if (rcu_access_pointer(eq->eq.child_cq[i]) == queue) {
+ RCU_INIT_POINTER(eq->eq.child_cq[i], NULL);
+ attached = true;
+ }
+ }
+ }
- if (!gc->cq_table[id])
- return;
+ if (id < gc->max_num_cqs && READ_ONCE(gc->cq_table[id]))
+ WRITE_ONCE(gc->cq_table[id], NULL);
- gc->cq_table[id] = NULL;
+ /* Wait for irq reader holding the cq */
+ if (attached)
+ synchronize_net();
}
int mana_gd_create_hwc_queue(struct gdma_dev *gd,
diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index 263e7c4e2934..10eeaa40dc5f 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -364,7 +364,7 @@ static void mana_hwc_comp_event(void *ctx, struct gdma_queue *q_self)
completions = hwc_cq->comp_buf;
comp_read = mana_gd_poll_cq(q_self, completions, hwc_cq->queue_depth);
- WARN_ON_ONCE(comp_read <= 0 || comp_read > hwc_cq->queue_depth);
+ WARN_ON_ONCE(comp_read < 0 || comp_read > hwc_cq->queue_depth);
for (i = 0; i < comp_read; ++i) {
comp_data = *(struct hwc_rx_oob *)completions[i].cqe_data;
@@ -820,9 +820,11 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
*/
if (gc->max_num_cqs > 0) {
mana_smc_teardown_hwc(&gc->shm_channel, false);
- gc->max_num_cqs = 0;
+ WRITE_ONCE(gc->max_num_cqs, 0);
}
+ synchronize_rcu();
+
if (hwc->txq)
mana_hwc_destroy_wq(hwc, hwc->txq);
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 33db79569d3b..bc1db86acf64 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -22,6 +22,8 @@ static const struct mana_stats_desc mana_eth_stats[] = {
tx_linear_pkt_cnt)},
{"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
rx_cqe_unknown_type)},
+ {"eq_throttle_events", offsetof(struct mana_ethtool_stats,
+ eq_throttle_events)},
};
static const struct mana_stats_desc mana_hc_stats[] = {
@@ -250,6 +252,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
u64 short_pkt_fmt;
u64 csum_partial;
u64 mana_map_err;
+ u64 throttle_events;
int q, i = 0, j;
if (!apc->port_is_up)
@@ -261,6 +264,12 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
*/
mana_query_phy_stats(apc);
+ throttle_events = 0;
+ for (q = 0; q < num_queues; q++)
+ throttle_events += READ_ONCE(apc->eqs[q].eq->eq.throttle_count);
+
+ apc->eth_stats.eq_throttle_events = throttle_events;
+
for (q = 0; q < ARRAY_SIZE(mana_eth_stats); q++)
data[i++] = *(u64 *)(eth_stats + mana_eth_stats[q].offset);
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 308950f9b54b..50eae2aac64e 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -58,6 +58,7 @@ enum gdma_work_request_flags {
enum gdma_eqe_type {
GDMA_EQE_COMPLETION = 3,
+ GDMA_EQE_THROTTLE = 4,
GDMA_EQE_TEST_EVENT = 64,
GDMA_EQE_HWC_INIT_EQ_ID_DB = 129,
GDMA_EQE_HWC_INIT_DATA = 130,
@@ -286,6 +287,7 @@ struct gdma_dev {
#define GDMA_EQE_SIZE 16
#define GDMA_MAX_SQE_SIZE 512
#define GDMA_MAX_RQE_SIZE 256
+#define GDMA_EQ_MAX_CHILD_CQ 2
#define GDMA_COMP_DATA_SIZE 0x3C
@@ -366,6 +368,10 @@ struct gdma_queue {
unsigned int irq;
u32 log2_throttle_limit;
+
+ u64 throttle_count;
+
+ struct gdma_queue __rcu *child_cq[GDMA_EQ_MAX_CHILD_CQ];
} eq;
struct {
@@ -686,6 +692,9 @@ enum {
/* Driver supports non-contiguous queue buffers */
#define GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS BIT(30)
+/* Driver supports handling throttled EQEs */
+#define GDMA_DRV_CAP_FLAG_1_THROTTLED_EVENT_QUEUE BIT_ULL(32)
+
#define GDMA_DRV_CAP_FLAGS1 \
(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
@@ -703,7 +712,8 @@ enum {
GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECOVERY | \
GDMA_DRV_CAP_FLAG_1_EQ_MSI_UNSHARE_MULTI_VPORT | \
GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION | \
- GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS)
+ GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS | \
+ GDMA_DRV_CAP_FLAG_1_THROTTLED_EVENT_QUEUE)
#define GDMA_DRV_CAP_FLAGS2 0
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 8c3dc9d0b299..1d4be069f869 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -450,6 +450,7 @@ struct mana_ethtool_stats {
u64 tx_cqe_unknown_type;
u64 tx_linear_pkt_cnt;
u64 rx_cqe_unknown_type;
+ u64 eq_throttle_events;
};
struct mana_ethtool_hc_stats {
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* RE: [PATCH net v3] net: mana: Add support to process throttled EQEs
2026-10-22 14:53 [PATCH net v3] net: mana: Add support to process throttled EQEs Sahil Chandna
@ 2026-10-22 19:42 ` Haiyang Zhang
2026-10-23 11:39 ` Sahil Chandna
2026-10-26 15:25 ` netdev-bot+sashiko
1 sibling, 1 reply; 4+ messages in thread
From: Haiyang Zhang @ 2026-10-22 19:42 UTC (permalink / raw)
To: Sahil Chandna, wei.liu@kernel.org, Dexuan Cui,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@kernel.org,
kuba@kernel.org, pabeni@redhat.com, Konstantin Taranov,
horms@kernel.org, ernis@linux.microsoft.com,
gargaditya@linux.microsoft.com, mawasthi@linux.microsoft.com,
leitao@debian.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-rdma@vger.kernel.org
Cc: stable@vger.kernel.org
> -----Original Message-----
> From: Sahil Chandna <sahilchandna@linux.microsoft.com>
> Sent: Thursday, October 22, 2026 10:54 AM
> To: Haiyang Zhang <haiyangz@microsoft.com>; wei.liu@kernel.org; Dexuan Cui
> <DECUI@microsoft.com>; andrew+netdev@lunn.ch; davem@davemloft.net;
> edumazet@kernel.org; kuba@kernel.org; pabeni@redhat.com; Konstantin
> Taranov <kotaranov@microsoft.com>; horms@kernel.org;
> ernis@linux.microsoft.com; gargaditya@linux.microsoft.com;
> mawasthi@linux.microsoft.com; leitao@debian.org; linux-
> hyperv@vger.kernel.org; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org; linux-rdma@vger.kernel.org
> Cc: stable@vger.kernel.org
> Subject: [PATCH net v3] net: mana: Add support to process throttled EQEs
>
> When an event queue nears full, the hardware coalesces the per-CQ
> GDMA_EQE_COMPLETION notifications into a single throttle EQE (type 4)
> that carries no cq_id. The driver does not handle this event type, so
> it falls through to the default case and is dropped. Any CQ whose
> completion notification was replaced by the throttle EQE can remain
> unserviced, causing its queue to stall.
> The issue was observed internally and following Tx stall logs were
> seen:
>
> 2026-10-03T05:29:01 hv_netvsc eth0: VF slot 0 removed
> 2026-10-03T05:29:23 mana 7870:00:00.0 ens1: NETDEV WATCHDOG: CPU: 45:
> transmit queue 1 timed out 15133 ms
> 2026-10-03T05:31:05 mana 7870:00:00.0: HWC: Request timed out: 60000 ms
> 2026-10-03T05:31:05 mana 7870:00:00.0: Gf stats wk handler: gf stats
> query timed out.
> 2026-10-03T05:31:21 ens1: NETDEV WATCHDOG: CPU: 20: transmit queue 0
> timed out 15859 ms
> 2026-10-03T05:31:37 ens1: NETDEV WATCHDOG: CPU: 15: transmit queue 0
> timed out 31731 ms
> 2026-10-03T05:31:53 ens1: NETDEV WATCHDOG: CPU: 21: transmit queue 0
> timed out 47603 ms
> 2026-10-03T05:32:08 ens1: NETDEV WATCHDOG: CPU: 42: transmit queue 0
> timed out 62451 ms
>
> Add support to process the CQs which belong to a throttled EQE of type 4
> advertise the capability bit, also add a counter to store the throttled
> EQEs count.
>
> Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network
> Adapter (MANA)")
> Cc: stable@vger.kernel.org
> Signed-off-by: Sahil Chandna <sahilchandna@linux.microsoft.com>
> ---
> Changes in v3:
> - Resolve race for cq in mana_gd_destroy_cq and irq handler using cq.
> - Rebase to net branch
> Link to v2:
> https://lore.ker/
> nel.org%2Fall%2F20261014134304.4177657-1-
> sahilchandna%40linux.microsoft.com%2F&data=05%7C02%7Chaiyangz%40microsoft.
> com%7C534992a49c0340631e2f08df304e3c73%7C72f988bf86f141af91ab2d7cd011db47%
> 7C1%7C0%7C639282784768349454%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRyd
> WUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C
> 0%7C%7C%7C&sdata=w2NpUCx%2FCNtqeFQSR0fIMOYnbHLP7XsFl90sL%2F%2F7Y0g%3D&rese
> rved=0
>
> Changes in v2:
> - Use WRITE_ONCE() when clearing max_num_cqs and add RCU
> grace period wait during HWC teardown.
> - Use synchronize_net() during CQ destroy only when the CQ was
> attached to its parent EQ.
> - Use WRITE_ONCE() and READ_ONCE() for the throttle-event counter.
> - Add Fixes tag and net instead of net-next.
> - Fix commit message to describe capability bit and counter.
> Link to v1:
> https://lore.ker/
> nel.org%2Fall%2F20261008083315.306076-1-
> sahilchandna%40linux.microsoft.com%2F&data=05%7C02%7Chaiyangz%40microsoft.
> com%7C534992a49c0340631e2f08df304e3c73%7C72f988bf86f141af91ab2d7cd011db47%
> 7C1%7C0%7C639282784768392174%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRyd
> WUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C
> 0%7C%7C%7C&sdata=oj6Ei41iOntNjgoAWNaLSZdvptpbZSkkZMOCa6c2PDw%3D&reserved=0
>
> .../net/ethernet/microsoft/mana/gdma_main.c | 62 +++++++++++++++++--
> .../net/ethernet/microsoft/mana/hw_channel.c | 6 +-
> .../ethernet/microsoft/mana/mana_ethtool.c | 9 +++
> include/net/mana/gdma.h | 12 +++-
> include/net/mana/mana.h | 1 +
> 5 files changed, 81 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> index 8e9bfc1d6a2a..d74ed00bb783 100644
> --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> @@ -904,6 +904,27 @@ ssize_t mana_gd_read_ring(struct gdma_queue *q, char
> __user *buf,
> return copied;
> }
>
> +static void mana_gd_schedule_eq_cqs(struct gdma_queue *eq)
> +{
> + struct gdma_context *gc = eq->gdma_dev->gdma_context;
> + struct gdma_queue *cq;
> + u8 i;
> +
> + for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
> + cq = rcu_dereference(eq->eq.child_cq[i]);
> +
> + if (!cq)
> + continue;
> +
> + if (cq->id >= READ_ONCE(gc->max_num_cqs) ||
> + !gc->cq_table || gc->cq_table[cq->id] != cq)
> + continue;
> +
> + if (cq->cq.callback)
> + cq->cq.callback(cq->cq.context, cq);
> + }
> +}
> +
> static void mana_gd_process_eqe(struct gdma_queue *eq)
> {
> u32 head = eq->head % (eq->queue_size / GDMA_EQE_SIZE);
> @@ -934,6 +955,11 @@ static void mana_gd_process_eqe(struct gdma_queue
> *eq)
>
> break;
>
> + case GDMA_EQE_THROTTLE:
> + WRITE_ONCE(eq->eq.throttle_count, eq->eq.throttle_count + 1);
Please use u64_stats_update_begin / end() for stats, which is the standard
way -- see other stats code in this driver.
> + mana_gd_schedule_eq_cqs(eq);
> + break;
> +
> case GDMA_EQE_TEST_EVENT:
> gc->test_event_eq_id = eq->id;
> complete(&gc->eq_test_event);
[...]
> @@ -250,6 +252,7 @@ static void mana_get_ethtool_stats(struct net_device
> *ndev,
> u64 short_pkt_fmt;
> u64 csum_partial;
> u64 mana_map_err;
> + u64 throttle_events;
> int q, i = 0, j;
>
> if (!apc->port_is_up)
> @@ -261,6 +264,12 @@ static void mana_get_ethtool_stats(struct net_device
> *ndev,
> */
> mana_query_phy_stats(apc);
>
> + throttle_events = 0;
> + for (q = 0; q < num_queues; q++)
> + throttle_events += READ_ONCE(apc->eqs[q].eq-
> >eq.throttle_count);
Since you already have per queue throttle_count, please output them for
each EQ.
Thanks,
- Haiyang
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net v3] net: mana: Add support to process throttled EQEs
2026-10-22 19:42 ` Haiyang Zhang
@ 2026-10-23 11:39 ` Sahil Chandna
0 siblings, 0 replies; 4+ messages in thread
From: Sahil Chandna @ 2026-10-23 11:39 UTC (permalink / raw)
To: Haiyang Zhang, wei.liu@kernel.org, Dexuan Cui,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@kernel.org,
kuba@kernel.org, pabeni@redhat.com, Konstantin Taranov,
horms@kernel.org, ernis@linux.microsoft.com,
gargaditya@linux.microsoft.com, mawasthi@linux.microsoft.com,
leitao@debian.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-rdma@vger.kernel.org
Cc: stable@vger.kernel.org
On 23-10-2026 01:12, Haiyang Zhang wrote:
>
>
>> -----Original Message-----
>> From: Sahil Chandna <sahilchandna@linux.microsoft.com>
>> Sent: Thursday, October 22, 2026 10:54 AM
>> To: Haiyang Zhang <haiyangz@microsoft.com>; wei.liu@kernel.org; Dexuan Cui
>> <DECUI@microsoft.com>; andrew+netdev@lunn.ch; davem@davemloft.net;
>> edumazet@kernel.org; kuba@kernel.org; pabeni@redhat.com; Konstantin
>> Taranov <kotaranov@microsoft.com>; horms@kernel.org;
>> ernis@linux.microsoft.com; gargaditya@linux.microsoft.com;
>> mawasthi@linux.microsoft.com; leitao@debian.org; linux-
>> hyperv@vger.kernel.org; netdev@vger.kernel.org; linux-
>> kernel@vger.kernel.org; linux-rdma@vger.kernel.org
>> Cc: stable@vger.kernel.org
>> Subject: [PATCH net v3] net: mana: Add support to process throttled EQEs
>>
>> When an event queue nears full, the hardware coalesces the per-CQ
>> GDMA_EQE_COMPLETION notifications into a single throttle EQE (type 4)
>> that carries no cq_id. The driver does not handle this event type, so
>> it falls through to the default case and is dropped. Any CQ whose
>> completion notification was replaced by the throttle EQE can remain
>> unserviced, causing its queue to stall.
>> The issue was observed internally and following Tx stall logs were
>> seen:
>>
>> 2026-10-03T05:29:01 hv_netvsc eth0: VF slot 0 removed
>> 2026-10-03T05:29:23 mana 7870:00:00.0 ens1: NETDEV WATCHDOG: CPU: 45:
>> transmit queue 1 timed out 15133 ms
>> 2026-10-03T05:31:05 mana 7870:00:00.0: HWC: Request timed out: 60000 ms
>> 2026-10-03T05:31:05 mana 7870:00:00.0: Gf stats wk handler: gf stats
>> query timed out.
>> 2026-10-03T05:31:21 ens1: NETDEV WATCHDOG: CPU: 20: transmit queue 0
>> timed out 15859 ms
>> 2026-10-03T05:31:37 ens1: NETDEV WATCHDOG: CPU: 15: transmit queue 0
>> timed out 31731 ms
>> 2026-10-03T05:31:53 ens1: NETDEV WATCHDOG: CPU: 21: transmit queue 0
>> timed out 47603 ms
>> 2026-10-03T05:32:08 ens1: NETDEV WATCHDOG: CPU: 42: transmit queue 0
>> timed out 62451 ms
>>
>> Add support to process the CQs which belong to a throttled EQE of type 4
>> advertise the capability bit, also add a counter to store the throttled
>> EQEs count.
>>
>> Fixes: ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network
>> Adapter (MANA)")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Sahil Chandna <sahilchandna@linux.microsoft.com>
>> ---
>> Changes in v3:
>> - Resolve race for cq in mana_gd_destroy_cq and irq handler using cq.
>> - Rebase to net branch
>> Link to v2:
>> https://lore.ker/
>> nel.org%2Fall%2F20261014134304.4177657-1-
>> sahilchandna%40linux.microsoft.com%2F&data=05%7C02%7Chaiyangz%40microsoft.
>> com%7C534992a49c0340631e2f08df304e3c73%7C72f988bf86f141af91ab2d7cd011db47%
>> 7C1%7C0%7C639282784768349454%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRyd
>> WUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C
>> 0%7C%7C%7C&sdata=w2NpUCx%2FCNtqeFQSR0fIMOYnbHLP7XsFl90sL%2F%2F7Y0g%3D&rese
>> rved=0
>>
>> Changes in v2:
>> - Use WRITE_ONCE() when clearing max_num_cqs and add RCU
>> grace period wait during HWC teardown.
>> - Use synchronize_net() during CQ destroy only when the CQ was
>> attached to its parent EQ.
>> - Use WRITE_ONCE() and READ_ONCE() for the throttle-event counter.
>> - Add Fixes tag and net instead of net-next.
>> - Fix commit message to describe capability bit and counter.
>> Link to v1:
>> https://lore.ker/
>> nel.org%2Fall%2F20261008083315.306076-1-
>> sahilchandna%40linux.microsoft.com%2F&data=05%7C02%7Chaiyangz%40microsoft.
>> com%7C534992a49c0340631e2f08df304e3c73%7C72f988bf86f141af91ab2d7cd011db47%
>> 7C1%7C0%7C639282784768392174%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRyd
>> WUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C
>> 0%7C%7C%7C&sdata=oj6Ei41iOntNjgoAWNaLSZdvptpbZSkkZMOCa6c2PDw%3D&reserved=0
>>
>> .../net/ethernet/microsoft/mana/gdma_main.c | 62 +++++++++++++++++--
>> .../net/ethernet/microsoft/mana/hw_channel.c | 6 +-
>> .../ethernet/microsoft/mana/mana_ethtool.c | 9 +++
>> include/net/mana/gdma.h | 12 +++-
>> include/net/mana/mana.h | 1 +
>> 5 files changed, 81 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c
>> b/drivers/net/ethernet/microsoft/mana/gdma_main.c
>> index 8e9bfc1d6a2a..d74ed00bb783 100644
>> --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
>> +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
>> @@ -904,6 +904,27 @@ ssize_t mana_gd_read_ring(struct gdma_queue *q, char
>> __user *buf,
>> return copied;
>> }
>>
>> +static void mana_gd_schedule_eq_cqs(struct gdma_queue *eq)
>> +{
>> + struct gdma_context *gc = eq->gdma_dev->gdma_context;
>> + struct gdma_queue *cq;
>> + u8 i;
>> +
>> + for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
>> + cq = rcu_dereference(eq->eq.child_cq[i]);
>> +
>> + if (!cq)
>> + continue;
>> +
>> + if (cq->id >= READ_ONCE(gc->max_num_cqs) ||
>> + !gc->cq_table || gc->cq_table[cq->id] != cq)
>> + continue;
>> +
>> + if (cq->cq.callback)
>> + cq->cq.callback(cq->cq.context, cq);
>> + }
>> +}
>> +
>> static void mana_gd_process_eqe(struct gdma_queue *eq)
>> {
>> u32 head = eq->head % (eq->queue_size / GDMA_EQE_SIZE);
>> @@ -934,6 +955,11 @@ static void mana_gd_process_eqe(struct gdma_queue
>> *eq)
>>
>> break;
>>
>> + case GDMA_EQE_THROTTLE:
>> + WRITE_ONCE(eq->eq.throttle_count, eq->eq.throttle_count + 1);
> Please use u64_stats_update_begin / end() for stats, which is the standard
> way -- see other stats code in this driver.
>
Ack, will update it in v4.>> + mana_gd_schedule_eq_cqs(eq);
>> + break;
>> +
>> case GDMA_EQE_TEST_EVENT:
>> gc->test_event_eq_id = eq->id;
>> complete(&gc->eq_test_event);
> [...]
>
>
>> @@ -250,6 +252,7 @@ static void mana_get_ethtool_stats(struct net_device
>> *ndev,
>> u64 short_pkt_fmt;
>> u64 csum_partial;
>> u64 mana_map_err;
>> + u64 throttle_events;
>> int q, i = 0, j;
>>
>> if (!apc->port_is_up)
>> @@ -261,6 +264,12 @@ static void mana_get_ethtool_stats(struct net_device
>> *ndev,
>> */
>> mana_query_phy_stats(apc);
>>
>> + throttle_events = 0;
>> + for (q = 0; q < num_queues; q++)
>> + throttle_events += READ_ONCE(apc->eqs[q].eq-
>>> eq.throttle_count);
>
> Since you already have per queue throttle_count, please output them for
> each EQ.
>
> Thanks,
> - Haiyang
Ack, i will drop accumulated throttle count and report per EQ in v4.
The patch needs rebase again for net branch, i will rebase in v4.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net v3] net: mana: Add support to process throttled EQEs
2026-10-22 14:53 [PATCH net v3] net: mana: Add support to process throttled EQEs Sahil Chandna
2026-10-22 19:42 ` Haiyang Zhang
@ 2026-10-26 15:25 ` netdev-bot+sashiko
1 sibling, 0 replies; 4+ messages in thread
From: netdev-bot+sashiko @ 2026-10-26 15:25 UTC (permalink / raw)
To: sahilchandna
Cc: haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet, kuba,
pabeni, kotaranov, horms, ernis, gargaditya, mawasthi, leitao,
linux-hyperv, netdev, linux-kernel, linux-rdma, stable
Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 1 · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] Incomplete fix: a throttle EQE never services RDMA (mana_ib)
CQs, so the CQ-stall bug the patch claims to fix is still reachable.
- [Medium] mana_gd_destroy_cq() now calls synchronize_net() for every CQ
that was attached to a parent EQ, which is every mana_en TX and RX CQ.
- [Low] Claimed race: mana_create_txq() and mana_create_rxq() write
gc->cq_table[] (mana_en.c:2855, 3181) before netif_napi_add_*() (2860,…
--
net: mana: Add support to process throttled EQEs
This patch handles GDMA_EQE_THROTTLE (type 4) events. Each EQ records
up to two child CQs, and their callbacks are invoked when a throttle EQE
arrives. It also advertises a new driver capability bit, adds an
eq_throttle_events ethtool counter, and adds RCU grace period waits to
the CQ and HWC teardown paths.
> diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> index 8e9bfc1d6a2ae..d74ed00bb7834 100644
> --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> @@ -904,6 +904,27 @@ ssize_t mana_gd_read_ring(struct gdma_queue *q, char __user *buf,
> return copied;
> }
>
> +static void mana_gd_schedule_eq_cqs(struct gdma_queue *eq)
> +{
> + struct gdma_context *gc = eq->gdma_dev->gdma_context;
> + struct gdma_queue *cq;
> + u8 i;
> +
> + for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
> + cq = rcu_dereference(eq->eq.child_cq[i]);
> +
> + if (!cq)
> + continue;
> +
> + if (cq->id >= READ_ONCE(gc->max_num_cqs) ||
> + !gc->cq_table || gc->cq_table[cq->id] != cq)
> + continue;
> +
> + if (cq->cq.callback)
> + cq->cq.callback(cq->cq.context, cq);
[Severity: Low]
This may not be reachable today, but is cq_table membership enough to
show that the CQ is ready for its callback?
mana_create_txq() and mana_create_rxq() publish the CQ in cq_table
before they add NAPI. For example, in mana_create_rxq():
gc->cq_table[cq->gdma_id] = cq->gdma_cq;
netif_napi_add_weight_locked(ndev, &cq->napi, mana_poll, 1);
If a GDMA_EQE_THROTTLE arrived on the parent EQ in that window, this
loop would call mana_schedule_napi()->napi_schedule_irqoff() on a
napi_struct that is not initialized yet.
In mana_alloc_queues() the EQs are freshly created. During the RX
window, the only other CQ on EQ i is TX CQ i. That CQ carries no
traffic while port_is_up is still false, so with the throttle semantics
described in the commit message this looks unreachable. It does depend
on that ordering, and on the hardware never sending a throttle EQE
without pending completions.
Would it be more robust to publish the cq_table entry only after
netif_napi_add_*() has run?
> + }
> +}
[ ... ]
> @@ -1220,25 +1246,49 @@ static void mana_gd_create_cq(const struct gdma_queue_spec *spec,
> struct gdma_queue *queue)
> {
> u32 log2_num_entries = ilog2(spec->queue_size / GDMA_CQE_SIZE);
> + struct gdma_queue *parent;
> + u8 i;
>
> queue->head |= INITIALIZED_OWNER_BIT(log2_num_entries);
> - queue->cq.parent = spec->cq.parent_eq;
> + parent = spec->cq.parent_eq;
> + queue->cq.parent = parent;
> queue->cq.context = spec->cq.context;
> queue->cq.callback = spec->cq.callback;
> +
> + if (!parent)
> + return;
> +
> + /* For throttled EQE store the child CQ */
> + for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++)
> + if (!rcu_access_pointer(parent->eq.child_cq[i])) {
> + rcu_assign_pointer(parent->eq.child_cq[i], queue);
> + return;
> + }
> }
[Severity: High]
Can a throttle EQE leave the mana_ib CQs unserviced?
child_cq[] is only filled here, and only when spec->cq.parent_eq is
set. In practice that covers the mana_en TX/RX CQs and the HWC CQ.
The RDMA CQs never get here with a parent:
- mana_ib_create_kernel_queue() in drivers/infiniband/hw/mana/main.c
builds its spec as below, so parent_eq is NULL:
struct gdma_queue_spec spec = {};
- User CQs from mana_ib_create_queue() never go through
mana_gd_create_cq().
- mana_ib_install_cq_cb() only does:
gc->cq_table[cq->queue.id] = gdma_cq;
The hardware still binds these CQs to GDMA EQs. In
mana_ib_gd_create_cq():
req.eq_id = mdev->eqs[cq->comp_vector]->id;
and in mana_ib_create_qp_rss() and mana_ib_create_qp_raw():
cq_spec.attached_eq = eq->eq->id;
where those EQs are created by mana_ib_cfg_vport() when RDMA owns the
vport.
These EQs are serviced by mana_gd_intr()->mana_gd_process_eqe(). On a
GDMA_EQE_THROTTLE, mana_gd_schedule_eq_cqs() walks an all-NULL
child_cq[], and mana_ib_cq_handler() never runs.
Wouldn't that leave RDMA consumers waiting on comp_handler with
completions pending? That is the same queue stall the commit message
describes.
GDMA_DRV_CAP_FLAG_1_THROTTLED_EVENT_QUEUE is added to
GDMA_DRV_CAP_FLAGS1. mana_gd_verify_vf_version() sends that once for
the whole device, which mana_en and mana_ib share. If firmware only
emits type 4 EQEs after this bit is set, does this add a new stall for
RDMA CQs? If firmware always emits them, is the fix incomplete for
those EQs?
Separately, once both GDMA_EQ_MAX_CHILD_CQ slots are taken, the loop
above returns without recording the CQ and without any warning. Many
RDMA CQs can share one comp_vector EQ, and that seems to be the case
most likely to fill an EQ and trigger throttling.
Would this need a per-EQ list of CQs, or a walk over every CQ whose
parent is this EQ, rather than a fixed 2-entry array?
>
> static void mana_gd_destroy_cq(struct gdma_context *gc,
> struct gdma_queue *queue)
> {
[ ... ]
> - gc->cq_table[id] = NULL;
> + /* Wait for irq reader holding the cq */
> + if (attached)
> + synchronize_net();
> }
[Severity: Medium]
Does this add one RCU grace period per CQ to every port teardown?
Every mana_en TX and RX CQ is attached to a parent EQ, and they are
destroyed one at a time:
mana_dealloc_queues()
mana_destroy_txq() /* loops over apc->num_queues */
mana_deinit_cq()
mana_gd_destroy_queue()
mana_gd_destroy_cq()
synchronize_net()
The same happens for each RX CQ through
mana_destroy_rxqs()->mana_destroy_rxq().
These paths run under RTNL: mana_close(), and mana_detach() from
ethtool -L/-G, MTU changes, XDP setup, and queue reset. Under RTNL,
synchronize_net() does:
if (from_cleanup_net() || rtnl_is_locked())
synchronize_rcu_expedited();
With MANA_MAX_NUM_QUEUES at 64, one teardown can run up to 128
expedited grace periods back to back while RTNL is held.
The HWC path also waits twice: once here for its CQ, and once in the
new synchronize_rcu() in mana_hwc_destroy_channel().
Could the child_cq[] and cq_table entries be cleared for all CQs first,
with a single grace period before the queues are freed?
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261022145428.323576-1-sahilchandna%40linux.microsoft.com
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-26 15:25 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-22 14:53 [PATCH net v3] net: mana: Add support to process throttled EQEs Sahil Chandna
2026-10-22 19:42 ` Haiyang Zhang
2026-10-23 11:39 ` Sahil Chandna
2026-10-26 15:25 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox