* [PATCH v3 0/3] ath11k: add 11d scan offload support for QCA6390/WCN6855 @ 2021-12-01 7:17 ` Wen Gong 0 siblings, 0 replies; 12+ messages in thread From: Wen Gong @ 2021-12-01 7:17 UTC (permalink / raw) To: ath11k; +Cc: linux-wireless, quic_wgong v3: 1. rebased to latest ath.git master ath-202111221436 2. add "ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work", it is to fix deadlock warning 3. move "cancel_work_sync(&ab->update_11d_work)" out from pci.c to mac.c/core.c v2: 1. rebased to latest ath.git master ath-202111170737 2. add "ath11k: add configure country code for QCA6390 and WCN6855", it is needed for patch "ath11k: add 11d scan offload support" Wen Gong (3): ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work ath11k: add configure country code for QCA6390 and WCN6855 ath11k: add 11d scan offload support drivers/net/wireless/ath/ath11k/core.c | 31 +++++ drivers/net/wireless/ath/ath11k/core.h | 9 ++ drivers/net/wireless/ath/ath11k/mac.c | 163 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/mac.h | 7 ++ drivers/net/wireless/ath/ath11k/reg.c | 15 +++ drivers/net/wireless/ath/ath11k/wmi.c | 147 +++++++++++++++++++++- drivers/net/wireless/ath/ath11k/wmi.h | 39 ++++++ 7 files changed, 409 insertions(+), 2 deletions(-) base-commit: e5118670f6edde897ab17c3467efd24ad334fe7b -- 2.31.1 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 0/3] ath11k: add 11d scan offload support for QCA6390/WCN6855 @ 2021-12-01 7:17 ` Wen Gong 0 siblings, 0 replies; 12+ messages in thread From: Wen Gong @ 2021-12-01 7:17 UTC (permalink / raw) To: ath11k; +Cc: linux-wireless, quic_wgong v3: 1. rebased to latest ath.git master ath-202111221436 2. add "ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work", it is to fix deadlock warning 3. move "cancel_work_sync(&ab->update_11d_work)" out from pci.c to mac.c/core.c v2: 1. rebased to latest ath.git master ath-202111170737 2. add "ath11k: add configure country code for QCA6390 and WCN6855", it is needed for patch "ath11k: add 11d scan offload support" Wen Gong (3): ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work ath11k: add configure country code for QCA6390 and WCN6855 ath11k: add 11d scan offload support drivers/net/wireless/ath/ath11k/core.c | 31 +++++ drivers/net/wireless/ath/ath11k/core.h | 9 ++ drivers/net/wireless/ath/ath11k/mac.c | 163 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/mac.h | 7 ++ drivers/net/wireless/ath/ath11k/reg.c | 15 +++ drivers/net/wireless/ath/ath11k/wmi.c | 147 +++++++++++++++++++++- drivers/net/wireless/ath/ath11k/wmi.h | 39 ++++++ 7 files changed, 409 insertions(+), 2 deletions(-) base-commit: e5118670f6edde897ab17c3467efd24ad334fe7b -- 2.31.1 -- ath11k mailing list ath11k@lists.infradead.org http://lists.infradead.org/mailman/listinfo/ath11k ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 1/3] ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work 2021-12-01 7:17 ` Wen Gong @ 2021-12-01 7:17 ` Wen Gong -1 siblings, 0 replies; 12+ messages in thread From: Wen Gong @ 2021-12-01 7:17 UTC (permalink / raw) To: ath11k; +Cc: linux-wireless, quic_wgong When enable debug config, it print below warning while shut down wlan interface shuh as run "ifconfig wlan0 down". The reason is because ar->regd_update_work is ran once, and it is will call wiphy_lock(ar->hw->wiphy) in function ath11k_regd_update() which is running in workqueue of ieee80211_local queued by ieee80211_queue_work(). Another thread from "ifconfig wlan0 down" will also accuqire the lock by wiphy_lock(sdata->local->hw.wiphy) in function ieee80211_stop(), and then it call ieee80211_stop_device() to flush_workqueue(local->workqueue), this will wait the workqueue of ieee80211_local finished. Then deadlock will happen easily if the two thread run meanwhile. Below warning disappeared after this change. [ 914.088798] ath11k_pci 0000:05:00.0: mac remove interface (vdev 0) [ 914.088806] ath11k_pci 0000:05:00.0: mac stop 11d scan [ 914.088810] ath11k_pci 0000:05:00.0: mac stop 11d vdev id 0 [ 914.088827] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) [ 914.088841] ath11k_pci 0000:05:00.0: send 11d scan stop vdev id 0 [ 914.088849] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 [ 914.088856] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 [ 914.096434] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 [ 914.096442] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) [ 914.096481] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) [ 914.096491] ath11k_pci 0000:05:00.0: WMI vdev delete id 0 [ 914.111598] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 [ 914.111628] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) [ 914.114659] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 20 [ 914.114742] ath11k_pci 0000:05:00.0: htc rx completion ep 2 skb pK-error [ 914.115977] ath11k_pci 0000:05:00.0: vdev delete resp for vdev id 0 [ 914.116685] ath11k_pci 0000:05:00.0: vdev 00:03:7f:29:61:11 deleted, vdev_id 0 [ 914.117583] ====================================================== [ 914.117592] WARNING: possible circular locking dependency detected [ 914.117600] 5.16.0-rc1-wt-ath+ #1 Tainted: G OE [ 914.117611] ------------------------------------------------------ [ 914.117618] ifconfig/2805 is trying to acquire lock: [ 914.117628] ffff9c00a62bb548 ((wq_completion)phy0){+.+.}-{0:0}, at: flush_workqueue+0x87/0x470 [ 914.117674] but task is already holding lock: [ 914.117682] ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] [ 914.117872] which lock already depends on the new lock. [ 914.117880] the existing dependency chain (in reverse order) is: [ 914.117888] -> #3 (&rdev->wiphy.mtx){+.+.}-{4:4}: [ 914.117910] __mutex_lock+0xa0/0x9c0 [ 914.117930] mutex_lock_nested+0x1b/0x20 [ 914.117944] reg_process_self_managed_hints+0x3a/0xb0 [cfg80211] [ 914.118093] wiphy_regulatory_register+0x47/0x80 [cfg80211] [ 914.118229] wiphy_register+0x84f/0x9c0 [cfg80211] [ 914.118353] ieee80211_register_hw+0x6b1/0xd90 [mac80211] [ 914.118486] ath11k_mac_register+0x6af/0xb60 [ath11k] [ 914.118550] ath11k_core_qmi_firmware_ready+0x383/0x4a0 [ath11k] [ 914.118598] ath11k_qmi_driver_event_work+0x347/0x4a0 [ath11k] [ 914.118656] process_one_work+0x228/0x670 [ 914.118669] worker_thread+0x4d/0x440 [ 914.118680] kthread+0x16d/0x1b0 [ 914.118697] ret_from_fork+0x22/0x30 [ 914.118714] -> #2 (rtnl_mutex){+.+.}-{4:4}: [ 914.118736] __mutex_lock+0xa0/0x9c0 [ 914.118751] mutex_lock_nested+0x1b/0x20 [ 914.118767] rtnl_lock+0x17/0x20 [ 914.118783] ath11k_regd_update+0x15a/0x260 [ath11k] [ 914.118841] ath11k_regd_update_work+0x15/0x20 [ath11k] [ 914.118897] process_one_work+0x228/0x670 [ 914.118909] worker_thread+0x4d/0x440 [ 914.118920] kthread+0x16d/0x1b0 [ 914.118934] ret_from_fork+0x22/0x30 [ 914.118948] -> #1 ((work_completion)(&ar->regd_update_work)){+.+.}-{0:0}: [ 914.118972] process_one_work+0x1fa/0x670 [ 914.118984] worker_thread+0x4d/0x440 [ 914.118996] kthread+0x16d/0x1b0 [ 914.119010] ret_from_fork+0x22/0x30 [ 914.119023] -> #0 ((wq_completion)phy0){+.+.}-{0:0}: [ 914.119045] __lock_acquire+0x146d/0x1cf0 [ 914.119057] lock_acquire+0x19b/0x360 [ 914.119067] flush_workqueue+0xae/0x470 [ 914.119084] ieee80211_stop_device+0x3b/0x50 [mac80211] [ 914.119260] ieee80211_do_stop+0x5d7/0x830 [mac80211] [ 914.119409] ieee80211_stop+0x45/0x180 [mac80211] [ 914.119557] __dev_close_many+0xb3/0x120 [ 914.119573] __dev_change_flags+0xc3/0x1d0 [ 914.119590] dev_change_flags+0x29/0x70 [ 914.119605] devinet_ioctl+0x653/0x810 [ 914.119620] inet_ioctl+0x193/0x1e0 [ 914.119631] sock_do_ioctl+0x4d/0xf0 [ 914.119649] sock_ioctl+0x262/0x340 [ 914.119665] __x64_sys_ioctl+0x96/0xd0 [ 914.119678] do_syscall_64+0x3d/0xd0 [ 914.119694] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 914.119709] other info that might help us debug this: [ 914.119717] Chain exists of: (wq_completion)phy0 --> rtnl_mutex --> &rdev->wiphy.mtx [ 914.119745] Possible unsafe locking scenario: [ 914.119752] CPU0 CPU1 [ 914.119758] ---- ---- [ 914.119765] lock(&rdev->wiphy.mtx); [ 914.119778] lock(rtnl_mutex); [ 914.119792] lock(&rdev->wiphy.mtx); [ 914.119807] lock((wq_completion)phy0); [ 914.119819] *** DEADLOCK *** [ 914.119827] 2 locks held by ifconfig/2805: [ 914.119837] #0: ffffffffba3dc010 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock+0x17/0x20 [ 914.119872] #1: ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] [ 914.120039] stack backtrace: [ 914.120048] CPU: 0 PID: 2805 Comm: ifconfig Tainted: G OE 5.16.0-rc1-wt-ath+ #1 [ 914.120064] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW (1.33 ) 07/29/2011 [ 914.120074] Call Trace: [ 914.120084] <TASK> [ 914.120094] dump_stack_lvl+0x73/0xa4 [ 914.120119] dump_stack+0x10/0x12 [ 914.120135] print_circular_bug.isra.44+0x221/0x2e0 [ 914.120165] check_noncircular+0x106/0x150 [ 914.120203] __lock_acquire+0x146d/0x1cf0 [ 914.120215] ? __lock_acquire+0x146d/0x1cf0 [ 914.120245] lock_acquire+0x19b/0x360 [ 914.120259] ? flush_workqueue+0x87/0x470 [ 914.120286] ? lockdep_init_map_type+0x6b/0x250 [ 914.120310] flush_workqueue+0xae/0x470 [ 914.120327] ? flush_workqueue+0x87/0x470 [ 914.120344] ? lockdep_hardirqs_on+0xd7/0x150 [ 914.120391] ieee80211_stop_device+0x3b/0x50 [mac80211] [ 914.120565] ? ieee80211_stop_device+0x3b/0x50 [mac80211] [ 914.120736] ieee80211_do_stop+0x5d7/0x830 [mac80211] [ 914.120906] ieee80211_stop+0x45/0x180 [mac80211] [ 914.121060] __dev_close_many+0xb3/0x120 [ 914.121081] __dev_change_flags+0xc3/0x1d0 [ 914.121109] dev_change_flags+0x29/0x70 [ 914.121131] devinet_ioctl+0x653/0x810 [ 914.121149] ? __might_fault+0x77/0x80 [ 914.121179] inet_ioctl+0x193/0x1e0 [ 914.121194] ? inet_ioctl+0x193/0x1e0 [ 914.121218] ? __might_fault+0x77/0x80 [ 914.121238] ? _copy_to_user+0x68/0x80 [ 914.121266] sock_do_ioctl+0x4d/0xf0 [ 914.121283] ? inet_stream_connect+0x60/0x60 [ 914.121297] ? sock_do_ioctl+0x4d/0xf0 [ 914.121329] sock_ioctl+0x262/0x340 [ 914.121347] ? sock_ioctl+0x262/0x340 [ 914.121362] ? exit_to_user_mode_prepare+0x13b/0x280 [ 914.121388] ? syscall_enter_from_user_mode+0x20/0x50 [ 914.121416] __x64_sys_ioctl+0x96/0xd0 [ 914.121430] ? br_ioctl_call+0x90/0x90 [ 914.121445] ? __x64_sys_ioctl+0x96/0xd0 [ 914.121465] do_syscall_64+0x3d/0xd0 [ 914.121482] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 914.121497] RIP: 0033:0x7f0ed051737b [ 914.121513] Code: 0f 1e fa 48 8b 05 15 3b 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e5 3a 0d 00 f7 d8 64 89 01 48 [ 914.121527] RSP: 002b:00007fff7be38b98 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 [ 914.121544] RAX: ffffffffffffffda RBX: 00007fff7be38ba0 RCX: 00007f0ed051737b [ 914.121555] RDX: 00007fff7be38ba0 RSI: 0000000000008914 RDI: 0000000000000004 [ 914.121566] RBP: 00007fff7be38c60 R08: 000000000000000a R09: 0000000000000001 [ 914.121576] R10: 0000000000000000 R11: 0000000000000202 R12: 00000000fffffffe [ 914.121586] R13: 0000000000000004 R14: 0000000000000000 R15: 0000000000000000 [ 914.121620] </TASK> Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> --- drivers/net/wireless/ath/ath11k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 87351e0a269d..a3a8c49b3329 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -6032,7 +6032,7 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk ar = ab->pdevs[pdev_idx].ar; kfree(ab->new_regd[pdev_idx]); ab->new_regd[pdev_idx] = regd; - ieee80211_queue_work(ar->hw, &ar->regd_update_work); + queue_work(ab->workqueue, &ar->regd_update_work); } else { /* This regd would be applied during mac registration and is * held constant throughout for regd intersection purpose -- 2.31.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 1/3] ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work @ 2021-12-01 7:17 ` Wen Gong 0 siblings, 0 replies; 12+ messages in thread From: Wen Gong @ 2021-12-01 7:17 UTC (permalink / raw) To: ath11k; +Cc: linux-wireless, quic_wgong When enable debug config, it print below warning while shut down wlan interface shuh as run "ifconfig wlan0 down". The reason is because ar->regd_update_work is ran once, and it is will call wiphy_lock(ar->hw->wiphy) in function ath11k_regd_update() which is running in workqueue of ieee80211_local queued by ieee80211_queue_work(). Another thread from "ifconfig wlan0 down" will also accuqire the lock by wiphy_lock(sdata->local->hw.wiphy) in function ieee80211_stop(), and then it call ieee80211_stop_device() to flush_workqueue(local->workqueue), this will wait the workqueue of ieee80211_local finished. Then deadlock will happen easily if the two thread run meanwhile. Below warning disappeared after this change. [ 914.088798] ath11k_pci 0000:05:00.0: mac remove interface (vdev 0) [ 914.088806] ath11k_pci 0000:05:00.0: mac stop 11d scan [ 914.088810] ath11k_pci 0000:05:00.0: mac stop 11d vdev id 0 [ 914.088827] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) [ 914.088841] ath11k_pci 0000:05:00.0: send 11d scan stop vdev id 0 [ 914.088849] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 [ 914.088856] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 [ 914.096434] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 [ 914.096442] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) [ 914.096481] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) [ 914.096491] ath11k_pci 0000:05:00.0: WMI vdev delete id 0 [ 914.111598] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 [ 914.111628] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) [ 914.114659] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 20 [ 914.114742] ath11k_pci 0000:05:00.0: htc rx completion ep 2 skb pK-error [ 914.115977] ath11k_pci 0000:05:00.0: vdev delete resp for vdev id 0 [ 914.116685] ath11k_pci 0000:05:00.0: vdev 00:03:7f:29:61:11 deleted, vdev_id 0 [ 914.117583] ====================================================== [ 914.117592] WARNING: possible circular locking dependency detected [ 914.117600] 5.16.0-rc1-wt-ath+ #1 Tainted: G OE [ 914.117611] ------------------------------------------------------ [ 914.117618] ifconfig/2805 is trying to acquire lock: [ 914.117628] ffff9c00a62bb548 ((wq_completion)phy0){+.+.}-{0:0}, at: flush_workqueue+0x87/0x470 [ 914.117674] but task is already holding lock: [ 914.117682] ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] [ 914.117872] which lock already depends on the new lock. [ 914.117880] the existing dependency chain (in reverse order) is: [ 914.117888] -> #3 (&rdev->wiphy.mtx){+.+.}-{4:4}: [ 914.117910] __mutex_lock+0xa0/0x9c0 [ 914.117930] mutex_lock_nested+0x1b/0x20 [ 914.117944] reg_process_self_managed_hints+0x3a/0xb0 [cfg80211] [ 914.118093] wiphy_regulatory_register+0x47/0x80 [cfg80211] [ 914.118229] wiphy_register+0x84f/0x9c0 [cfg80211] [ 914.118353] ieee80211_register_hw+0x6b1/0xd90 [mac80211] [ 914.118486] ath11k_mac_register+0x6af/0xb60 [ath11k] [ 914.118550] ath11k_core_qmi_firmware_ready+0x383/0x4a0 [ath11k] [ 914.118598] ath11k_qmi_driver_event_work+0x347/0x4a0 [ath11k] [ 914.118656] process_one_work+0x228/0x670 [ 914.118669] worker_thread+0x4d/0x440 [ 914.118680] kthread+0x16d/0x1b0 [ 914.118697] ret_from_fork+0x22/0x30 [ 914.118714] -> #2 (rtnl_mutex){+.+.}-{4:4}: [ 914.118736] __mutex_lock+0xa0/0x9c0 [ 914.118751] mutex_lock_nested+0x1b/0x20 [ 914.118767] rtnl_lock+0x17/0x20 [ 914.118783] ath11k_regd_update+0x15a/0x260 [ath11k] [ 914.118841] ath11k_regd_update_work+0x15/0x20 [ath11k] [ 914.118897] process_one_work+0x228/0x670 [ 914.118909] worker_thread+0x4d/0x440 [ 914.118920] kthread+0x16d/0x1b0 [ 914.118934] ret_from_fork+0x22/0x30 [ 914.118948] -> #1 ((work_completion)(&ar->regd_update_work)){+.+.}-{0:0}: [ 914.118972] process_one_work+0x1fa/0x670 [ 914.118984] worker_thread+0x4d/0x440 [ 914.118996] kthread+0x16d/0x1b0 [ 914.119010] ret_from_fork+0x22/0x30 [ 914.119023] -> #0 ((wq_completion)phy0){+.+.}-{0:0}: [ 914.119045] __lock_acquire+0x146d/0x1cf0 [ 914.119057] lock_acquire+0x19b/0x360 [ 914.119067] flush_workqueue+0xae/0x470 [ 914.119084] ieee80211_stop_device+0x3b/0x50 [mac80211] [ 914.119260] ieee80211_do_stop+0x5d7/0x830 [mac80211] [ 914.119409] ieee80211_stop+0x45/0x180 [mac80211] [ 914.119557] __dev_close_many+0xb3/0x120 [ 914.119573] __dev_change_flags+0xc3/0x1d0 [ 914.119590] dev_change_flags+0x29/0x70 [ 914.119605] devinet_ioctl+0x653/0x810 [ 914.119620] inet_ioctl+0x193/0x1e0 [ 914.119631] sock_do_ioctl+0x4d/0xf0 [ 914.119649] sock_ioctl+0x262/0x340 [ 914.119665] __x64_sys_ioctl+0x96/0xd0 [ 914.119678] do_syscall_64+0x3d/0xd0 [ 914.119694] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 914.119709] other info that might help us debug this: [ 914.119717] Chain exists of: (wq_completion)phy0 --> rtnl_mutex --> &rdev->wiphy.mtx [ 914.119745] Possible unsafe locking scenario: [ 914.119752] CPU0 CPU1 [ 914.119758] ---- ---- [ 914.119765] lock(&rdev->wiphy.mtx); [ 914.119778] lock(rtnl_mutex); [ 914.119792] lock(&rdev->wiphy.mtx); [ 914.119807] lock((wq_completion)phy0); [ 914.119819] *** DEADLOCK *** [ 914.119827] 2 locks held by ifconfig/2805: [ 914.119837] #0: ffffffffba3dc010 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock+0x17/0x20 [ 914.119872] #1: ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] [ 914.120039] stack backtrace: [ 914.120048] CPU: 0 PID: 2805 Comm: ifconfig Tainted: G OE 5.16.0-rc1-wt-ath+ #1 [ 914.120064] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW (1.33 ) 07/29/2011 [ 914.120074] Call Trace: [ 914.120084] <TASK> [ 914.120094] dump_stack_lvl+0x73/0xa4 [ 914.120119] dump_stack+0x10/0x12 [ 914.120135] print_circular_bug.isra.44+0x221/0x2e0 [ 914.120165] check_noncircular+0x106/0x150 [ 914.120203] __lock_acquire+0x146d/0x1cf0 [ 914.120215] ? __lock_acquire+0x146d/0x1cf0 [ 914.120245] lock_acquire+0x19b/0x360 [ 914.120259] ? flush_workqueue+0x87/0x470 [ 914.120286] ? lockdep_init_map_type+0x6b/0x250 [ 914.120310] flush_workqueue+0xae/0x470 [ 914.120327] ? flush_workqueue+0x87/0x470 [ 914.120344] ? lockdep_hardirqs_on+0xd7/0x150 [ 914.120391] ieee80211_stop_device+0x3b/0x50 [mac80211] [ 914.120565] ? ieee80211_stop_device+0x3b/0x50 [mac80211] [ 914.120736] ieee80211_do_stop+0x5d7/0x830 [mac80211] [ 914.120906] ieee80211_stop+0x45/0x180 [mac80211] [ 914.121060] __dev_close_many+0xb3/0x120 [ 914.121081] __dev_change_flags+0xc3/0x1d0 [ 914.121109] dev_change_flags+0x29/0x70 [ 914.121131] devinet_ioctl+0x653/0x810 [ 914.121149] ? __might_fault+0x77/0x80 [ 914.121179] inet_ioctl+0x193/0x1e0 [ 914.121194] ? inet_ioctl+0x193/0x1e0 [ 914.121218] ? __might_fault+0x77/0x80 [ 914.121238] ? _copy_to_user+0x68/0x80 [ 914.121266] sock_do_ioctl+0x4d/0xf0 [ 914.121283] ? inet_stream_connect+0x60/0x60 [ 914.121297] ? sock_do_ioctl+0x4d/0xf0 [ 914.121329] sock_ioctl+0x262/0x340 [ 914.121347] ? sock_ioctl+0x262/0x340 [ 914.121362] ? exit_to_user_mode_prepare+0x13b/0x280 [ 914.121388] ? syscall_enter_from_user_mode+0x20/0x50 [ 914.121416] __x64_sys_ioctl+0x96/0xd0 [ 914.121430] ? br_ioctl_call+0x90/0x90 [ 914.121445] ? __x64_sys_ioctl+0x96/0xd0 [ 914.121465] do_syscall_64+0x3d/0xd0 [ 914.121482] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 914.121497] RIP: 0033:0x7f0ed051737b [ 914.121513] Code: 0f 1e fa 48 8b 05 15 3b 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e5 3a 0d 00 f7 d8 64 89 01 48 [ 914.121527] RSP: 002b:00007fff7be38b98 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 [ 914.121544] RAX: ffffffffffffffda RBX: 00007fff7be38ba0 RCX: 00007f0ed051737b [ 914.121555] RDX: 00007fff7be38ba0 RSI: 0000000000008914 RDI: 0000000000000004 [ 914.121566] RBP: 00007fff7be38c60 R08: 000000000000000a R09: 0000000000000001 [ 914.121576] R10: 0000000000000000 R11: 0000000000000202 R12: 00000000fffffffe [ 914.121586] R13: 0000000000000004 R14: 0000000000000000 R15: 0000000000000000 [ 914.121620] </TASK> Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> --- drivers/net/wireless/ath/ath11k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 87351e0a269d..a3a8c49b3329 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -6032,7 +6032,7 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk ar = ab->pdevs[pdev_idx].ar; kfree(ab->new_regd[pdev_idx]); ab->new_regd[pdev_idx] = regd; - ieee80211_queue_work(ar->hw, &ar->regd_update_work); + queue_work(ab->workqueue, &ar->regd_update_work); } else { /* This regd would be applied during mac registration and is * held constant throughout for regd intersection purpose -- 2.31.1 -- ath11k mailing list ath11k@lists.infradead.org http://lists.infradead.org/mailman/listinfo/ath11k ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/3] ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work 2021-12-01 7:17 ` Wen Gong @ 2021-12-08 8:33 ` Kalle Valo -1 siblings, 0 replies; 12+ messages in thread From: Kalle Valo @ 2021-12-08 8:33 UTC (permalink / raw) To: Wen Gong; +Cc: ath11k, linux-wireless, quic_wgong Wen Gong <quic_wgong@quicinc.com> wrote: > When enable debug config, it print below warning while shut down wlan > interface shuh as run "ifconfig wlan0 down". > > The reason is because ar->regd_update_work is ran once, and it is will > call wiphy_lock(ar->hw->wiphy) in function ath11k_regd_update() which > is running in workqueue of ieee80211_local queued by ieee80211_queue_work(). > Another thread from "ifconfig wlan0 down" will also accuqire the lock > by wiphy_lock(sdata->local->hw.wiphy) in function ieee80211_stop(), and > then it call ieee80211_stop_device() to flush_workqueue(local->workqueue), > this will wait the workqueue of ieee80211_local finished. Then deadlock > will happen easily if the two thread run meanwhile. > > Below warning disappeared after this change. > > [ 914.088798] ath11k_pci 0000:05:00.0: mac remove interface (vdev 0) > [ 914.088806] ath11k_pci 0000:05:00.0: mac stop 11d scan > [ 914.088810] ath11k_pci 0000:05:00.0: mac stop 11d vdev id 0 > [ 914.088827] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) > [ 914.088841] ath11k_pci 0000:05:00.0: send 11d scan stop vdev id 0 > [ 914.088849] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 > [ 914.088856] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 > [ 914.096434] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 > [ 914.096442] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) > [ 914.096481] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) > [ 914.096491] ath11k_pci 0000:05:00.0: WMI vdev delete id 0 > [ 914.111598] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 > [ 914.111628] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) > [ 914.114659] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 20 > [ 914.114742] ath11k_pci 0000:05:00.0: htc rx completion ep 2 skb pK-error > [ 914.115977] ath11k_pci 0000:05:00.0: vdev delete resp for vdev id 0 > [ 914.116685] ath11k_pci 0000:05:00.0: vdev 00:03:7f:29:61:11 deleted, vdev_id 0 > > [ 914.117583] ====================================================== > [ 914.117592] WARNING: possible circular locking dependency detected > [ 914.117600] 5.16.0-rc1-wt-ath+ #1 Tainted: G OE > [ 914.117611] ------------------------------------------------------ > [ 914.117618] ifconfig/2805 is trying to acquire lock: > [ 914.117628] ffff9c00a62bb548 ((wq_completion)phy0){+.+.}-{0:0}, at: flush_workqueue+0x87/0x470 > [ 914.117674] > but task is already holding lock: > [ 914.117682] ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] > [ 914.117872] > which lock already depends on the new lock. > > [ 914.117880] > the existing dependency chain (in reverse order) is: > [ 914.117888] > -> #3 (&rdev->wiphy.mtx){+.+.}-{4:4}: > [ 914.117910] __mutex_lock+0xa0/0x9c0 > [ 914.117930] mutex_lock_nested+0x1b/0x20 > [ 914.117944] reg_process_self_managed_hints+0x3a/0xb0 [cfg80211] > [ 914.118093] wiphy_regulatory_register+0x47/0x80 [cfg80211] > [ 914.118229] wiphy_register+0x84f/0x9c0 [cfg80211] > [ 914.118353] ieee80211_register_hw+0x6b1/0xd90 [mac80211] > [ 914.118486] ath11k_mac_register+0x6af/0xb60 [ath11k] > [ 914.118550] ath11k_core_qmi_firmware_ready+0x383/0x4a0 [ath11k] > [ 914.118598] ath11k_qmi_driver_event_work+0x347/0x4a0 [ath11k] > [ 914.118656] process_one_work+0x228/0x670 > [ 914.118669] worker_thread+0x4d/0x440 > [ 914.118680] kthread+0x16d/0x1b0 > [ 914.118697] ret_from_fork+0x22/0x30 > [ 914.118714] > -> #2 (rtnl_mutex){+.+.}-{4:4}: > [ 914.118736] __mutex_lock+0xa0/0x9c0 > [ 914.118751] mutex_lock_nested+0x1b/0x20 > [ 914.118767] rtnl_lock+0x17/0x20 > [ 914.118783] ath11k_regd_update+0x15a/0x260 [ath11k] > [ 914.118841] ath11k_regd_update_work+0x15/0x20 [ath11k] > [ 914.118897] process_one_work+0x228/0x670 > [ 914.118909] worker_thread+0x4d/0x440 > [ 914.118920] kthread+0x16d/0x1b0 > [ 914.118934] ret_from_fork+0x22/0x30 > [ 914.118948] > -> #1 ((work_completion)(&ar->regd_update_work)){+.+.}-{0:0}: > [ 914.118972] process_one_work+0x1fa/0x670 > [ 914.118984] worker_thread+0x4d/0x440 > [ 914.118996] kthread+0x16d/0x1b0 > [ 914.119010] ret_from_fork+0x22/0x30 > [ 914.119023] > -> #0 ((wq_completion)phy0){+.+.}-{0:0}: > [ 914.119045] __lock_acquire+0x146d/0x1cf0 > [ 914.119057] lock_acquire+0x19b/0x360 > [ 914.119067] flush_workqueue+0xae/0x470 > [ 914.119084] ieee80211_stop_device+0x3b/0x50 [mac80211] > [ 914.119260] ieee80211_do_stop+0x5d7/0x830 [mac80211] > [ 914.119409] ieee80211_stop+0x45/0x180 [mac80211] > [ 914.119557] __dev_close_many+0xb3/0x120 > [ 914.119573] __dev_change_flags+0xc3/0x1d0 > [ 914.119590] dev_change_flags+0x29/0x70 > [ 914.119605] devinet_ioctl+0x653/0x810 > [ 914.119620] inet_ioctl+0x193/0x1e0 > [ 914.119631] sock_do_ioctl+0x4d/0xf0 > [ 914.119649] sock_ioctl+0x262/0x340 > [ 914.119665] __x64_sys_ioctl+0x96/0xd0 > [ 914.119678] do_syscall_64+0x3d/0xd0 > [ 914.119694] entry_SYSCALL_64_after_hwframe+0x44/0xae > [ 914.119709] > other info that might help us debug this: > > [ 914.119717] Chain exists of: > (wq_completion)phy0 --> rtnl_mutex --> &rdev->wiphy.mtx > > [ 914.119745] Possible unsafe locking scenario: > > [ 914.119752] CPU0 CPU1 > [ 914.119758] ---- ---- > [ 914.119765] lock(&rdev->wiphy.mtx); > [ 914.119778] lock(rtnl_mutex); > [ 914.119792] lock(&rdev->wiphy.mtx); > [ 914.119807] lock((wq_completion)phy0); > [ 914.119819] > *** DEADLOCK *** > > [ 914.119827] 2 locks held by ifconfig/2805: > [ 914.119837] #0: ffffffffba3dc010 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock+0x17/0x20 > [ 914.119872] #1: ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] > [ 914.120039] > stack backtrace: > [ 914.120048] CPU: 0 PID: 2805 Comm: ifconfig Tainted: G OE 5.16.0-rc1-wt-ath+ #1 > [ 914.120064] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW (1.33 ) 07/29/2011 > [ 914.120074] Call Trace: > [ 914.120084] <TASK> > [ 914.120094] dump_stack_lvl+0x73/0xa4 > [ 914.120119] dump_stack+0x10/0x12 > [ 914.120135] print_circular_bug.isra.44+0x221/0x2e0 > [ 914.120165] check_noncircular+0x106/0x150 > [ 914.120203] __lock_acquire+0x146d/0x1cf0 > [ 914.120215] ? __lock_acquire+0x146d/0x1cf0 > [ 914.120245] lock_acquire+0x19b/0x360 > [ 914.120259] ? flush_workqueue+0x87/0x470 > [ 914.120286] ? lockdep_init_map_type+0x6b/0x250 > [ 914.120310] flush_workqueue+0xae/0x470 > [ 914.120327] ? flush_workqueue+0x87/0x470 > [ 914.120344] ? lockdep_hardirqs_on+0xd7/0x150 > [ 914.120391] ieee80211_stop_device+0x3b/0x50 [mac80211] > [ 914.120565] ? ieee80211_stop_device+0x3b/0x50 [mac80211] > [ 914.120736] ieee80211_do_stop+0x5d7/0x830 [mac80211] > [ 914.120906] ieee80211_stop+0x45/0x180 [mac80211] > [ 914.121060] __dev_close_many+0xb3/0x120 > [ 914.121081] __dev_change_flags+0xc3/0x1d0 > [ 914.121109] dev_change_flags+0x29/0x70 > [ 914.121131] devinet_ioctl+0x653/0x810 > [ 914.121149] ? __might_fault+0x77/0x80 > [ 914.121179] inet_ioctl+0x193/0x1e0 > [ 914.121194] ? inet_ioctl+0x193/0x1e0 > [ 914.121218] ? __might_fault+0x77/0x80 > [ 914.121238] ? _copy_to_user+0x68/0x80 > [ 914.121266] sock_do_ioctl+0x4d/0xf0 > [ 914.121283] ? inet_stream_connect+0x60/0x60 > [ 914.121297] ? sock_do_ioctl+0x4d/0xf0 > [ 914.121329] sock_ioctl+0x262/0x340 > [ 914.121347] ? sock_ioctl+0x262/0x340 > [ 914.121362] ? exit_to_user_mode_prepare+0x13b/0x280 > [ 914.121388] ? syscall_enter_from_user_mode+0x20/0x50 > [ 914.121416] __x64_sys_ioctl+0x96/0xd0 > [ 914.121430] ? br_ioctl_call+0x90/0x90 > [ 914.121445] ? __x64_sys_ioctl+0x96/0xd0 > [ 914.121465] do_syscall_64+0x3d/0xd0 > [ 914.121482] entry_SYSCALL_64_after_hwframe+0x44/0xae > [ 914.121497] RIP: 0033:0x7f0ed051737b > [ 914.121513] Code: 0f 1e fa 48 8b 05 15 3b 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e5 3a 0d 00 f7 d8 64 89 01 48 > [ 914.121527] RSP: 002b:00007fff7be38b98 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 > [ 914.121544] RAX: ffffffffffffffda RBX: 00007fff7be38ba0 RCX: 00007f0ed051737b > [ 914.121555] RDX: 00007fff7be38ba0 RSI: 0000000000008914 RDI: 0000000000000004 > [ 914.121566] RBP: 00007fff7be38c60 R08: 000000000000000a R09: 0000000000000001 > [ 914.121576] R10: 0000000000000000 R11: 0000000000000202 R12: 00000000fffffffe > [ 914.121586] R13: 0000000000000004 R14: 0000000000000000 R15: 0000000000000000 > [ 914.121620] </TASK> > > Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 > > Signed-off-by: Wen Gong <quic_wgong@quicinc.com> > Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com> 3 patches applied to ath-next branch of ath.git, thanks. ed05c7cf1286 ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work 0b05ddad8e4b ath11k: add configure country code for QCA6390 and WCN6855 9dcf6808b253 ath11k: add 11d scan offload support -- https://patchwork.kernel.org/project/linux-wireless/patch/20211201071745.17746-2-quic_wgong@quicinc.com/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/3] ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work @ 2021-12-08 8:33 ` Kalle Valo 0 siblings, 0 replies; 12+ messages in thread From: Kalle Valo @ 2021-12-08 8:33 UTC (permalink / raw) To: Wen Gong; +Cc: ath11k, linux-wireless, quic_wgong Wen Gong <quic_wgong@quicinc.com> wrote: > When enable debug config, it print below warning while shut down wlan > interface shuh as run "ifconfig wlan0 down". > > The reason is because ar->regd_update_work is ran once, and it is will > call wiphy_lock(ar->hw->wiphy) in function ath11k_regd_update() which > is running in workqueue of ieee80211_local queued by ieee80211_queue_work(). > Another thread from "ifconfig wlan0 down" will also accuqire the lock > by wiphy_lock(sdata->local->hw.wiphy) in function ieee80211_stop(), and > then it call ieee80211_stop_device() to flush_workqueue(local->workqueue), > this will wait the workqueue of ieee80211_local finished. Then deadlock > will happen easily if the two thread run meanwhile. > > Below warning disappeared after this change. > > [ 914.088798] ath11k_pci 0000:05:00.0: mac remove interface (vdev 0) > [ 914.088806] ath11k_pci 0000:05:00.0: mac stop 11d scan > [ 914.088810] ath11k_pci 0000:05:00.0: mac stop 11d vdev id 0 > [ 914.088827] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) > [ 914.088841] ath11k_pci 0000:05:00.0: send 11d scan stop vdev id 0 > [ 914.088849] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 > [ 914.088856] ath11k_pci 0000:05:00.0: htc insufficient credits ep 2 required 1 available 0 > [ 914.096434] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 > [ 914.096442] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) > [ 914.096481] ath11k_pci 0000:05:00.0: htc ep 2 consumed 1 credits (total 0) > [ 914.096491] ath11k_pci 0000:05:00.0: WMI vdev delete id 0 > [ 914.111598] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 16 > [ 914.111628] ath11k_pci 0000:05:00.0: htc ep 2 got 1 credits (total 1) > [ 914.114659] ath11k_pci 0000:05:00.0: rx ce pipe 2 len 20 > [ 914.114742] ath11k_pci 0000:05:00.0: htc rx completion ep 2 skb pK-error > [ 914.115977] ath11k_pci 0000:05:00.0: vdev delete resp for vdev id 0 > [ 914.116685] ath11k_pci 0000:05:00.0: vdev 00:03:7f:29:61:11 deleted, vdev_id 0 > > [ 914.117583] ====================================================== > [ 914.117592] WARNING: possible circular locking dependency detected > [ 914.117600] 5.16.0-rc1-wt-ath+ #1 Tainted: G OE > [ 914.117611] ------------------------------------------------------ > [ 914.117618] ifconfig/2805 is trying to acquire lock: > [ 914.117628] ffff9c00a62bb548 ((wq_completion)phy0){+.+.}-{0:0}, at: flush_workqueue+0x87/0x470 > [ 914.117674] > but task is already holding lock: > [ 914.117682] ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] > [ 914.117872] > which lock already depends on the new lock. > > [ 914.117880] > the existing dependency chain (in reverse order) is: > [ 914.117888] > -> #3 (&rdev->wiphy.mtx){+.+.}-{4:4}: > [ 914.117910] __mutex_lock+0xa0/0x9c0 > [ 914.117930] mutex_lock_nested+0x1b/0x20 > [ 914.117944] reg_process_self_managed_hints+0x3a/0xb0 [cfg80211] > [ 914.118093] wiphy_regulatory_register+0x47/0x80 [cfg80211] > [ 914.118229] wiphy_register+0x84f/0x9c0 [cfg80211] > [ 914.118353] ieee80211_register_hw+0x6b1/0xd90 [mac80211] > [ 914.118486] ath11k_mac_register+0x6af/0xb60 [ath11k] > [ 914.118550] ath11k_core_qmi_firmware_ready+0x383/0x4a0 [ath11k] > [ 914.118598] ath11k_qmi_driver_event_work+0x347/0x4a0 [ath11k] > [ 914.118656] process_one_work+0x228/0x670 > [ 914.118669] worker_thread+0x4d/0x440 > [ 914.118680] kthread+0x16d/0x1b0 > [ 914.118697] ret_from_fork+0x22/0x30 > [ 914.118714] > -> #2 (rtnl_mutex){+.+.}-{4:4}: > [ 914.118736] __mutex_lock+0xa0/0x9c0 > [ 914.118751] mutex_lock_nested+0x1b/0x20 > [ 914.118767] rtnl_lock+0x17/0x20 > [ 914.118783] ath11k_regd_update+0x15a/0x260 [ath11k] > [ 914.118841] ath11k_regd_update_work+0x15/0x20 [ath11k] > [ 914.118897] process_one_work+0x228/0x670 > [ 914.118909] worker_thread+0x4d/0x440 > [ 914.118920] kthread+0x16d/0x1b0 > [ 914.118934] ret_from_fork+0x22/0x30 > [ 914.118948] > -> #1 ((work_completion)(&ar->regd_update_work)){+.+.}-{0:0}: > [ 914.118972] process_one_work+0x1fa/0x670 > [ 914.118984] worker_thread+0x4d/0x440 > [ 914.118996] kthread+0x16d/0x1b0 > [ 914.119010] ret_from_fork+0x22/0x30 > [ 914.119023] > -> #0 ((wq_completion)phy0){+.+.}-{0:0}: > [ 914.119045] __lock_acquire+0x146d/0x1cf0 > [ 914.119057] lock_acquire+0x19b/0x360 > [ 914.119067] flush_workqueue+0xae/0x470 > [ 914.119084] ieee80211_stop_device+0x3b/0x50 [mac80211] > [ 914.119260] ieee80211_do_stop+0x5d7/0x830 [mac80211] > [ 914.119409] ieee80211_stop+0x45/0x180 [mac80211] > [ 914.119557] __dev_close_many+0xb3/0x120 > [ 914.119573] __dev_change_flags+0xc3/0x1d0 > [ 914.119590] dev_change_flags+0x29/0x70 > [ 914.119605] devinet_ioctl+0x653/0x810 > [ 914.119620] inet_ioctl+0x193/0x1e0 > [ 914.119631] sock_do_ioctl+0x4d/0xf0 > [ 914.119649] sock_ioctl+0x262/0x340 > [ 914.119665] __x64_sys_ioctl+0x96/0xd0 > [ 914.119678] do_syscall_64+0x3d/0xd0 > [ 914.119694] entry_SYSCALL_64_after_hwframe+0x44/0xae > [ 914.119709] > other info that might help us debug this: > > [ 914.119717] Chain exists of: > (wq_completion)phy0 --> rtnl_mutex --> &rdev->wiphy.mtx > > [ 914.119745] Possible unsafe locking scenario: > > [ 914.119752] CPU0 CPU1 > [ 914.119758] ---- ---- > [ 914.119765] lock(&rdev->wiphy.mtx); > [ 914.119778] lock(rtnl_mutex); > [ 914.119792] lock(&rdev->wiphy.mtx); > [ 914.119807] lock((wq_completion)phy0); > [ 914.119819] > *** DEADLOCK *** > > [ 914.119827] 2 locks held by ifconfig/2805: > [ 914.119837] #0: ffffffffba3dc010 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock+0x17/0x20 > [ 914.119872] #1: ffff9c00baea07d0 (&rdev->wiphy.mtx){+.+.}-{4:4}, at: ieee80211_stop+0x38/0x180 [mac80211] > [ 914.120039] > stack backtrace: > [ 914.120048] CPU: 0 PID: 2805 Comm: ifconfig Tainted: G OE 5.16.0-rc1-wt-ath+ #1 > [ 914.120064] Hardware name: LENOVO 418065C/418065C, BIOS 83ET63WW (1.33 ) 07/29/2011 > [ 914.120074] Call Trace: > [ 914.120084] <TASK> > [ 914.120094] dump_stack_lvl+0x73/0xa4 > [ 914.120119] dump_stack+0x10/0x12 > [ 914.120135] print_circular_bug.isra.44+0x221/0x2e0 > [ 914.120165] check_noncircular+0x106/0x150 > [ 914.120203] __lock_acquire+0x146d/0x1cf0 > [ 914.120215] ? __lock_acquire+0x146d/0x1cf0 > [ 914.120245] lock_acquire+0x19b/0x360 > [ 914.120259] ? flush_workqueue+0x87/0x470 > [ 914.120286] ? lockdep_init_map_type+0x6b/0x250 > [ 914.120310] flush_workqueue+0xae/0x470 > [ 914.120327] ? flush_workqueue+0x87/0x470 > [ 914.120344] ? lockdep_hardirqs_on+0xd7/0x150 > [ 914.120391] ieee80211_stop_device+0x3b/0x50 [mac80211] > [ 914.120565] ? ieee80211_stop_device+0x3b/0x50 [mac80211] > [ 914.120736] ieee80211_do_stop+0x5d7/0x830 [mac80211] > [ 914.120906] ieee80211_stop+0x45/0x180 [mac80211] > [ 914.121060] __dev_close_many+0xb3/0x120 > [ 914.121081] __dev_change_flags+0xc3/0x1d0 > [ 914.121109] dev_change_flags+0x29/0x70 > [ 914.121131] devinet_ioctl+0x653/0x810 > [ 914.121149] ? __might_fault+0x77/0x80 > [ 914.121179] inet_ioctl+0x193/0x1e0 > [ 914.121194] ? inet_ioctl+0x193/0x1e0 > [ 914.121218] ? __might_fault+0x77/0x80 > [ 914.121238] ? _copy_to_user+0x68/0x80 > [ 914.121266] sock_do_ioctl+0x4d/0xf0 > [ 914.121283] ? inet_stream_connect+0x60/0x60 > [ 914.121297] ? sock_do_ioctl+0x4d/0xf0 > [ 914.121329] sock_ioctl+0x262/0x340 > [ 914.121347] ? sock_ioctl+0x262/0x340 > [ 914.121362] ? exit_to_user_mode_prepare+0x13b/0x280 > [ 914.121388] ? syscall_enter_from_user_mode+0x20/0x50 > [ 914.121416] __x64_sys_ioctl+0x96/0xd0 > [ 914.121430] ? br_ioctl_call+0x90/0x90 > [ 914.121445] ? __x64_sys_ioctl+0x96/0xd0 > [ 914.121465] do_syscall_64+0x3d/0xd0 > [ 914.121482] entry_SYSCALL_64_after_hwframe+0x44/0xae > [ 914.121497] RIP: 0033:0x7f0ed051737b > [ 914.121513] Code: 0f 1e fa 48 8b 05 15 3b 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e5 3a 0d 00 f7 d8 64 89 01 48 > [ 914.121527] RSP: 002b:00007fff7be38b98 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 > [ 914.121544] RAX: ffffffffffffffda RBX: 00007fff7be38ba0 RCX: 00007f0ed051737b > [ 914.121555] RDX: 00007fff7be38ba0 RSI: 0000000000008914 RDI: 0000000000000004 > [ 914.121566] RBP: 00007fff7be38c60 R08: 000000000000000a R09: 0000000000000001 > [ 914.121576] R10: 0000000000000000 R11: 0000000000000202 R12: 00000000fffffffe > [ 914.121586] R13: 0000000000000004 R14: 0000000000000000 R15: 0000000000000000 > [ 914.121620] </TASK> > > Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 > > Signed-off-by: Wen Gong <quic_wgong@quicinc.com> > Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com> 3 patches applied to ath-next branch of ath.git, thanks. ed05c7cf1286 ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work 0b05ddad8e4b ath11k: add configure country code for QCA6390 and WCN6855 9dcf6808b253 ath11k: add 11d scan offload support -- https://patchwork.kernel.org/project/linux-wireless/patch/20211201071745.17746-2-quic_wgong@quicinc.com/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches -- ath11k mailing list ath11k@lists.infradead.org http://lists.infradead.org/mailman/listinfo/ath11k ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 2/3] ath11k: add configure country code for QCA6390 and WCN6855 2021-12-01 7:17 ` Wen Gong @ 2021-12-01 7:17 ` Wen Gong -1 siblings, 0 replies; 12+ messages in thread From: Wen Gong @ 2021-12-01 7:17 UTC (permalink / raw) To: ath11k; +Cc: linux-wireless, quic_wgong Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware which is used for QCA6390 and WCN6855. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> --- drivers/net/wireless/ath/ath11k/wmi.c | 36 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/wmi.h | 12 +++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index a3a8c49b3329..47361256bfeb 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2798,6 +2798,42 @@ ath11k_wmi_send_init_country_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, + struct wmi_set_current_country_params *param) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_set_current_country_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_current_country_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SET_CURRENT_COUNTRY_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->pdev_id = ar->pdev->pdev_id; + memcpy(&cmd->new_alpha2, ¶m->alpha2, 3); + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "set current country pdev id %d alpha2 %c%c\n", + ar->pdev->pdev_id, + param->alpha2[0], + param->alpha2[1]); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, struct thermal_mitigation_params *param) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 8e8bac1b7370..49db414d0bf3 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3770,6 +3770,16 @@ struct stats_request_params { u32 pdev_id; }; +struct wmi_set_current_country_params { + u8 alpha2[3]; +}; + +struct wmi_set_current_country_cmd { + u32 tlv_header; + u32 pdev_id; + u32 new_alpha2; +} __packed; + enum set_init_cc_type { WMI_COUNTRY_INFO_TYPE_ALPHA, WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE, @@ -5433,6 +5443,8 @@ int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, u32 tid, u32 initiator, u32 reason); int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, u32 vdev_id, u32 bcn_ctrl_op); +int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, + struct wmi_set_current_country_params *param); int ath11k_wmi_send_init_country_cmd(struct ath11k *ar, struct wmi_init_country_params init_cc_param); -- 2.31.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 2/3] ath11k: add configure country code for QCA6390 and WCN6855 @ 2021-12-01 7:17 ` Wen Gong 0 siblings, 0 replies; 12+ messages in thread From: Wen Gong @ 2021-12-01 7:17 UTC (permalink / raw) To: ath11k; +Cc: linux-wireless, quic_wgong Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware which is used for QCA6390 and WCN6855. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1 Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> --- drivers/net/wireless/ath/ath11k/wmi.c | 36 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/wmi.h | 12 +++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index a3a8c49b3329..47361256bfeb 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2798,6 +2798,42 @@ ath11k_wmi_send_init_country_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, + struct wmi_set_current_country_params *param) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_set_current_country_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_current_country_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SET_CURRENT_COUNTRY_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->pdev_id = ar->pdev->pdev_id; + memcpy(&cmd->new_alpha2, ¶m->alpha2, 3); + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "set current country pdev id %d alpha2 %c%c\n", + ar->pdev->pdev_id, + param->alpha2[0], + param->alpha2[1]); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, struct thermal_mitigation_params *param) diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 8e8bac1b7370..49db414d0bf3 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3770,6 +3770,16 @@ struct stats_request_params { u32 pdev_id; }; +struct wmi_set_current_country_params { + u8 alpha2[3]; +}; + +struct wmi_set_current_country_cmd { + u32 tlv_header; + u32 pdev_id; + u32 new_alpha2; +} __packed; + enum set_init_cc_type { WMI_COUNTRY_INFO_TYPE_ALPHA, WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE, @@ -5433,6 +5443,8 @@ int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, u32 tid, u32 initiator, u32 reason); int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, u32 vdev_id, u32 bcn_ctrl_op); +int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, + struct wmi_set_current_country_params *param); int ath11k_wmi_send_init_country_cmd(struct ath11k *ar, struct wmi_init_country_params init_cc_param); -- 2.31.1 -- ath11k mailing list ath11k@lists.infradead.org http://lists.infradead.org/mailman/listinfo/ath11k ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 2/3] ath11k: add configure country code for QCA6390 and WCN6855 2021-12-01 7:17 ` Wen Gong @ 2022-01-06 7:18 ` Dan Carpenter -1 siblings, 0 replies; 12+ messages in thread From: Dan Carpenter @ 2022-01-06 7:18 UTC (permalink / raw) To: Wen Gong; +Cc: ath11k, linux-wireless On Wed, Dec 01, 2021 at 02:17:44AM -0500, Wen Gong wrote: > +int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, > + struct wmi_set_current_country_params *param) > +{ > + struct ath11k_pdev_wmi *wmi = ar->wmi; > + struct wmi_set_current_country_cmd *cmd; > + struct sk_buff *skb; > + int ret; > + > + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); > + if (!skb) > + return -ENOMEM; > + > + cmd = (struct wmi_set_current_country_cmd *)skb->data; > + cmd->tlv_header = > + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SET_CURRENT_COUNTRY_CMD) | > + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); > + > + cmd->pdev_id = ar->pdev->pdev_id; > + memcpy(&cmd->new_alpha2, ¶m->alpha2, 3); cmd->new_alpha2 is a u32 in this driver. (In a different driver it is a 3 byte array). So this will leave the last byte as random garbage. Probably harmless but it leads to a Smatch static checker warning. drivers/net/wireless/ath/ath11k/wmi.c:2837 ath11k_wmi_send_set_current_country_cmd() warn: not copying enough bytes for '&cmd->new_alpha2' (4 vs 3 bytes) > + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); > + > + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, > + "set current country pdev id %d alpha2 %c%c\n", > + ar->pdev->pdev_id, > + param->alpha2[0], > + param->alpha2[1]); > + > + if (ret) { > + ath11k_warn(ar->ab, > + "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); > + dev_kfree_skb(skb); > + } > + > + return ret; > +} regards, dan carpenter ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 2/3] ath11k: add configure country code for QCA6390 and WCN6855 @ 2022-01-06 7:18 ` Dan Carpenter 0 siblings, 0 replies; 12+ messages in thread From: Dan Carpenter @ 2022-01-06 7:18 UTC (permalink / raw) To: Wen Gong; +Cc: ath11k, linux-wireless On Wed, Dec 01, 2021 at 02:17:44AM -0500, Wen Gong wrote: > +int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, > + struct wmi_set_current_country_params *param) > +{ > + struct ath11k_pdev_wmi *wmi = ar->wmi; > + struct wmi_set_current_country_cmd *cmd; > + struct sk_buff *skb; > + int ret; > + > + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); > + if (!skb) > + return -ENOMEM; > + > + cmd = (struct wmi_set_current_country_cmd *)skb->data; > + cmd->tlv_header = > + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SET_CURRENT_COUNTRY_CMD) | > + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); > + > + cmd->pdev_id = ar->pdev->pdev_id; > + memcpy(&cmd->new_alpha2, ¶m->alpha2, 3); cmd->new_alpha2 is a u32 in this driver. (In a different driver it is a 3 byte array). So this will leave the last byte as random garbage. Probably harmless but it leads to a Smatch static checker warning. drivers/net/wireless/ath/ath11k/wmi.c:2837 ath11k_wmi_send_set_current_country_cmd() warn: not copying enough bytes for '&cmd->new_alpha2' (4 vs 3 bytes) > + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); > + > + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, > + "set current country pdev id %d alpha2 %c%c\n", > + ar->pdev->pdev_id, > + param->alpha2[0], > + param->alpha2[1]); > + > + if (ret) { > + ath11k_warn(ar->ab, > + "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); > + dev_kfree_skb(skb); > + } > + > + return ret; > +} regards, dan carpenter -- ath11k mailing list ath11k@lists.infradead.org http://lists.infradead.org/mailman/listinfo/ath11k ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 3/3] ath11k: add 11d scan offload support 2021-12-01 7:17 ` Wen Gong @ 2021-12-01 7:17 ` Wen Gong -1 siblings, 0 replies; 12+ messages in thread From: Wen Gong @ 2021-12-01 7:17 UTC (permalink / raw) To: ath11k; +Cc: linux-wireless, quic_wgong Add handler for WMI_11D_NEW_COUNTRY_EVENTID, WMI_11D_SCAN_START_CMDID, WMI_11D_SCAN_STOP_CMDID. After vdev create for STATION, send WMI_11D_SCAN_START_CMDID to firmware and wait firmware complete it, the scan from mac80211 also need to wait the 11d scan finished, and send WMI_11D_SCAN_STOP_CMDID to firmware before vdev delete for STATION. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> --- drivers/net/wireless/ath/ath11k/core.c | 31 +++++ drivers/net/wireless/ath/ath11k/core.h | 9 ++ drivers/net/wireless/ath/ath11k/mac.c | 163 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/mac.h | 7 ++ drivers/net/wireless/ath/ath11k/reg.c | 15 +++ drivers/net/wireless/ath/ath11k/wmi.c | 109 +++++++++++++++++ drivers/net/wireless/ath/ath11k/wmi.h | 27 ++++ 7 files changed, 360 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index a3a9bfef0c38..cd7e568a6c07 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -1122,6 +1122,7 @@ void ath11k_core_halt(struct ath11k *ar) ath11k_mac_peer_cleanup_all(ar); cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ab->update_11d_work); rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL); synchronize_rcu(); @@ -1129,6 +1130,34 @@ void ath11k_core_halt(struct ath11k *ar) idr_init(&ar->txmgmt_idr); } +static void ath11k_update_11d(struct work_struct *work) +{ + struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); + struct ath11k *ar; + struct ath11k_pdev *pdev; + struct wmi_set_current_country_params set_current_param = {}; + int ret, i; + + spin_lock_bh(&ab->base_lock); + memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n", + set_current_param.alpha2[0], + set_current_param.alpha2[1]); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + if (ret) + ath11k_warn(ar->ab, + "pdev id %d failed set current country code: %d\n", + i, ret); + } +} + static void ath11k_core_restart(struct work_struct *work) { struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work); @@ -1298,12 +1327,14 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, mutex_init(&ab->core_lock); spin_lock_init(&ab->base_lock); + mutex_init(&ab->vdev_id_11d_lock); INIT_LIST_HEAD(&ab->peers); init_waitqueue_head(&ab->peer_mapping_wq); init_waitqueue_head(&ab->wmi_ab.tx_credits_wq); init_waitqueue_head(&ab->qmi.cold_boot_waitq); INIT_WORK(&ab->restart_work, ath11k_core_restart); + INIT_WORK(&ab->update_11d_work, ath11k_update_11d); timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); init_completion(&ab->wow.wakeup_completed); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 7b1770ae0e7c..89a47d63e088 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -587,6 +587,11 @@ struct ath11k { #endif bool dfs_block_radar_events; struct ath11k_thermal thermal; + u32 vdev_id_11d_scan; + struct completion finish_11d_scan; + struct completion finish_11d_ch_list; + bool pending_11d; + bool regdom_set_by_user; }; struct ath11k_band_cap { @@ -761,6 +766,8 @@ struct ath11k_base { struct completion driver_recovery; struct workqueue_struct *workqueue; struct work_struct restart_work; + struct work_struct update_11d_work; + u8 new_alpha2[3]; struct { /* protected by data_lock */ u32 fw_crash_counter; @@ -770,6 +777,8 @@ struct ath11k_base { struct ath11k_dbring_cap *db_caps; u32 num_db_cap; + /* To synchronize 11d scan vdev id */ + struct mutex vdev_id_11d_lock; struct timer_list mon_reap_timer; struct completion htc_suspend; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 06d20658586a..de897a7500c6 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2680,6 +2680,8 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, if (ret) ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", arvif->vdev_id, ret); + + ath11k_mac_11d_scan_stop_all(ar->ab); } static void ath11k_bss_disassoc(struct ieee80211_hw *hw, @@ -3409,6 +3411,7 @@ static int ath11k_start_scan(struct ath11k *ar, struct scan_req_params *arg) { int ret; + unsigned long timeout = 1 * HZ; lockdep_assert_held(&ar->conf_mutex); @@ -3419,7 +3422,14 @@ static int ath11k_start_scan(struct ath11k *ar, if (ret) return ret; - ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ); + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) { + timeout = 5 * HZ; + + if (ar->supports_6ghz) + timeout += 5 * HZ; + } + + ret = wait_for_completion_timeout(&ar->scan.started, timeout); if (ret == 0) { ret = ath11k_scan_stop(ar); if (ret) @@ -3476,6 +3486,26 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, if (ret) goto exit; + /* Currently the pending_11d=true only happened 1 time while + * wlan interface up in ath11k_mac_11d_scan_start(), it is called by + * ath11k_mac_op_add_interface(), after wlan interface up, + * pending_11d=false always. + * If remove below wait, it always happened scan fail and lead connect + * fail while wlan interface up, because it has a 11d scan which is running + * in firmware, and lead this scan failed. + */ + if (ar->pending_11d) { + long time_left; + unsigned long timeout = 5 * HZ; + + if (ar->supports_6ghz) + timeout += 5 * HZ; + + time_left = wait_for_completion_timeout(&ar->finish_11d_ch_list, timeout); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac wait 11d channel list time left %ld\n", time_left); + } + memset(&arg, 0, sizeof(arg)); ath11k_wmi_start_scan_init(ar, &arg); arg.vdev_id = arvif->vdev_id; @@ -5620,6 +5650,7 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ar->ab->update_11d_work); spin_lock_bh(&ar->data_lock); list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { @@ -5773,6 +5804,122 @@ static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw, } } +static bool ath11k_mac_vif_ap_active_any(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_pdev *pdev; + struct ath11k_vif *arvif; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP) + return true; + } + } + return false; +} + +void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait) +{ + struct wmi_11d_scan_start_params param; + int ret; + + mutex_lock(&ar->ab->vdev_id_11d_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev id for 11d scan %d\n", + ar->vdev_id_11d_scan); + + if (ar->regdom_set_by_user) + goto fin; + + if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) + goto fin; + + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) + goto fin; + + if (ath11k_mac_vif_ap_active_any(ar->ab)) + goto fin; + + param.vdev_id = vdev_id; + param.start_interval_msec = 0; + param.scan_period_msec = ATH11K_SCAN_11D_INTERVAL; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac start 11d scan\n"); + + if (wait) + reinit_completion(&ar->finish_11d_scan); + + ret = ath11k_wmi_send_11d_scan_start_cmd(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n", + vdev_id, ret); + } else { + ar->vdev_id_11d_scan = vdev_id; + if (wait) { + ar->pending_11d = true; + ret = wait_for_completion_timeout(&ar->finish_11d_scan, + 5 * HZ); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac 11d scan left time %d\n", ret); + + if (!ret) + ar->pending_11d = false; + } + } + +fin: + mutex_unlock(&ar->ab->vdev_id_11d_lock); +} + +void ath11k_mac_11d_scan_stop(struct ath11k *ar) +{ + int ret; + u32 vdev_id; + + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) + return; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d scan\n"); + + mutex_lock(&ar->ab->vdev_id_11d_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d vdev id %d\n", + ar->vdev_id_11d_scan); + + if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) { + vdev_id = ar->vdev_id_11d_scan; + + ret = ath11k_wmi_send_11d_scan_stop_cmd(ar, vdev_id); + if (ret) + ath11k_warn(ar->ab, + "failed to stopt 11d scan vdev %d ret: %d\n", + vdev_id, ret); + else + ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; + } + mutex_unlock(&ar->ab->vdev_id_11d_lock); +} + +void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_pdev *pdev; + int i; + + ath11k_dbg(ab, ATH11K_DBG_MAC, "mac stop soc 11d scan\n"); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + ath11k_mac_11d_scan_stop(ar); + } +} + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -5906,6 +6053,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto err_peer_del; } + + ath11k_mac_11d_scan_stop_all(ar->ab); break; case WMI_VDEV_TYPE_STA: param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY; @@ -5945,6 +6094,9 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto err_peer_del; } + + ath11k_mac_11d_scan_start(ar, arvif->vdev_id, true); + break; case WMI_VDEV_TYPE_MONITOR: set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); @@ -6046,6 +6198,9 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", arvif->vdev_id); + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + ath11k_mac_11d_scan_stop(ar); + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr); if (ret) @@ -6764,6 +6919,9 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, ret); } + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + ath11k_mac_11d_scan_start(ar, arvif->vdev_id, false); + mutex_unlock(&ar->conf_mutex); } @@ -8165,6 +8323,9 @@ int ath11k_mac_allocate(struct ath11k_base *ab) ar->monitor_vdev_id = -1; clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); + ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; + init_completion(&ar->finish_11d_scan); + init_completion(&ar->finish_11d_ch_list); } return 0; diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 359e5e9ca904..035d6738c20b 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -127,6 +127,13 @@ struct ath11k_generic_iter { extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default; +#define ATH11K_SCAN_11D_INTERVAL 600000 +#define ATH11K_11D_INVALID_VDEV_ID 0xFFFF + +void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait); +void ath11k_mac_11d_scan_stop(struct ath11k *ar); +void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab); + void ath11k_mac_destroy(struct ath11k_base *ab); void ath11k_mac_unregister(struct ath11k_base *ab); int ath11k_mac_register(struct ath11k_base *ab); diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 8606170ba80d..1f8a81987187 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -86,6 +86,9 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) if (ret) ath11k_warn(ar->ab, "INIT Country code set to fw failed : %d\n", ret); + + ath11k_mac_11d_scan_stop(ar); + ar->regdom_set_by_user = true; } int ath11k_reg_update_chan_list(struct ath11k *ar) @@ -179,6 +182,11 @@ int ath11k_reg_update_chan_list(struct ath11k *ar) ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params); kfree(params); + if (ar->pending_11d) { + complete(&ar->finish_11d_ch_list); + ar->pending_11d = false; + } + return ret; } @@ -244,8 +252,15 @@ int ath11k_regd_update(struct ath11k *ar) goto err; } + if (ar->pending_11d) + complete(&ar->finish_11d_scan); + rtnl_lock(); wiphy_lock(ar->hw->wiphy); + + if (ar->pending_11d) + reinit_completion(&ar->finish_11d_ch_list); + ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); wiphy_unlock(ar->hw->wiphy); rtnl_unlock(); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 47361256bfeb..db90af054f05 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -130,6 +130,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, [WMI_TAG_OBSS_COLOR_COLLISION_EVT] = { .min_len = sizeof(struct wmi_obss_color_collision_event) }, + [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { + .min_len = sizeof(struct wmi_11d_new_cc_ev) }, }; #define PRIMAP(_hw_mode_) \ @@ -2898,6 +2900,75 @@ ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, + struct wmi_11d_scan_start_params *param) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_11d_scan_start_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_11d_scan_start_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_START_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = param->vdev_id; + cmd->scan_period_msec = param->scan_period_msec; + cmd->start_interval_msec = param->start_interval_msec; + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "send 11d scan start vdev id %d period %d ms internal %d ms\n", + cmd->vdev_id, + cmd->scan_period_msec, + cmd->start_interval_msec); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + +int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_11d_scan_stop_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_11d_scan_stop_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_STOP_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = vdev_id; + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "send 11d scan stop vdev id %d\n", + cmd->vdev_id); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter) { struct ath11k_pdev_wmi *wmi = ar->wmi; @@ -5938,6 +6009,41 @@ static void ath11k_wmi_op_ep_tx_credits(struct ath11k_base *ab) wake_up(&ab->wmi_ab.tx_credits_wq); } +static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *skb) +{ + const struct wmi_11d_new_cc_ev *ev; + const void **tb; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT]; + if (!ev) { + kfree(tb); + ath11k_warn(ab, "failed to fetch 11d new cc ev"); + return -EPROTO; + } + + spin_lock_bh(&ab->base_lock); + memcpy(&ab->new_alpha2, &ev->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi 11d new cc %c%c\n", + ab->new_alpha2[0], + ab->new_alpha2[1]); + + kfree(tb); + + queue_work(ab->workqueue, &ab->update_11d_work); + + return 0; +} + static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, struct sk_buff *skb) { @@ -7333,6 +7439,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_WOW_WAKEUP_HOST_EVENTID: ath11k_wmi_event_wow_wakeup_host(ab, skb); break; + case WMI_11D_NEW_COUNTRY_EVENTID: + ath11k_reg_11d_new_cc_event(ab, skb); + break; /* TODO: Add remaining events */ default: ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 49db414d0bf3..735f5a560b18 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3813,6 +3813,28 @@ struct wmi_init_country_cmd { } cc_info; } __packed; +struct wmi_11d_scan_start_params { + u32 vdev_id; + u32 scan_period_msec; + u32 start_interval_msec; +}; + +struct wmi_11d_scan_start_cmd { + u32 tlv_header; + u32 vdev_id; + u32 scan_period_msec; + u32 start_interval_msec; +} __packed; + +struct wmi_11d_scan_stop_cmd { + u32 tlv_header; + u32 vdev_id; +} __packed; + +struct wmi_11d_new_cc_ev { + u32 new_alpha2; +} __packed; + #define THERMAL_LEVELS 1 struct tt_level_config { u32 tmplwm; @@ -5448,6 +5470,11 @@ int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, int ath11k_wmi_send_init_country_cmd(struct ath11k *ar, struct wmi_init_country_params init_cc_param); + +int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, + struct wmi_11d_scan_start_params *param); +int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id); + int ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, struct thermal_mitigation_params *param); -- 2.31.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 3/3] ath11k: add 11d scan offload support @ 2021-12-01 7:17 ` Wen Gong 0 siblings, 0 replies; 12+ messages in thread From: Wen Gong @ 2021-12-01 7:17 UTC (permalink / raw) To: ath11k; +Cc: linux-wireless, quic_wgong Add handler for WMI_11D_NEW_COUNTRY_EVENTID, WMI_11D_SCAN_START_CMDID, WMI_11D_SCAN_STOP_CMDID. After vdev create for STATION, send WMI_11D_SCAN_START_CMDID to firmware and wait firmware complete it, the scan from mac80211 also need to wait the 11d scan finished, and send WMI_11D_SCAN_STOP_CMDID to firmware before vdev delete for STATION. Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01230-QCAHSTSWPLZ_V2_TO_X86-1 Signed-off-by: Wen Gong <quic_wgong@quicinc.com> --- drivers/net/wireless/ath/ath11k/core.c | 31 +++++ drivers/net/wireless/ath/ath11k/core.h | 9 ++ drivers/net/wireless/ath/ath11k/mac.c | 163 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/mac.h | 7 ++ drivers/net/wireless/ath/ath11k/reg.c | 15 +++ drivers/net/wireless/ath/ath11k/wmi.c | 109 +++++++++++++++++ drivers/net/wireless/ath/ath11k/wmi.h | 27 ++++ 7 files changed, 360 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index a3a9bfef0c38..cd7e568a6c07 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -1122,6 +1122,7 @@ void ath11k_core_halt(struct ath11k *ar) ath11k_mac_peer_cleanup_all(ar); cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ab->update_11d_work); rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL); synchronize_rcu(); @@ -1129,6 +1130,34 @@ void ath11k_core_halt(struct ath11k *ar) idr_init(&ar->txmgmt_idr); } +static void ath11k_update_11d(struct work_struct *work) +{ + struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); + struct ath11k *ar; + struct ath11k_pdev *pdev; + struct wmi_set_current_country_params set_current_param = {}; + int ret, i; + + spin_lock_bh(&ab->base_lock); + memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n", + set_current_param.alpha2[0], + set_current_param.alpha2[1]); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + if (ret) + ath11k_warn(ar->ab, + "pdev id %d failed set current country code: %d\n", + i, ret); + } +} + static void ath11k_core_restart(struct work_struct *work) { struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work); @@ -1298,12 +1327,14 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, mutex_init(&ab->core_lock); spin_lock_init(&ab->base_lock); + mutex_init(&ab->vdev_id_11d_lock); INIT_LIST_HEAD(&ab->peers); init_waitqueue_head(&ab->peer_mapping_wq); init_waitqueue_head(&ab->wmi_ab.tx_credits_wq); init_waitqueue_head(&ab->qmi.cold_boot_waitq); INIT_WORK(&ab->restart_work, ath11k_core_restart); + INIT_WORK(&ab->update_11d_work, ath11k_update_11d); timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); init_completion(&ab->wow.wakeup_completed); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 7b1770ae0e7c..89a47d63e088 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -587,6 +587,11 @@ struct ath11k { #endif bool dfs_block_radar_events; struct ath11k_thermal thermal; + u32 vdev_id_11d_scan; + struct completion finish_11d_scan; + struct completion finish_11d_ch_list; + bool pending_11d; + bool regdom_set_by_user; }; struct ath11k_band_cap { @@ -761,6 +766,8 @@ struct ath11k_base { struct completion driver_recovery; struct workqueue_struct *workqueue; struct work_struct restart_work; + struct work_struct update_11d_work; + u8 new_alpha2[3]; struct { /* protected by data_lock */ u32 fw_crash_counter; @@ -770,6 +777,8 @@ struct ath11k_base { struct ath11k_dbring_cap *db_caps; u32 num_db_cap; + /* To synchronize 11d scan vdev id */ + struct mutex vdev_id_11d_lock; struct timer_list mon_reap_timer; struct completion htc_suspend; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 06d20658586a..de897a7500c6 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2680,6 +2680,8 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, if (ret) ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", arvif->vdev_id, ret); + + ath11k_mac_11d_scan_stop_all(ar->ab); } static void ath11k_bss_disassoc(struct ieee80211_hw *hw, @@ -3409,6 +3411,7 @@ static int ath11k_start_scan(struct ath11k *ar, struct scan_req_params *arg) { int ret; + unsigned long timeout = 1 * HZ; lockdep_assert_held(&ar->conf_mutex); @@ -3419,7 +3422,14 @@ static int ath11k_start_scan(struct ath11k *ar, if (ret) return ret; - ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ); + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) { + timeout = 5 * HZ; + + if (ar->supports_6ghz) + timeout += 5 * HZ; + } + + ret = wait_for_completion_timeout(&ar->scan.started, timeout); if (ret == 0) { ret = ath11k_scan_stop(ar); if (ret) @@ -3476,6 +3486,26 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, if (ret) goto exit; + /* Currently the pending_11d=true only happened 1 time while + * wlan interface up in ath11k_mac_11d_scan_start(), it is called by + * ath11k_mac_op_add_interface(), after wlan interface up, + * pending_11d=false always. + * If remove below wait, it always happened scan fail and lead connect + * fail while wlan interface up, because it has a 11d scan which is running + * in firmware, and lead this scan failed. + */ + if (ar->pending_11d) { + long time_left; + unsigned long timeout = 5 * HZ; + + if (ar->supports_6ghz) + timeout += 5 * HZ; + + time_left = wait_for_completion_timeout(&ar->finish_11d_ch_list, timeout); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac wait 11d channel list time left %ld\n", time_left); + } + memset(&arg, 0, sizeof(arg)); ath11k_wmi_start_scan_init(ar, &arg); arg.vdev_id = arvif->vdev_id; @@ -5620,6 +5650,7 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ar->ab->update_11d_work); spin_lock_bh(&ar->data_lock); list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { @@ -5773,6 +5804,122 @@ static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw, } } +static bool ath11k_mac_vif_ap_active_any(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_pdev *pdev; + struct ath11k_vif *arvif; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP) + return true; + } + } + return false; +} + +void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait) +{ + struct wmi_11d_scan_start_params param; + int ret; + + mutex_lock(&ar->ab->vdev_id_11d_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev id for 11d scan %d\n", + ar->vdev_id_11d_scan); + + if (ar->regdom_set_by_user) + goto fin; + + if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) + goto fin; + + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) + goto fin; + + if (ath11k_mac_vif_ap_active_any(ar->ab)) + goto fin; + + param.vdev_id = vdev_id; + param.start_interval_msec = 0; + param.scan_period_msec = ATH11K_SCAN_11D_INTERVAL; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac start 11d scan\n"); + + if (wait) + reinit_completion(&ar->finish_11d_scan); + + ret = ath11k_wmi_send_11d_scan_start_cmd(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n", + vdev_id, ret); + } else { + ar->vdev_id_11d_scan = vdev_id; + if (wait) { + ar->pending_11d = true; + ret = wait_for_completion_timeout(&ar->finish_11d_scan, + 5 * HZ); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac 11d scan left time %d\n", ret); + + if (!ret) + ar->pending_11d = false; + } + } + +fin: + mutex_unlock(&ar->ab->vdev_id_11d_lock); +} + +void ath11k_mac_11d_scan_stop(struct ath11k *ar) +{ + int ret; + u32 vdev_id; + + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) + return; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d scan\n"); + + mutex_lock(&ar->ab->vdev_id_11d_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d vdev id %d\n", + ar->vdev_id_11d_scan); + + if (ar->vdev_id_11d_scan != ATH11K_11D_INVALID_VDEV_ID) { + vdev_id = ar->vdev_id_11d_scan; + + ret = ath11k_wmi_send_11d_scan_stop_cmd(ar, vdev_id); + if (ret) + ath11k_warn(ar->ab, + "failed to stopt 11d scan vdev %d ret: %d\n", + vdev_id, ret); + else + ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; + } + mutex_unlock(&ar->ab->vdev_id_11d_lock); +} + +void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_pdev *pdev; + int i; + + ath11k_dbg(ab, ATH11K_DBG_MAC, "mac stop soc 11d scan\n"); + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + ath11k_mac_11d_scan_stop(ar); + } +} + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -5906,6 +6053,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto err_peer_del; } + + ath11k_mac_11d_scan_stop_all(ar->ab); break; case WMI_VDEV_TYPE_STA: param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY; @@ -5945,6 +6094,9 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto err_peer_del; } + + ath11k_mac_11d_scan_start(ar, arvif->vdev_id, true); + break; case WMI_VDEV_TYPE_MONITOR: set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); @@ -6046,6 +6198,9 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", arvif->vdev_id); + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + ath11k_mac_11d_scan_stop(ar); + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr); if (ret) @@ -6764,6 +6919,9 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, ret); } + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + ath11k_mac_11d_scan_start(ar, arvif->vdev_id, false); + mutex_unlock(&ar->conf_mutex); } @@ -8165,6 +8323,9 @@ int ath11k_mac_allocate(struct ath11k_base *ab) ar->monitor_vdev_id = -1; clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); + ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID; + init_completion(&ar->finish_11d_scan); + init_completion(&ar->finish_11d_ch_list); } return 0; diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 359e5e9ca904..035d6738c20b 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -127,6 +127,13 @@ struct ath11k_generic_iter { extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default; +#define ATH11K_SCAN_11D_INTERVAL 600000 +#define ATH11K_11D_INVALID_VDEV_ID 0xFFFF + +void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id, bool wait); +void ath11k_mac_11d_scan_stop(struct ath11k *ar); +void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab); + void ath11k_mac_destroy(struct ath11k_base *ab); void ath11k_mac_unregister(struct ath11k_base *ab); int ath11k_mac_register(struct ath11k_base *ab); diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 8606170ba80d..1f8a81987187 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -86,6 +86,9 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) if (ret) ath11k_warn(ar->ab, "INIT Country code set to fw failed : %d\n", ret); + + ath11k_mac_11d_scan_stop(ar); + ar->regdom_set_by_user = true; } int ath11k_reg_update_chan_list(struct ath11k *ar) @@ -179,6 +182,11 @@ int ath11k_reg_update_chan_list(struct ath11k *ar) ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params); kfree(params); + if (ar->pending_11d) { + complete(&ar->finish_11d_ch_list); + ar->pending_11d = false; + } + return ret; } @@ -244,8 +252,15 @@ int ath11k_regd_update(struct ath11k *ar) goto err; } + if (ar->pending_11d) + complete(&ar->finish_11d_scan); + rtnl_lock(); wiphy_lock(ar->hw->wiphy); + + if (ar->pending_11d) + reinit_completion(&ar->finish_11d_ch_list); + ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); wiphy_unlock(ar->hw->wiphy); rtnl_unlock(); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 47361256bfeb..db90af054f05 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -130,6 +130,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, [WMI_TAG_OBSS_COLOR_COLLISION_EVT] = { .min_len = sizeof(struct wmi_obss_color_collision_event) }, + [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { + .min_len = sizeof(struct wmi_11d_new_cc_ev) }, }; #define PRIMAP(_hw_mode_) \ @@ -2898,6 +2900,75 @@ ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, + struct wmi_11d_scan_start_params *param) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_11d_scan_start_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_11d_scan_start_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_START_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = param->vdev_id; + cmd->scan_period_msec = param->scan_period_msec; + cmd->start_interval_msec = param->start_interval_msec; + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "send 11d scan start vdev id %d period %d ms internal %d ms\n", + cmd->vdev_id, + cmd->scan_period_msec, + cmd->start_interval_msec); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + +int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_11d_scan_stop_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_11d_scan_stop_cmd *)skb->data; + cmd->tlv_header = + FIELD_PREP(WMI_TLV_TAG, WMI_TAG_11D_SCAN_STOP_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = vdev_id; + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "send 11d scan stop vdev id %d\n", + cmd->vdev_id); + + if (ret) { + ath11k_warn(ar->ab, + "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter) { struct ath11k_pdev_wmi *wmi = ar->wmi; @@ -5938,6 +6009,41 @@ static void ath11k_wmi_op_ep_tx_credits(struct ath11k_base *ab) wake_up(&ab->wmi_ab.tx_credits_wq); } +static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *skb) +{ + const struct wmi_11d_new_cc_ev *ev; + const void **tb; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT]; + if (!ev) { + kfree(tb); + ath11k_warn(ab, "failed to fetch 11d new cc ev"); + return -EPROTO; + } + + spin_lock_bh(&ab->base_lock); + memcpy(&ab->new_alpha2, &ev->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi 11d new cc %c%c\n", + ab->new_alpha2[0], + ab->new_alpha2[1]); + + kfree(tb); + + queue_work(ab->workqueue, &ab->update_11d_work); + + return 0; +} + static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, struct sk_buff *skb) { @@ -7333,6 +7439,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_WOW_WAKEUP_HOST_EVENTID: ath11k_wmi_event_wow_wakeup_host(ab, skb); break; + case WMI_11D_NEW_COUNTRY_EVENTID: + ath11k_reg_11d_new_cc_event(ab, skb); + break; /* TODO: Add remaining events */ default: ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 49db414d0bf3..735f5a560b18 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3813,6 +3813,28 @@ struct wmi_init_country_cmd { } cc_info; } __packed; +struct wmi_11d_scan_start_params { + u32 vdev_id; + u32 scan_period_msec; + u32 start_interval_msec; +}; + +struct wmi_11d_scan_start_cmd { + u32 tlv_header; + u32 vdev_id; + u32 scan_period_msec; + u32 start_interval_msec; +} __packed; + +struct wmi_11d_scan_stop_cmd { + u32 tlv_header; + u32 vdev_id; +} __packed; + +struct wmi_11d_new_cc_ev { + u32 new_alpha2; +} __packed; + #define THERMAL_LEVELS 1 struct tt_level_config { u32 tmplwm; @@ -5448,6 +5470,11 @@ int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, int ath11k_wmi_send_init_country_cmd(struct ath11k *ar, struct wmi_init_country_params init_cc_param); + +int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, + struct wmi_11d_scan_start_params *param); +int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id); + int ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, struct thermal_mitigation_params *param); -- 2.31.1 -- ath11k mailing list ath11k@lists.infradead.org http://lists.infradead.org/mailman/listinfo/ath11k ^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2022-01-06 7:18 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-12-01 7:17 [PATCH v3 0/3] ath11k: add 11d scan offload support for QCA6390/WCN6855 Wen Gong 2021-12-01 7:17 ` Wen Gong 2021-12-01 7:17 ` [PATCH v3 1/3] ath11k: avoid deadlock by change ieee80211_queue_work for regd_update_work Wen Gong 2021-12-01 7:17 ` Wen Gong 2021-12-08 8:33 ` Kalle Valo 2021-12-08 8:33 ` Kalle Valo 2021-12-01 7:17 ` [PATCH v3 2/3] ath11k: add configure country code for QCA6390 and WCN6855 Wen Gong 2021-12-01 7:17 ` Wen Gong 2022-01-06 7:18 ` Dan Carpenter 2022-01-06 7:18 ` Dan Carpenter 2021-12-01 7:17 ` [PATCH v3 3/3] ath11k: add 11d scan offload support Wen Gong 2021-12-01 7:17 ` Wen Gong
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.