qcacmn: Make sure vdev manager delete isn't executed in softirq context

Currently host driver will call wlan_objmgr_peer_release_ref() in
tgt_mgmt_txrx_tx_completion_handler() to decrease peer reference
count when management frame TX completion is received. When the
last pending reference is management frame in some corner cases,
below call stack will be triggered:

BUG: scheduling while atomic: swapper/0/0/0x00000102
[  105.368065] Call trace:
[  105.368079] dump_backtrace+0x0/0x1b4
[  105.368087] show_stack+0x14/0x1c
[  105.368096] dump_stack+0xd4/0x10c
[  105.368105] __schedule_bug+0x50/0x70
[  105.368113] __schedule+0x980/0xc04
[  105.368119] schedule+0x70/0x90
[  105.368126] schedule_timeout+0x3c/0x5f4
[  105.368133] wait_for_common+0xb0/0x138
[  105.368139] wait_for_completion+0x14/0x1c
[  105.368148] synchronize_srcu_expedited+0xc8/0x100
[  105.368153] synchronize_srcu+0xa4/0x17c
[  105.368161] wakeup_source_remove+0x54/0x74
[  105.368840] __qdf_wake_lock_destroy+0x14/0x28 [wlan]
[  105.369518] wma_vdev_deinit+0x104/0x144 [wlan]
[  105.370190] wma_vdev_detach_callback+0xd8/0x108 [wlan]
[  105.370870] vdevmgr_vdev_delete_rsp_handle+0x48/0x54 [wlan]
[  105.371557] mlme_vdev_ops_ext_hdl_delete_rsp+0x2c/0x44 [wlan]
[  105.372245] tgt_vdev_mgr_delete_response_handler+0xc/0x14 [wlan]
[  105.372928] target_if_vdev_mgr_delete_send+0x2cc/0x2d8 [wlan]
[  105.373613] tgt_vdev_mgr_delete_send+0x15c/0x19c [wlan]
[  105.374296] vdev_mgr_delete_send+0x44/0x118 [wlan]
[  105.374975] vdevmgr_mlme_ext_hdl_destroy+0x7c/0x128 [wlan]
[  105.375662] mlme_vdev_ops_ext_hdl_destroy+0x2c/0x44 [wlan]
[  105.376341] mlme_vdev_obj_destroy_handler+0x2c/0xc0 [wlan]
[  105.377027] wlan_objmgr_vdev_release_ref+0x128/0x250 [wlan]
[  105.377710] wlan_objmgr_peer_obj_free+0x1d4/0x1dc [wlan]
[  105.378402] wlan_objmgr_peer_release_ref+0x1f8/0x22c [wlan]
[  105.379085] tgt_mgmt_txrx_tx_completion_handler+0x194/0x1c0 [wlan]
[  105.379751] wma_mgmt_tx_ack_comp_hdlr+0xdc/0x190 [wlan]
[  105.380425] ol_tx_desc_frame_free_nonstd+0x58/0xec [wlan]
[  105.381100] ol_tx_single_completion_handler+0x27c/0x2bc [wlan]
[  105.381796] htt_t2h_msg_handler+0xeec/0x1280 [wlan]
[  105.382506] htc_rx_completion_handler+0x8b0/0x9c4 [wlan]
[  105.383202] hif_pci_ce_recv_data+0x198/0x234 [wlan]
[  105.383899] ce_engine_service_reg+0x110/0x444 [wlan]
[  105.384595] ce_per_engine_service+0x70/0x104 [wlan]
[  105.385289] hif_napi_poll+0x94/0x3b4 [wlan]
[  105.385899] hdd_napi_poll+0x28/0x34 [wlan]
[  105.385928] net_rx_action+0x110/0x480
[  105.385948] __do_softirq+0x1e8/0x39c
[  105.385962] irq_exit+0xcc/0xd8
[  105.385982] __handle_domain_irq+0x84/0xbc
[  105.386001] gic_handle_irq+0x168/0x1b8
[  105.386015] el1_irq+0xb0/0x124
[  105.386035] lpm_cpuidle_enter+0x4fc/0x538
[  105.386051] cpuidle_enter_state+0x1c0/0x338
[  105.386063] cpuidle_enter+0x18/0x20
[  105.386084] do_idle+0x1a0/0x288

Due to some wlan chip doesn't support wmi_service_sync_delete_cmds
capability,  it will call target_if_vdev_mgr_delete_response_send()
directly to process further and doesn't exit softirq context, then
cause thread schedule under softirq context. To avoid above race
condition, let vdev manager delete response scheduled by driver
thread for MCC case.

Change-Id: I143b585bf0e7b7d3bfbe94656ea1c548cfd2efd8
CRs-Fixed: 3300663
此提交包含在:
Qun Zhang
2022-09-22 14:06:04 +08:00
提交者 Madan Koyyalamudi
父節點 393465dcf4
當前提交 4c70bb772f

查看文件

@@ -499,20 +499,99 @@ static QDF_STATUS target_if_vdev_mgr_start_send(
}
static QDF_STATUS target_if_vdev_mgr_delete_response_send(
struct wlan_objmgr_vdev *vdev,
struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id,
struct wlan_lmac_if_mlme_rx_ops *rx_ops)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev);
struct vdev_delete_response rsp = {0};
rsp.vdev_id = wlan_vdev_get_id(vdev);
rsp.vdev_id = vdev_id;
status = rx_ops->vdev_mgr_delete_response(psoc, &rsp);
target_if_wake_lock_timeout_release(psoc, DELETE_WAKELOCK);
return status;
}
#ifdef SERIALIZE_VDEV_RESP
static QDF_STATUS
target_if_vdev_mgr_del_rsp_post_flush_cb(struct scheduler_msg *msg)
{
/* Dummy */
return QDF_STATUS_SUCCESS;
}
static void
target_if_vdev_mgr_del_rsp_post_cb(struct scheduler_msg *msg)
{
struct wlan_objmgr_psoc *psoc;
struct wlan_lmac_if_mlme_rx_ops *rx_ops;
uint8_t vdev_id;
if (!msg || !msg->bodyptr) {
mlme_err("Msg or Msg bodyptr is NULL");
return;
}
psoc = msg->bodyptr;
vdev_id = msg->bodyval;
if (vdev_id >= WLAN_UMAC_PSOC_MAX_VDEVS) {
mlme_err("Invalid VDEV_ID %d", vdev_id);
return;
}
rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
if (!rx_ops) {
mlme_err("No Rx Ops");
return;
}
/* Don't try to get vdev as it's already deleted */
target_if_vdev_mgr_delete_response_send(psoc, vdev_id, rx_ops);
}
static void target_if_vdev_mgr_delete_rsp_post_ctx(
struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id)
{
struct scheduler_msg msg = {0};
msg.callback = (scheduler_msg_process_fn_t)
target_if_vdev_mgr_del_rsp_post_cb;
msg.bodyptr = psoc;
msg.bodyval = vdev_id;
msg.flush_callback =
target_if_vdev_mgr_del_rsp_post_flush_cb;
if (scheduler_post_message(QDF_MODULE_ID_TARGET_IF,
QDF_MODULE_ID_TARGET_IF,
QDF_MODULE_ID_TARGET_IF, &msg) ==
QDF_STATUS_SUCCESS)
return;
mlme_err("Failed to enqueue vdev delete response");
}
static void
target_if_vdev_mgr_delete_rsp_handler(
struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id,
struct wlan_lmac_if_mlme_rx_ops *rx_ops)
{
target_if_vdev_mgr_delete_rsp_post_ctx(psoc, vdev_id);
}
#else
static void
target_if_vdev_mgr_delete_rsp_handler(
struct wlan_objmgr_psoc *psoc,
uint8_t vdev_id,
struct wlan_lmac_if_mlme_rx_ops *rx_ops)
{
target_if_vdev_mgr_delete_response_send(psoc, vdev_id, rx_ops);
}
#endif
static QDF_STATUS target_if_vdev_mgr_delete_send(
struct wlan_objmgr_vdev *vdev,
struct vdev_delete_params *param)
@@ -567,7 +646,8 @@ static QDF_STATUS target_if_vdev_mgr_delete_send(
WLAN_SOC_F_TESTMODE_ENABLE)) {
target_if_vdev_mgr_rsp_timer_stop(psoc, vdev_rsp,
DELETE_RESPONSE_BIT);
target_if_vdev_mgr_delete_response_send(vdev, rx_ops);
target_if_vdev_mgr_delete_rsp_handler(psoc, vdev_id,
rx_ops);
}
} else {
vdev_rsp->expire_time = 0;