1 /*
2 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /**
19 * DOC: wlan_hdd_btc_chain_mode.c
20 *
21 * The implementation of bt coex chain mode configuration
22 *
23 */
24
25 #include "wlan_hdd_main.h"
26 #include "wlan_hdd_btc_chain_mode.h"
27 #include "osif_sync.h"
28 #include "wlan_coex_ucfg_api.h"
29 #include "wlan_hdd_object_manager.h"
30 #include "wlan_cfg80211_coex.h"
31
32 static QDF_STATUS
wlan_hdd_btc_chain_mode_handler(struct wlan_objmgr_vdev * vdev)33 wlan_hdd_btc_chain_mode_handler(struct wlan_objmgr_vdev *vdev)
34 {
35 QDF_STATUS status;
36 struct hdd_adapter *adapter;
37 mac_handle_t mac_handle;
38 uint8_t nss, band;
39 enum coex_btc_chain_mode mode;
40 uint8_t vdev_id;
41 uint32_t freq;
42 struct wlan_objmgr_psoc *psoc;
43 struct wlan_hdd_link_info *link_info;
44
45 if (!vdev) {
46 hdd_err("NULL vdev");
47 return QDF_STATUS_E_INVAL;
48 }
49
50 vdev_id = wlan_vdev_get_id(vdev);
51 if (wlan_hdd_validate_vdev_id(vdev_id))
52 return QDF_STATUS_E_INVAL;
53
54 psoc = wlan_vdev_get_psoc(vdev);
55 if (!psoc) {
56 hdd_err("NULL psoc");
57 return QDF_STATUS_E_INVAL;
58 }
59
60 link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id);
61 if (!link_info) {
62 hdd_err("Invalid vdev");
63 return QDF_STATUS_E_INVAL;
64 }
65
66 adapter = link_info->adapter;
67 status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &mode);
68 if (QDF_IS_STATUS_ERROR(status)) {
69 hdd_err("failed to get cur BTC chain mode, status %d", status);
70 return -EFAULT;
71 }
72
73 mac_handle = adapter->hdd_ctx->mac_handle;
74 if (!mac_handle) {
75 hdd_err("NULL MAC handle");
76 return -EINVAL;
77 }
78
79 nss = ((mode == WLAN_COEX_BTC_CHAIN_MODE_FDD ||
80 mode == WLAN_COEX_BTC_CHAIN_MODE_HYBRID) ? 1 : 2);
81
82 hdd_debug("update nss to %d for vdev %d, device mode %d",
83 nss, link_info->vdev_id, adapter->device_mode);
84 band = NSS_CHAINS_BAND_2GHZ;
85 sme_update_nss_in_mlme_cfg(mac_handle, nss, nss,
86 adapter->device_mode, band);
87 sme_update_vdev_type_nss(mac_handle, nss, band);
88
89 status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_OSIF_ID);
90 if (QDF_IS_STATUS_SUCCESS(status)) {
91 hdd_store_nss_chains_cfg_in_vdev(adapter->hdd_ctx, vdev);
92 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
93 }
94
95 sme_update_he_cap_nss(mac_handle, link_info->vdev_id, nss);
96 freq = hdd_get_link_info_home_channel(link_info);
97
98 /*
99 * BT coex chain mode is for COEX between BT and WiFi-2.4G.
100 * Nss and related parameters have been updated upon for
101 * NSS_CHAINS_BAND_2GHZ.
102 * If the current home channel is NOT 2.4G, these parameters
103 * will take effect when switching to 2.4G, so no need to do
104 * restart here.
105 */
106 if (!WLAN_REG_IS_24GHZ_CH_FREQ(freq))
107 return QDF_STATUS_SUCCESS;
108
109 switch (adapter->device_mode) {
110 case QDF_STA_MODE:
111 case QDF_P2P_CLIENT_MODE:
112 wlan_hdd_cm_issue_disconnect(link_info,
113 REASON_PREV_AUTH_NOT_VALID, false);
114 break;
115 case QDF_SAP_MODE:
116 case QDF_P2P_GO_MODE:
117 hdd_restart_sap(link_info);
118 break;
119 default:
120 break;
121 }
122
123 return QDF_STATUS_SUCCESS;
124 }
125
wlan_hdd_register_btc_chain_mode_handler(struct wlan_objmgr_psoc * psoc)126 void wlan_hdd_register_btc_chain_mode_handler(struct wlan_objmgr_psoc *psoc)
127 {
128 ucfg_coex_register_cfg_updated_handler(psoc,
129 COEX_CONFIG_BTC_CHAIN_MODE,
130 wlan_hdd_btc_chain_mode_handler
131 );
132 }
133
134 /**
135 * __wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode
136 * @wiphy: pointer to wireless wiphy structure.
137 * @wdev: pointer to wireless_dev structure.
138 * @data: pointer to btc chain mode command parameters.
139 * @data_len: the length in byte of btc chain mode command parameters.
140 *
141 * Return: An error code or 0 on success.
142 */
__wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)143 static int __wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy *wiphy,
144 struct wireless_dev *wdev,
145 const void *data,
146 int data_len)
147 {
148 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev);
149 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
150 int errno;
151 struct wlan_objmgr_vdev *vdev;
152
153 hdd_enter_dev(wdev->netdev);
154
155 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
156 hdd_err("Command not allowed in FTM mode");
157 return -EPERM;
158 }
159
160 errno = wlan_hdd_validate_context(hdd_ctx);
161 if (errno != 0)
162 return errno;
163
164 if (hdd_ctx->num_rf_chains < 2) {
165 hdd_debug("Num of chains [%u] is less than 2, setting BTC separate chain mode is not allowed",
166 hdd_ctx->num_rf_chains);
167 return -EINVAL;
168 }
169
170 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID);
171 if (!vdev)
172 return -EINVAL;
173
174 errno = wlan_cfg80211_coex_set_btc_chain_mode(vdev, data, data_len);
175 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
176
177 return errno;
178 }
179
180 /**
181 * wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode
182 * @wiphy: pointer to wireless wiphy structure.
183 * @wdev: pointer to wireless_dev structure.
184 * @data: pointer to btc chain mode command parameters.
185 * @data_len: the length in byte of btc chain mode command parameters.
186 *
187 * Return: An error code or 0 on success.
188 */
wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)189 int wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy *wiphy,
190 struct wireless_dev *wdev,
191 const void *data, int data_len)
192 {
193 int errno;
194 struct osif_vdev_sync *vdev_sync;
195
196 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
197 if (errno)
198 return errno;
199
200 errno = __wlan_hdd_cfg80211_set_btc_chain_mode(wiphy, wdev,
201 data, data_len);
202
203 osif_vdev_sync_op_stop(vdev_sync);
204
205 return errno;
206 }
207