qcacmn: Fix disconnection issue due to N/W queues pause

Due to DP flow control network queues are stuck in
paused state and not getting reset even after new connection.
This is causing DHCP packets to be dropped and resulting
immediate disconnection after every connection.

Fix this by properly pausing and unpausing the AC flow control
based network subqueues during disconnection/connection events.

Change-Id: I280e704d5a01b19d180c32aaa272c0cb731f8c0e
CRs-Fixed: 3078745
This commit is contained in:
Karthik Kantamneni
2021-11-23 15:55:37 +05:30
committato da Madan Koyyalamudi
parent 1cee4a643a
commit fcebc684e9
4 ha cambiato i file con 161 aggiunte e 20 eliminazioni

Vedi File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -90,20 +91,7 @@ dp_tx_flow_pool_reattach(struct dp_tx_desc_pool_s *pool)
"%s: flow pool already allocated, attached %d times",
__func__, pool->pool_create_cnt);
if (pool->avail_desc > pool->start_th[DP_TH_BE_BK])
pool->status = FLOW_POOL_ACTIVE_UNPAUSED;
else if (pool->avail_desc <= pool->start_th[DP_TH_BE_BK] &&
pool->avail_desc > pool->start_th[DP_TH_VI])
pool->status = FLOW_POOL_BE_BK_PAUSED;
else if (pool->avail_desc <= pool->start_th[DP_TH_VI] &&
pool->avail_desc > pool->start_th[DP_TH_VO])
pool->status = FLOW_POOL_VI_PAUSED;
else if (pool->avail_desc <= pool->start_th[DP_TH_VO] &&
pool->avail_desc > pool->start_th[DP_TH_HI])
pool->status = FLOW_POOL_VO_PAUSED;
else
pool->status = FLOW_POOL_ACTIVE_PAUSED;
pool->status = FLOW_POOL_ACTIVE_UNPAUSED_REATTACH;
pool->pool_create_cnt++;
}
@@ -131,6 +119,44 @@ dp_tx_flow_pool_dump_threshold(struct dp_tx_desc_pool_s *pool)
}
}
/**
* dp_tx_flow_ctrl_reset_subqueues() - Reset subqueues to orginal state
* @soc: dp soc
* @pool: flow pool
* @pool_status: flow pool status
*
* Return: none
*/
static inline void
dp_tx_flow_ctrl_reset_subqueues(struct dp_soc *soc,
struct dp_tx_desc_pool_s *pool,
enum flow_pool_status pool_status)
{
switch (pool_status) {
case FLOW_POOL_ACTIVE_PAUSED:
soc->pause_cb(pool->flow_pool_id,
WLAN_NETIF_PRIORITY_QUEUE_ON,
WLAN_DATA_FLOW_CTRL_PRI);
case FLOW_POOL_VO_PAUSED:
soc->pause_cb(pool->flow_pool_id,
WLAN_NETIF_VO_QUEUE_ON,
WLAN_DATA_FLOW_CTRL_VO);
case FLOW_POOL_VI_PAUSED:
soc->pause_cb(pool->flow_pool_id,
WLAN_NETIF_VI_QUEUE_ON,
WLAN_DATA_FLOW_CTRL_VI);
case FLOW_POOL_BE_BK_PAUSED:
soc->pause_cb(pool->flow_pool_id,
WLAN_NETIF_BE_BK_QUEUE_ON,
WLAN_DATA_FLOW_CTRL_BE_BK);
default:
break;
}
}
#else
static inline void
dp_tx_initialize_threshold(struct dp_tx_desc_pool_s *pool,
@@ -166,6 +192,13 @@ dp_tx_flow_pool_dump_threshold(struct dp_tx_desc_pool_s *pool)
pool->start_th, pool->stop_th);
}
static inline void
dp_tx_flow_ctrl_reset_subqueues(struct dp_soc *soc,
struct dp_tx_desc_pool_s *pool,
enum flow_pool_status pool_status)
{
}
#endif
/**
@@ -356,6 +389,7 @@ int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool,
bool force)
{
struct dp_vdev *vdev;
enum flow_pool_status pool_status;
if (!soc || !pool) {
dp_err("pool or soc is NULL");
@@ -381,7 +415,10 @@ int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool,
}
if (pool->avail_desc < pool->pool_size) {
pool_status = pool->status;
pool->status = FLOW_POOL_INVALID;
dp_tx_flow_ctrl_reset_subqueues(soc, pool, pool_status);
qdf_spin_unlock_bh(&pool->flow_pool_lock);
/* Reset TX desc associated to this Vdev as NULL */
vdev = dp_vdev_get_ref_by_id(soc, pool->flow_pool_id,