aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorGovind Singh <govinds@codeaurora.org>2018-10-11 06:16:26 -0400
committerKalle Valo <kvalo@codeaurora.org>2018-10-13 13:31:56 -0400
commitba94c753ccb471bafe8bd824b744fda6fee0001e (patch)
tree24e367261a88b12ace4a0557765d4806eb62c794 /drivers/net/wireless
parent35a6657667375d1564f9e9b75491c9e41b04c51f (diff)
ath10k: add QMI message handshake for wcn3990 client
Add WCN3990 QMI client handshakes for Q6 integrated WLAN connectivity subsystem. This layer is responsible for communicating qmi control messages to wifi fw QMI service using QMI messaging protocol. Qualcomm MSM Interface(QMI) is a messaging format used to communicate between components running between remote processors with underlying transport layer based on integrated chipset(shared memory) or discrete chipset(PCI/USB/SDIO/UART). Signed-off-by: Govind Singh <govinds@codeaurora.org> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org> Acked-by: Niklas Cassel <niklas.cassel@linaro.org> Reviewed-by: Brian Norris <briannorris@chromium.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig1
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile4
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c1019
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.h129
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c267
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.h4
8 files changed, 1419 insertions, 13 deletions
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index 6572a43590a8..e1ad6b9166a6 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -44,6 +44,7 @@ config ATH10K_SNOC
44 tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)" 44 tristate "Qualcomm ath10k SNOC support (EXPERIMENTAL)"
45 depends on ATH10K 45 depends on ATH10K
46 depends on ARCH_QCOM || COMPILE_TEST 46 depends on ARCH_QCOM || COMPILE_TEST
47 select QCOM_QMI_HELPERS
47 ---help--- 48 ---help---
48 This module adds support for integrated WCN3990 chip connected 49 This module adds support for integrated WCN3990 chip connected
49 to system NOC(SNOC). Currently work in progress and will not 50 to system NOC(SNOC). Currently work in progress and will not
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 44d60a61b242..66326b949ab1 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -36,7 +36,9 @@ obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o
36ath10k_usb-y += usb.o 36ath10k_usb-y += usb.o
37 37
38obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o 38obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o
39ath10k_snoc-y += snoc.o 39ath10k_snoc-y += qmi.o \
40 qmi_wlfw_v01.o \
41 snoc.o
40 42
41# for tracing framework to find trace.h 43# for tracing framework to find trace.h
42CFLAGS_trace.o := -I$(src) 44CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 393314538772..da607febfd82 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -989,7 +989,7 @@ static int ath10k_download_fw(struct ath10k *ar)
989 data, data_len); 989 data, data_len);
990} 990}
991 991
992static void ath10k_core_free_board_files(struct ath10k *ar) 992void ath10k_core_free_board_files(struct ath10k *ar)
993{ 993{
994 if (!IS_ERR(ar->normal_mode_fw.board)) 994 if (!IS_ERR(ar->normal_mode_fw.board))
995 release_firmware(ar->normal_mode_fw.board); 995 release_firmware(ar->normal_mode_fw.board);
@@ -1004,6 +1004,7 @@ static void ath10k_core_free_board_files(struct ath10k *ar)
1004 ar->normal_mode_fw.ext_board_data = NULL; 1004 ar->normal_mode_fw.ext_board_data = NULL;
1005 ar->normal_mode_fw.ext_board_len = 0; 1005 ar->normal_mode_fw.ext_board_len = 0;
1006} 1006}
1007EXPORT_SYMBOL(ath10k_core_free_board_files);
1007 1008
1008static void ath10k_core_free_firmware_files(struct ath10k *ar) 1009static void ath10k_core_free_firmware_files(struct ath10k *ar)
1009{ 1010{
@@ -1367,7 +1368,7 @@ static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name,
1367 return -1; 1368 return -1;
1368} 1369}
1369 1370
1370static int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) 1371int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)
1371{ 1372{
1372 char boardname[100], fallback_boardname[100]; 1373 char boardname[100], fallback_boardname[100];
1373 int ret; 1374 int ret;
@@ -1415,6 +1416,7 @@ success:
1415 ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api); 1416 ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api);
1416 return 0; 1417 return 0;
1417} 1418}
1419EXPORT_SYMBOL(ath10k_core_fetch_board_file);
1418 1420
1419static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar) 1421static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar)
1420{ 1422{
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index ecedd49c8a98..042418097cf9 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1218,5 +1218,7 @@ void ath10k_core_stop(struct ath10k *ar);
1218int ath10k_core_register(struct ath10k *ar, 1218int ath10k_core_register(struct ath10k *ar,
1219 const struct ath10k_bus_params *bus_params); 1219 const struct ath10k_bus_params *bus_params);
1220void ath10k_core_unregister(struct ath10k *ar); 1220void ath10k_core_unregister(struct ath10k *ar);
1221int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type);
1222void ath10k_core_free_board_files(struct ath10k *ar);
1221 1223
1222#endif /* _CORE_H_ */ 1224#endif /* _CORE_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
new file mode 100644
index 000000000000..56cb1831dcdf
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -0,0 +1,1019 @@
1/*
2 * Copyright (c) 2018 The Linux Foundation. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/completion.h>
18#include <linux/device.h>
19#include <linux/debugfs.h>
20#include <linux/idr.h>
21#include <linux/kernel.h>
22#include <linux/of.h>
23#include <linux/of_address.h>
24#include <linux/module.h>
25#include <linux/net.h>
26#include <linux/platform_device.h>
27#include <linux/qcom_scm.h>
28#include <linux/string.h>
29#include <net/sock.h>
30
31#include "debug.h"
32#include "snoc.h"
33
34#define ATH10K_QMI_CLIENT_ID 0x4b4e454c
35#define ATH10K_QMI_TIMEOUT 30
36
37static int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi,
38 struct ath10k_msa_mem_info *mem_info)
39{
40 struct qcom_scm_vmperm dst_perms[3];
41 struct ath10k *ar = qmi->ar;
42 unsigned int src_perms;
43 u32 perm_count;
44 int ret;
45
46 src_perms = BIT(QCOM_SCM_VMID_HLOS);
47
48 dst_perms[0].vmid = QCOM_SCM_VMID_MSS_MSA;
49 dst_perms[0].perm = QCOM_SCM_PERM_RW;
50 dst_perms[1].vmid = QCOM_SCM_VMID_WLAN;
51 dst_perms[1].perm = QCOM_SCM_PERM_RW;
52
53 if (mem_info->secure) {
54 perm_count = 2;
55 } else {
56 dst_perms[2].vmid = QCOM_SCM_VMID_WLAN_CE;
57 dst_perms[2].perm = QCOM_SCM_PERM_RW;
58 perm_count = 3;
59 }
60
61 ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size,
62 &src_perms, dst_perms, perm_count);
63 if (ret < 0)
64 ath10k_err(ar, "failed to assign msa map permissions: %d\n", ret);
65
66 return ret;
67}
68
69static int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi,
70 struct ath10k_msa_mem_info *mem_info)
71{
72 struct qcom_scm_vmperm dst_perms;
73 struct ath10k *ar = qmi->ar;
74 unsigned int src_perms;
75 int ret;
76
77 src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN);
78
79 if (!mem_info->secure)
80 src_perms |= BIT(QCOM_SCM_VMID_WLAN_CE);
81
82 dst_perms.vmid = QCOM_SCM_VMID_HLOS;
83 dst_perms.perm = QCOM_SCM_PERM_RW;
84
85 ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size,
86 &src_perms, &dst_perms, 1);
87 if (ret < 0)
88 ath10k_err(ar, "failed to unmap msa permissions: %d\n", ret);
89
90 return ret;
91}
92
93static int ath10k_qmi_setup_msa_permissions(struct ath10k_qmi *qmi)
94{
95 int ret;
96 int i;
97
98 for (i = 0; i < qmi->nr_mem_region; i++) {
99 ret = ath10k_qmi_map_msa_permission(qmi, &qmi->mem_region[i]);
100 if (ret)
101 goto err_unmap;
102 }
103
104 return 0;
105
106err_unmap:
107 for (i--; i >= 0; i--)
108 ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]);
109 return ret;
110}
111
112static void ath10k_qmi_remove_msa_permission(struct ath10k_qmi *qmi)
113{
114 int i;
115
116 for (i = 0; i < qmi->nr_mem_region; i++)
117 ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]);
118}
119
120static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
121{
122 struct wlfw_msa_info_resp_msg_v01 resp = {};
123 struct wlfw_msa_info_req_msg_v01 req = {};
124 struct ath10k *ar = qmi->ar;
125 struct qmi_txn txn;
126 int ret;
127 int i;
128
129 req.msa_addr = qmi->msa_pa;
130 req.size = qmi->msa_mem_size;
131
132 ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
133 wlfw_msa_info_resp_msg_v01_ei, &resp);
134 if (ret < 0)
135 goto out;
136
137 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
138 QMI_WLFW_MSA_INFO_REQ_V01,
139 WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN,
140 wlfw_msa_info_req_msg_v01_ei, &req);
141 if (ret < 0) {
142 qmi_txn_cancel(&txn);
143 ath10k_err(ar, "failed to send msa mem info req: %d\n", ret);
144 goto out;
145 }
146
147 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
148 if (ret < 0)
149 goto out;
150
151 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
152 ath10k_err(ar, "msa info req rejected: %d\n", resp.resp.error);
153 ret = -EINVAL;
154 goto out;
155 }
156
157 if (resp.mem_region_info_len > QMI_WLFW_MAX_MEM_REG_V01) {
158 ath10k_err(ar, "invalid memory region length received: %d\n",
159 resp.mem_region_info_len);
160 ret = -EINVAL;
161 goto out;
162 }
163
164 qmi->nr_mem_region = resp.mem_region_info_len;
165 for (i = 0; i < resp.mem_region_info_len; i++) {
166 qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr;
167 qmi->mem_region[i].size = resp.mem_region_info[i].size;
168 qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag;
169 ath10k_dbg(ar, ATH10K_DBG_QMI,
170 "qmi msa mem region %d addr 0x%pa size 0x%x flag 0x%08x\n",
171 i, &qmi->mem_region[i].addr,
172 qmi->mem_region[i].size,
173 qmi->mem_region[i].secure);
174 }
175
176 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n");
177 return 0;
178
179out:
180 return ret;
181}
182
183static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi)
184{
185 struct wlfw_msa_ready_resp_msg_v01 resp = {};
186 struct wlfw_msa_ready_req_msg_v01 req = {};
187 struct ath10k *ar = qmi->ar;
188 struct qmi_txn txn;
189 int ret;
190
191 ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
192 wlfw_msa_ready_resp_msg_v01_ei, &resp);
193 if (ret < 0)
194 goto out;
195
196 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
197 QMI_WLFW_MSA_READY_REQ_V01,
198 WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN,
199 wlfw_msa_ready_req_msg_v01_ei, &req);
200 if (ret < 0) {
201 qmi_txn_cancel(&txn);
202 ath10k_err(ar, "failed to send msa mem ready request: %d\n", ret);
203 goto out;
204 }
205
206 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
207 if (ret < 0)
208 goto out;
209
210 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
211 ath10k_err(ar, "msa ready request rejected: %d\n", resp.resp.error);
212 ret = -EINVAL;
213 }
214
215 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem ready request completed\n");
216 return 0;
217
218out:
219 return ret;
220}
221
222static int ath10k_qmi_bdf_dnld_send_sync(struct ath10k_qmi *qmi)
223{
224 struct wlfw_bdf_download_resp_msg_v01 resp = {};
225 struct wlfw_bdf_download_req_msg_v01 *req;
226 struct ath10k *ar = qmi->ar;
227 unsigned int remaining;
228 struct qmi_txn txn;
229 const u8 *temp;
230 int ret;
231
232 req = kzalloc(sizeof(*req), GFP_KERNEL);
233 if (!req)
234 return -ENOMEM;
235
236 temp = ar->normal_mode_fw.board_data;
237 remaining = ar->normal_mode_fw.board_len;
238
239 while (remaining) {
240 req->valid = 1;
241 req->file_id_valid = 1;
242 req->file_id = 0;
243 req->total_size_valid = 1;
244 req->total_size = ar->normal_mode_fw.board_len;
245 req->seg_id_valid = 1;
246 req->data_valid = 1;
247 req->end_valid = 1;
248
249 if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
250 req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
251 } else {
252 req->data_len = remaining;
253 req->end = 1;
254 }
255
256 memcpy(req->data, temp, req->data_len);
257
258 ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
259 wlfw_bdf_download_resp_msg_v01_ei,
260 &resp);
261 if (ret < 0)
262 goto out;
263
264 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
265 QMI_WLFW_BDF_DOWNLOAD_REQ_V01,
266 WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
267 wlfw_bdf_download_req_msg_v01_ei, req);
268 if (ret < 0) {
269 qmi_txn_cancel(&txn);
270 goto out;
271 }
272
273 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
274
275 if (ret < 0)
276 goto out;
277
278 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
279 ath10k_err(ar, "failed to download board data file: %d\n",
280 resp.resp.error);
281 ret = -EINVAL;
282 goto out;
283 }
284
285 remaining -= req->data_len;
286 temp += req->data_len;
287 req->seg_id++;
288 }
289
290 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi bdf download request completed\n");
291
292 kfree(req);
293 return 0;
294
295out:
296 kfree(req);
297 return ret;
298}
299
300static int ath10k_qmi_send_cal_report_req(struct ath10k_qmi *qmi)
301{
302 struct wlfw_cal_report_resp_msg_v01 resp = {};
303 struct wlfw_cal_report_req_msg_v01 req = {};
304 struct ath10k *ar = qmi->ar;
305 struct qmi_txn txn;
306 int i, j = 0;
307 int ret;
308
309 ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei,
310 &resp);
311 if (ret < 0)
312 goto out;
313
314 for (i = 0; i < QMI_WLFW_MAX_NUM_CAL_V01; i++) {
315 if (qmi->cal_data[i].total_size &&
316 qmi->cal_data[i].data) {
317 req.meta_data[j] = qmi->cal_data[i].cal_id;
318 j++;
319 }
320 }
321 req.meta_data_len = j;
322
323 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
324 QMI_WLFW_CAL_REPORT_REQ_V01,
325 WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN,
326 wlfw_cal_report_req_msg_v01_ei, &req);
327 if (ret < 0) {
328 qmi_txn_cancel(&txn);
329 ath10k_err(ar, "failed to send calibration request: %d\n", ret);
330 goto out;
331 }
332
333 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
334 if (ret < 0)
335 goto out;
336
337 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
338 ath10k_err(ar, "calibration request rejected: %d\n", resp.resp.error);
339 ret = -EINVAL;
340 goto out;
341 }
342
343 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi cal report request completed\n");
344 return 0;
345
346out:
347 return ret;
348}
349
350static int
351ath10k_qmi_mode_send_sync_msg(struct ath10k *ar, enum wlfw_driver_mode_enum_v01 mode)
352{
353 struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
354 struct ath10k_qmi *qmi = ar_snoc->qmi;
355 struct wlfw_wlan_mode_resp_msg_v01 resp = {};
356 struct wlfw_wlan_mode_req_msg_v01 req = {};
357 struct qmi_txn txn;
358 int ret;
359
360 ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
361 wlfw_wlan_mode_resp_msg_v01_ei,
362 &resp);
363 if (ret < 0)
364 goto out;
365
366 req.mode = mode;
367 req.hw_debug_valid = 1;
368 req.hw_debug = 0;
369
370 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
371 QMI_WLFW_WLAN_MODE_REQ_V01,
372 WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN,
373 wlfw_wlan_mode_req_msg_v01_ei, &req);
374 if (ret < 0) {
375 qmi_txn_cancel(&txn);
376 ath10k_err(ar, "failed to send wlan mode %d request: %d\n", mode, ret);
377 goto out;
378 }
379
380 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
381 if (ret < 0)
382 goto out;
383
384 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
385 ath10k_err(ar, "more request rejected: %d\n", resp.resp.error);
386 ret = -EINVAL;
387 goto out;
388 }
389
390 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wlan mode req completed: %d\n", mode);
391 return 0;
392
393out:
394 return ret;
395}
396
397static int
398ath10k_qmi_cfg_send_sync_msg(struct ath10k *ar,
399 struct ath10k_qmi_wlan_enable_cfg *config,
400 const char *version)
401{
402 struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
403 struct ath10k_qmi *qmi = ar_snoc->qmi;
404 struct wlfw_wlan_cfg_resp_msg_v01 resp = {};
405 struct wlfw_wlan_cfg_req_msg_v01 *req;
406 struct qmi_txn txn;
407 int ret;
408 u32 i;
409
410 req = kzalloc(sizeof(*req), GFP_KERNEL);
411 if (!req)
412 return -ENOMEM;
413
414 ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
415 wlfw_wlan_cfg_resp_msg_v01_ei,
416 &resp);
417 if (ret < 0)
418 goto out;
419
420 req->host_version_valid = 0;
421
422 req->tgt_cfg_valid = 1;
423 if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01)
424 req->tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
425 else
426 req->tgt_cfg_len = config->num_ce_tgt_cfg;
427 for (i = 0; i < req->tgt_cfg_len; i++) {
428 req->tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
429 req->tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
430 req->tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
431 req->tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
432 req->tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
433 }
434
435 req->svc_cfg_valid = 1;
436 if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01)
437 req->svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01;
438 else
439 req->svc_cfg_len = config->num_ce_svc_pipe_cfg;
440 for (i = 0; i < req->svc_cfg_len; i++) {
441 req->svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
442 req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
443 req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
444 }
445
446 req->shadow_reg_valid = 1;
447 if (config->num_shadow_reg_cfg >
448 QMI_WLFW_MAX_NUM_SHADOW_REG_V01)
449 req->shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01;
450 else
451 req->shadow_reg_len = config->num_shadow_reg_cfg;
452
453 memcpy(req->shadow_reg, config->shadow_reg_cfg,
454 sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req->shadow_reg_len);
455
456 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
457 QMI_WLFW_WLAN_CFG_REQ_V01,
458 WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN,
459 wlfw_wlan_cfg_req_msg_v01_ei, req);
460 if (ret < 0) {
461 qmi_txn_cancel(&txn);
462 ath10k_err(ar, "failed to send config request: %d\n", ret);
463 goto out;
464 }
465
466 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
467 if (ret < 0)
468 goto out;
469
470 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
471 ath10k_err(ar, "config request rejected: %d\n", resp.resp.error);
472 ret = -EINVAL;
473 goto out;
474 }
475
476 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi config request completed\n");
477 kfree(req);
478 return 0;
479
480out:
481 kfree(req);
482 return ret;
483}
484
485int ath10k_qmi_wlan_enable(struct ath10k *ar,
486 struct ath10k_qmi_wlan_enable_cfg *config,
487 enum wlfw_driver_mode_enum_v01 mode,
488 const char *version)
489{
490 int ret;
491
492 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi mode %d config %p\n",
493 mode, config);
494
495 ret = ath10k_qmi_cfg_send_sync_msg(ar, config, version);
496 if (ret) {
497 ath10k_err(ar, "failed to send qmi config: %d\n", ret);
498 return ret;
499 }
500
501 ret = ath10k_qmi_mode_send_sync_msg(ar, mode);
502 if (ret) {
503 ath10k_err(ar, "failed to send qmi mode: %d\n", ret);
504 return ret;
505 }
506
507 return 0;
508}
509
510int ath10k_qmi_wlan_disable(struct ath10k *ar)
511{
512 return ath10k_qmi_mode_send_sync_msg(ar, QMI_WLFW_OFF_V01);
513}
514
515static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi)
516{
517 struct wlfw_cap_resp_msg_v01 *resp;
518 struct wlfw_cap_req_msg_v01 req = {};
519 struct ath10k *ar = qmi->ar;
520 struct qmi_txn txn;
521 int ret;
522
523 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
524 if (!resp)
525 return -ENOMEM;
526
527 ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cap_resp_msg_v01_ei, resp);
528 if (ret < 0)
529 goto out;
530
531 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
532 QMI_WLFW_CAP_REQ_V01,
533 WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN,
534 wlfw_cap_req_msg_v01_ei, &req);
535 if (ret < 0) {
536 qmi_txn_cancel(&txn);
537 ath10k_err(ar, "failed to send capability request: %d\n", ret);
538 goto out;
539 }
540
541 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
542 if (ret < 0)
543 goto out;
544
545 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
546 ath10k_err(ar, "capablity req rejected: %d\n", resp->resp.error);
547 ret = -EINVAL;
548 goto out;
549 }
550
551 if (resp->chip_info_valid) {
552 qmi->chip_info.chip_id = resp->chip_info.chip_id;
553 qmi->chip_info.chip_family = resp->chip_info.chip_family;
554 }
555
556 if (resp->board_info_valid)
557 qmi->board_info.board_id = resp->board_info.board_id;
558 else
559 qmi->board_info.board_id = 0xFF;
560
561 if (resp->soc_info_valid)
562 qmi->soc_info.soc_id = resp->soc_info.soc_id;
563
564 if (resp->fw_version_info_valid) {
565 qmi->fw_version = resp->fw_version_info.fw_version;
566 strlcpy(qmi->fw_build_timestamp, resp->fw_version_info.fw_build_timestamp,
567 sizeof(qmi->fw_build_timestamp));
568 }
569
570 if (resp->fw_build_id_valid)
571 strlcpy(qmi->fw_build_id, resp->fw_build_id,
572 MAX_BUILD_ID_LEN + 1);
573
574 ath10k_dbg(ar, ATH10K_DBG_QMI,
575 "qmi chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x",
576 qmi->chip_info.chip_id, qmi->chip_info.chip_family,
577 qmi->board_info.board_id, qmi->soc_info.soc_id);
578 ath10k_dbg(ar, ATH10K_DBG_QMI,
579 "qmi fw_version 0x%x fw_build_timestamp %s fw_build_id %s",
580 qmi->fw_version, qmi->fw_build_timestamp, qmi->fw_build_id);
581
582 kfree(resp);
583 return 0;
584
585out:
586 kfree(resp);
587 return ret;
588}
589
590static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi)
591{
592 struct wlfw_host_cap_resp_msg_v01 resp = {};
593 struct wlfw_host_cap_req_msg_v01 req = {};
594 struct ath10k *ar = qmi->ar;
595 struct qmi_txn txn;
596 int ret;
597
598 req.daemon_support_valid = 1;
599 req.daemon_support = 0;
600
601 ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
602 wlfw_host_cap_resp_msg_v01_ei, &resp);
603 if (ret < 0)
604 goto out;
605
606 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
607 QMI_WLFW_HOST_CAP_REQ_V01,
608 WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN,
609 wlfw_host_cap_req_msg_v01_ei, &req);
610 if (ret < 0) {
611 qmi_txn_cancel(&txn);
612 ath10k_err(ar, "failed to send host capability request: %d\n", ret);
613 goto out;
614 }
615
616 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
617 if (ret < 0)
618 goto out;
619
620 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
621 ath10k_err(ar, "host capability request rejected: %d\n", resp.resp.error);
622 ret = -EINVAL;
623 goto out;
624 }
625
626 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi host capablity request completed\n");
627 return 0;
628
629out:
630 return ret;
631}
632
633static int
634ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi)
635{
636 struct wlfw_ind_register_resp_msg_v01 resp = {};
637 struct wlfw_ind_register_req_msg_v01 req = {};
638 struct ath10k *ar = qmi->ar;
639 struct qmi_txn txn;
640 int ret;
641
642 req.client_id_valid = 1;
643 req.client_id = ATH10K_QMI_CLIENT_ID;
644 req.fw_ready_enable_valid = 1;
645 req.fw_ready_enable = 1;
646 req.msa_ready_enable_valid = 1;
647 req.msa_ready_enable = 1;
648
649 ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
650 wlfw_ind_register_resp_msg_v01_ei, &resp);
651 if (ret < 0)
652 goto out;
653
654 ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
655 QMI_WLFW_IND_REGISTER_REQ_V01,
656 WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN,
657 wlfw_ind_register_req_msg_v01_ei, &req);
658 if (ret < 0) {
659 qmi_txn_cancel(&txn);
660 ath10k_err(ar, "failed to send indication registed request: %d\n", ret);
661 goto out;
662 }
663
664 ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
665 if (ret < 0)
666 goto out;
667
668 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
669 ath10k_err(ar, "indication request rejected: %d\n", resp.resp.error);
670 ret = -EINVAL;
671 goto out;
672 }
673
674 if (resp.fw_status_valid) {
675 if (resp.fw_status & QMI_WLFW_FW_READY_V01)
676 qmi->fw_ready = true;
677 }
678 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi indication register request completed\n");
679 return 0;
680
681out:
682 return ret;
683}
684
685static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi)
686{
687 struct ath10k *ar = qmi->ar;
688 int ret;
689
690 ret = ath10k_qmi_ind_register_send_sync_msg(qmi);
691 if (ret)
692 return;
693
694 if (qmi->fw_ready) {
695 ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND);
696 return;
697 }
698
699 ret = ath10k_qmi_host_cap_send_sync(qmi);
700 if (ret)
701 return;
702
703 ret = ath10k_qmi_msa_mem_info_send_sync_msg(qmi);
704 if (ret)
705 return;
706
707 ret = ath10k_qmi_setup_msa_permissions(qmi);
708 if (ret)
709 return;
710
711 ret = ath10k_qmi_msa_ready_send_sync_msg(qmi);
712 if (ret)
713 goto err_setup_msa;
714
715 ret = ath10k_qmi_cap_send_sync_msg(qmi);
716 if (ret)
717 goto err_setup_msa;
718
719 return;
720
721err_setup_msa:
722 ath10k_qmi_remove_msa_permission(qmi);
723}
724
725static int ath10k_qmi_fetch_board_file(struct ath10k_qmi *qmi)
726{
727 struct ath10k *ar = qmi->ar;
728
729 ar->hif.bus = ATH10K_BUS_SNOC;
730 ar->id.qmi_ids_valid = true;
731 ar->id.qmi_board_id = qmi->board_info.board_id;
732 ar->hw_params.fw.dir = WCN3990_HW_1_0_FW_DIR;
733
734 return ath10k_core_fetch_board_file(qmi->ar, ATH10K_BD_IE_BOARD);
735}
736
737static int
738ath10k_qmi_driver_event_post(struct ath10k_qmi *qmi,
739 enum ath10k_qmi_driver_event_type type,
740 void *data)
741{
742 struct ath10k_qmi_driver_event *event;
743
744 event = kzalloc(sizeof(*event), GFP_ATOMIC);
745 if (!event)
746 return -ENOMEM;
747
748 event->type = type;
749 event->data = data;
750
751 spin_lock(&qmi->event_lock);
752 list_add_tail(&event->list, &qmi->event_list);
753 spin_unlock(&qmi->event_lock);
754
755 queue_work(qmi->event_wq, &qmi->event_work);
756
757 return 0;
758}
759
760static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi)
761{
762 struct ath10k *ar = qmi->ar;
763
764 ath10k_qmi_remove_msa_permission(qmi);
765 ath10k_core_free_board_files(ar);
766 ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND);
767 ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n");
768}
769
770static void ath10k_qmi_event_msa_ready(struct ath10k_qmi *qmi)
771{
772 int ret;
773
774 ret = ath10k_qmi_fetch_board_file(qmi);
775 if (ret)
776 goto out;
777
778 ret = ath10k_qmi_bdf_dnld_send_sync(qmi);
779 if (ret)
780 goto out;
781
782 ret = ath10k_qmi_send_cal_report_req(qmi);
783
784out:
785 return;
786}
787
788static int ath10k_qmi_event_fw_ready_ind(struct ath10k_qmi *qmi)
789{
790 struct ath10k *ar = qmi->ar;
791
792 ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw ready event received\n");
793 ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND);
794
795 return 0;
796}
797
798static void ath10k_qmi_fw_ready_ind(struct qmi_handle *qmi_hdl,
799 struct sockaddr_qrtr *sq,
800 struct qmi_txn *txn, const void *data)
801{
802 struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
803
804 ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_FW_READY_IND, NULL);
805}
806
807static void ath10k_qmi_msa_ready_ind(struct qmi_handle *qmi_hdl,
808 struct sockaddr_qrtr *sq,
809 struct qmi_txn *txn, const void *data)
810{
811 struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
812
813 ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_MSA_READY_IND, NULL);
814}
815
816static struct qmi_msg_handler qmi_msg_handler[] = {
817 {
818 .type = QMI_INDICATION,
819 .msg_id = QMI_WLFW_FW_READY_IND_V01,
820 .ei = wlfw_fw_ready_ind_msg_v01_ei,
821 .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01),
822 .fn = ath10k_qmi_fw_ready_ind,
823 },
824 {
825 .type = QMI_INDICATION,
826 .msg_id = QMI_WLFW_MSA_READY_IND_V01,
827 .ei = wlfw_msa_ready_ind_msg_v01_ei,
828 .decoded_size = sizeof(struct wlfw_msa_ready_ind_msg_v01),
829 .fn = ath10k_qmi_msa_ready_ind,
830 },
831 {}
832};
833
834static int ath10k_qmi_new_server(struct qmi_handle *qmi_hdl,
835 struct qmi_service *service)
836{
837 struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
838 struct sockaddr_qrtr *sq = &qmi->sq;
839 struct ath10k *ar = qmi->ar;
840 int ret;
841
842 sq->sq_family = AF_QIPCRTR;
843 sq->sq_node = service->node;
844 sq->sq_port = service->port;
845
846 ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service found\n");
847
848 ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)&qmi->sq,
849 sizeof(qmi->sq), 0);
850 if (ret) {
851 ath10k_err(ar, "failed to connect to a remote QMI service port\n");
852 return ret;
853 }
854
855 ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wifi fw qmi service connected\n");
856 ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_ARRIVE, NULL);
857
858 return ret;
859}
860
861static void ath10k_qmi_del_server(struct qmi_handle *qmi_hdl,
862 struct qmi_service *service)
863{
864 struct ath10k_qmi *qmi =
865 container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
866
867 qmi->fw_ready = false;
868 ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_EXIT, NULL);
869}
870
871static struct qmi_ops ath10k_qmi_ops = {
872 .new_server = ath10k_qmi_new_server,
873 .del_server = ath10k_qmi_del_server,
874};
875
876static void ath10k_qmi_driver_event_work(struct work_struct *work)
877{
878 struct ath10k_qmi *qmi = container_of(work, struct ath10k_qmi,
879 event_work);
880 struct ath10k_qmi_driver_event *event;
881 struct ath10k *ar = qmi->ar;
882
883 spin_lock(&qmi->event_lock);
884 while (!list_empty(&qmi->event_list)) {
885 event = list_first_entry(&qmi->event_list,
886 struct ath10k_qmi_driver_event, list);
887 list_del(&event->list);
888 spin_unlock(&qmi->event_lock);
889
890 switch (event->type) {
891 case ATH10K_QMI_EVENT_SERVER_ARRIVE:
892 ath10k_qmi_event_server_arrive(qmi);
893 break;
894 case ATH10K_QMI_EVENT_SERVER_EXIT:
895 ath10k_qmi_event_server_exit(qmi);
896 break;
897 case ATH10K_QMI_EVENT_FW_READY_IND:
898 ath10k_qmi_event_fw_ready_ind(qmi);
899 break;
900 case ATH10K_QMI_EVENT_MSA_READY_IND:
901 ath10k_qmi_event_msa_ready(qmi);
902 break;
903 default:
904 ath10k_warn(ar, "invalid event type: %d", event->type);
905 break;
906 }
907 kfree(event);
908 spin_lock(&qmi->event_lock);
909 }
910 spin_unlock(&qmi->event_lock);
911}
912
913static int ath10k_qmi_setup_msa_resources(struct ath10k_qmi *qmi, u32 msa_size)
914{
915 struct ath10k *ar = qmi->ar;
916 struct device *dev = ar->dev;
917 struct device_node *node;
918 struct resource r;
919 int ret;
920
921 node = of_parse_phandle(dev->of_node, "memory-region", 0);
922 if (node) {
923 ret = of_address_to_resource(node, 0, &r);
924 if (ret) {
925 dev_err(dev, "failed to resolve msa fixed region\n");
926 return ret;
927 }
928 of_node_put(node);
929
930 qmi->msa_pa = r.start;
931 qmi->msa_mem_size = resource_size(&r);
932 qmi->msa_va = devm_memremap(dev, qmi->msa_pa, qmi->msa_mem_size,
933 MEMREMAP_WT);
934 if (!qmi->msa_pa) {
935 dev_err(dev, "failed to map memory region: %pa\n", &r.start);
936 return -EBUSY;
937 }
938 } else {
939 qmi->msa_va = dmam_alloc_coherent(dev, msa_size,
940 &qmi->msa_pa, GFP_KERNEL);
941 if (!qmi->msa_va) {
942 ath10k_err(ar, "failed to allocate dma memory for msa region\n");
943 return -ENOMEM;
944 }
945 qmi->msa_mem_size = msa_size;
946 }
947
948 ath10k_dbg(ar, ATH10K_DBG_QMI, "msa pa: %pad , msa va: 0x%p\n",
949 &qmi->msa_pa,
950 qmi->msa_va);
951
952 return 0;
953}
954
955int ath10k_qmi_init(struct ath10k *ar, u32 msa_size)
956{
957 struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
958 struct ath10k_qmi *qmi;
959 int ret;
960
961 qmi = kzalloc(sizeof(*qmi), GFP_KERNEL);
962 if (!qmi)
963 return -ENOMEM;
964
965 qmi->ar = ar;
966 ar_snoc->qmi = qmi;
967
968 ret = ath10k_qmi_setup_msa_resources(qmi, msa_size);
969 if (ret)
970 goto err;
971
972 ret = qmi_handle_init(&qmi->qmi_hdl,
973 WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
974 &ath10k_qmi_ops, qmi_msg_handler);
975 if (ret)
976 goto err;
977
978 qmi->event_wq = alloc_workqueue("ath10k_qmi_driver_event",
979 WQ_UNBOUND, 1);
980 if (!qmi->event_wq) {
981 ath10k_err(ar, "failed to allocate workqueue\n");
982 ret = -EFAULT;
983 goto err_release_qmi_handle;
984 }
985
986 INIT_LIST_HEAD(&qmi->event_list);
987 spin_lock_init(&qmi->event_lock);
988 INIT_WORK(&qmi->event_work, ath10k_qmi_driver_event_work);
989
990 ret = qmi_add_lookup(&qmi->qmi_hdl, WLFW_SERVICE_ID_V01,
991 WLFW_SERVICE_VERS_V01, 0);
992 if (ret)
993 goto err_qmi_lookup;
994
995 return 0;
996
997err_qmi_lookup:
998 destroy_workqueue(qmi->event_wq);
999
1000err_release_qmi_handle:
1001 qmi_handle_release(&qmi->qmi_hdl);
1002
1003err:
1004 kfree(qmi);
1005 return ret;
1006}
1007
1008int ath10k_qmi_deinit(struct ath10k *ar)
1009{
1010 struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
1011 struct ath10k_qmi *qmi = ar_snoc->qmi;
1012
1013 qmi_handle_release(&qmi->qmi_hdl);
1014 cancel_work_sync(&qmi->event_work);
1015 destroy_workqueue(qmi->event_wq);
1016 ar_snoc->qmi = NULL;
1017
1018 return 0;
1019}
diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h
new file mode 100644
index 000000000000..1efe1d22fc2f
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/qmi.h
@@ -0,0 +1,129 @@
1/*
2 * Copyright (c) 2018 The Linux Foundation. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16#ifndef _ATH10K_QMI_H_
17#define _ATH10K_QMI_H_
18
19#include <linux/soc/qcom/qmi.h>
20#include <linux/qrtr.h>
21#include "qmi_wlfw_v01.h"
22
23#define MAX_NUM_MEMORY_REGIONS 2
24#define MAX_TIMESTAMP_LEN 32
25#define MAX_BUILD_ID_LEN 128
26#define MAX_NUM_CAL_V01 5
27
28enum ath10k_qmi_driver_event_type {
29 ATH10K_QMI_EVENT_SERVER_ARRIVE,
30 ATH10K_QMI_EVENT_SERVER_EXIT,
31 ATH10K_QMI_EVENT_FW_READY_IND,
32 ATH10K_QMI_EVENT_FW_DOWN_IND,
33 ATH10K_QMI_EVENT_MSA_READY_IND,
34 ATH10K_QMI_EVENT_MAX,
35};
36
37struct ath10k_msa_mem_info {
38 phys_addr_t addr;
39 u32 size;
40 bool secure;
41};
42
43struct ath10k_qmi_chip_info {
44 u32 chip_id;
45 u32 chip_family;
46};
47
48struct ath10k_qmi_board_info {
49 u32 board_id;
50};
51
52struct ath10k_qmi_soc_info {
53 u32 soc_id;
54};
55
56struct ath10k_qmi_cal_data {
57 u32 cal_id;
58 u32 total_size;
59 u8 *data;
60};
61
62struct ath10k_tgt_pipe_cfg {
63 __le32 pipe_num;
64 __le32 pipe_dir;
65 __le32 nentries;
66 __le32 nbytes_max;
67 __le32 flags;
68 __le32 reserved;
69};
70
71struct ath10k_svc_pipe_cfg {
72 __le32 service_id;
73 __le32 pipe_dir;
74 __le32 pipe_num;
75};
76
77struct ath10k_shadow_reg_cfg {
78 __le16 ce_id;
79 __le16 reg_offset;
80};
81
82struct ath10k_qmi_wlan_enable_cfg {
83 u32 num_ce_tgt_cfg;
84 struct ath10k_tgt_pipe_cfg *ce_tgt_cfg;
85 u32 num_ce_svc_pipe_cfg;
86 struct ath10k_svc_pipe_cfg *ce_svc_cfg;
87 u32 num_shadow_reg_cfg;
88 struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
89};
90
91struct ath10k_qmi_driver_event {
92 struct list_head list;
93 enum ath10k_qmi_driver_event_type type;
94 void *data;
95};
96
97struct ath10k_qmi {
98 struct ath10k *ar;
99 struct qmi_handle qmi_hdl;
100 struct sockaddr_qrtr sq;
101 struct work_struct event_work;
102 struct workqueue_struct *event_wq;
103 struct list_head event_list;
104 spinlock_t event_lock; /* spinlock for qmi event list */
105 u32 nr_mem_region;
106 struct ath10k_msa_mem_info mem_region[MAX_NUM_MEMORY_REGIONS];
107 dma_addr_t msa_pa;
108 u32 msa_mem_size;
109 void *msa_va;
110 struct ath10k_qmi_chip_info chip_info;
111 struct ath10k_qmi_board_info board_info;
112 struct ath10k_qmi_soc_info soc_info;
113 char fw_build_id[MAX_BUILD_ID_LEN + 1];
114 u32 fw_version;
115 bool fw_ready;
116 char fw_build_timestamp[MAX_TIMESTAMP_LEN + 1];
117 struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01];
118};
119
120int ath10k_qmi_wlan_enable(struct ath10k *ar,
121 struct ath10k_qmi_wlan_enable_cfg *config,
122 enum wlfw_driver_mode_enum_v01 mode,
123 const char *version);
124int ath10k_qmi_wlan_disable(struct ath10k *ar);
125int ath10k_qmi_register_service_notifier(struct notifier_block *nb);
126int ath10k_qmi_init(struct ath10k *ar, u32 msa_size);
127int ath10k_qmi_deinit(struct ath10k *ar);
128
129#endif /* ATH10K_QMI_H */
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index f7b5b855aab2..8d3d9bca410f 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -67,6 +67,72 @@ static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);
67static const struct ath10k_snoc_drv_priv drv_priv = { 67static const struct ath10k_snoc_drv_priv drv_priv = {
68 .hw_rev = ATH10K_HW_WCN3990, 68 .hw_rev = ATH10K_HW_WCN3990,
69 .dma_mask = DMA_BIT_MASK(37), 69 .dma_mask = DMA_BIT_MASK(37),
70 .msa_size = 0x100000,
71};
72
73#define WCN3990_SRC_WR_IDX_OFFSET 0x3C
74#define WCN3990_DST_WR_IDX_OFFSET 0x40
75
76static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {
77 {
78 .ce_id = __cpu_to_le16(0),
79 .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
80 },
81
82 {
83 .ce_id = __cpu_to_le16(3),
84 .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
85 },
86
87 {
88 .ce_id = __cpu_to_le16(4),
89 .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
90 },
91
92 {
93 .ce_id = __cpu_to_le16(5),
94 .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
95 },
96
97 {
98 .ce_id = __cpu_to_le16(7),
99 .reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),
100 },
101
102 {
103 .ce_id = __cpu_to_le16(1),
104 .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
105 },
106
107 {
108 .ce_id = __cpu_to_le16(2),
109 .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
110 },
111
112 {
113 .ce_id = __cpu_to_le16(7),
114 .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
115 },
116
117 {
118 .ce_id = __cpu_to_le16(8),
119 .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
120 },
121
122 {
123 .ce_id = __cpu_to_le16(9),
124 .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
125 },
126
127 {
128 .ce_id = __cpu_to_le16(10),
129 .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
130 },
131
132 {
133 .ce_id = __cpu_to_le16(11),
134 .reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),
135 },
70}; 136};
71 137
72static struct ce_attr host_ce_config_wlan[] = { 138static struct ce_attr host_ce_config_wlan[] = {
@@ -176,6 +242,128 @@ static struct ce_attr host_ce_config_wlan[] = {
176 }, 242 },
177}; 243};
178 244
245static struct ce_pipe_config target_ce_config_wlan[] = {
246 /* CE0: host->target HTC control and raw streams */
247 {
248 .pipenum = __cpu_to_le32(0),
249 .pipedir = __cpu_to_le32(PIPEDIR_OUT),
250 .nentries = __cpu_to_le32(32),
251 .nbytes_max = __cpu_to_le32(2048),
252 .flags = __cpu_to_le32(CE_ATTR_FLAGS),
253 .reserved = __cpu_to_le32(0),
254 },
255
256 /* CE1: target->host HTT + HTC control */
257 {
258 .pipenum = __cpu_to_le32(1),
259 .pipedir = __cpu_to_le32(PIPEDIR_IN),
260 .nentries = __cpu_to_le32(32),
261 .nbytes_max = __cpu_to_le32(2048),
262 .flags = __cpu_to_le32(CE_ATTR_FLAGS),
263 .reserved = __cpu_to_le32(0),
264 },
265
266 /* CE2: target->host WMI */
267 {
268 .pipenum = __cpu_to_le32(2),
269 .pipedir = __cpu_to_le32(PIPEDIR_IN),
270 .nentries = __cpu_to_le32(64),
271 .nbytes_max = __cpu_to_le32(2048),
272 .flags = __cpu_to_le32(CE_ATTR_FLAGS),
273 .reserved = __cpu_to_le32(0),
274 },
275
276 /* CE3: host->target WMI */
277 {
278 .pipenum = __cpu_to_le32(3),
279 .pipedir = __cpu_to_le32(PIPEDIR_OUT),
280 .nentries = __cpu_to_le32(32),
281 .nbytes_max = __cpu_to_le32(2048),
282 .flags = __cpu_to_le32(CE_ATTR_FLAGS),
283 .reserved = __cpu_to_le32(0),
284 },
285
286 /* CE4: host->target HTT */
287 {
288 .pipenum = __cpu_to_le32(4),
289 .pipedir = __cpu_to_le32(PIPEDIR_OUT),
290 .nentries = __cpu_to_le32(256),
291 .nbytes_max = __cpu_to_le32(256),
292 .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
293 .reserved = __cpu_to_le32(0),
294 },
295
296 /* CE5: target->host HTT (HIF->HTT) */
297 {
298 .pipenum = __cpu_to_le32(5),
299 .pipedir = __cpu_to_le32(PIPEDIR_OUT),
300 .nentries = __cpu_to_le32(1024),
301 .nbytes_max = __cpu_to_le32(64),
302 .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
303 .reserved = __cpu_to_le32(0),
304 },
305
306 /* CE6: Reserved for target autonomous hif_memcpy */
307 {
308 .pipenum = __cpu_to_le32(6),
309 .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
310 .nentries = __cpu_to_le32(32),
311 .nbytes_max = __cpu_to_le32(16384),
312 .flags = __cpu_to_le32(CE_ATTR_FLAGS),
313 .reserved = __cpu_to_le32(0),
314 },
315
316 /* CE7 used only by Host */
317 {
318 .pipenum = __cpu_to_le32(7),
319 .pipedir = __cpu_to_le32(4),
320 .nentries = __cpu_to_le32(0),
321 .nbytes_max = __cpu_to_le32(0),
322 .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
323 .reserved = __cpu_to_le32(0),
324 },
325
326 /* CE8 Target to uMC */
327 {
328 .pipenum = __cpu_to_le32(8),
329 .pipedir = __cpu_to_le32(PIPEDIR_IN),
330 .nentries = __cpu_to_le32(32),
331 .nbytes_max = __cpu_to_le32(2048),
332 .flags = __cpu_to_le32(0),
333 .reserved = __cpu_to_le32(0),
334 },
335
336 /* CE9 target->host HTT */
337 {
338 .pipenum = __cpu_to_le32(9),
339 .pipedir = __cpu_to_le32(PIPEDIR_IN),
340 .nentries = __cpu_to_le32(32),
341 .nbytes_max = __cpu_to_le32(2048),
342 .flags = __cpu_to_le32(CE_ATTR_FLAGS),
343 .reserved = __cpu_to_le32(0),
344 },
345
346 /* CE10 target->host HTT */
347 {
348 .pipenum = __cpu_to_le32(10),
349 .pipedir = __cpu_to_le32(PIPEDIR_IN),
350 .nentries = __cpu_to_le32(32),
351 .nbytes_max = __cpu_to_le32(2048),
352 .flags = __cpu_to_le32(CE_ATTR_FLAGS),
353 .reserved = __cpu_to_le32(0),
354 },
355
356 /* CE11 target autonomous qcache memcpy */
357 {
358 .pipenum = __cpu_to_le32(11),
359 .pipedir = __cpu_to_le32(PIPEDIR_IN),
360 .nentries = __cpu_to_le32(32),
361 .nbytes_max = __cpu_to_le32(2048),
362 .flags = __cpu_to_le32(CE_ATTR_FLAGS),
363 .reserved = __cpu_to_le32(0),
364 },
365};
366
179static struct service_to_pipe target_service_to_ce_map_wlan[] = { 367static struct service_to_pipe target_service_to_ce_map_wlan[] = {
180 { 368 {
181 __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), 369 __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
@@ -766,11 +954,47 @@ static int ath10k_snoc_init_pipes(struct ath10k *ar)
766 954
767static int ath10k_snoc_wlan_enable(struct ath10k *ar) 955static int ath10k_snoc_wlan_enable(struct ath10k *ar)
768{ 956{
769 return 0; 957 struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];
958 struct ath10k_qmi_wlan_enable_cfg cfg;
959 enum wlfw_driver_mode_enum_v01 mode;
960 int pipe_num;
961
962 for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) {
963 tgt_cfg[pipe_num].pipe_num =
964 target_ce_config_wlan[pipe_num].pipenum;
965 tgt_cfg[pipe_num].pipe_dir =
966 target_ce_config_wlan[pipe_num].pipedir;
967 tgt_cfg[pipe_num].nentries =
968 target_ce_config_wlan[pipe_num].nentries;
969 tgt_cfg[pipe_num].nbytes_max =
970 target_ce_config_wlan[pipe_num].nbytes_max;
971 tgt_cfg[pipe_num].flags =
972 target_ce_config_wlan[pipe_num].flags;
973 tgt_cfg[pipe_num].reserved = 0;
974 }
975
976 cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /
977 sizeof(struct ath10k_tgt_pipe_cfg);
978 cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *)
979 &tgt_cfg;
980 cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /
981 sizeof(struct ath10k_svc_pipe_cfg);
982 cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *)
983 &target_service_to_ce_map_wlan;
984 cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) /
985 sizeof(struct ath10k_shadow_reg_cfg);
986 cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)
987 &target_shadow_reg_cfg_map;
988
989 mode = QMI_WLFW_MISSION_V01;
990
991 return ath10k_qmi_wlan_enable(ar, &cfg, mode,
992 NULL);
770} 993}
771 994
772static void ath10k_snoc_wlan_disable(struct ath10k *ar) 995static void ath10k_snoc_wlan_disable(struct ath10k *ar)
773{ 996{
997 ath10k_qmi_wlan_disable(ar);
774} 998}
775 999
776static void ath10k_snoc_hif_power_down(struct ath10k *ar) 1000static void ath10k_snoc_hif_power_down(struct ath10k *ar)
@@ -957,6 +1181,32 @@ out:
957 return ret; 1181 return ret;
958} 1182}
959 1183
1184int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
1185{
1186 struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
1187 struct ath10k_bus_params bus_params;
1188 int ret;
1189
1190 switch (type) {
1191 case ATH10K_QMI_EVENT_FW_READY_IND:
1192 bus_params.dev_type = ATH10K_DEV_TYPE_LL;
1193 bus_params.chip_id = ar_snoc->target_info.soc_version;
1194 ret = ath10k_core_register(ar, &bus_params);
1195 if (ret) {
1196 ath10k_err(ar, "failed to register driver core: %d\n",
1197 ret);
1198 }
1199 break;
1200 case ATH10K_QMI_EVENT_FW_DOWN_IND:
1201 break;
1202 default:
1203 ath10k_err(ar, "invalid fw indication: %llx\n", type);
1204 return -EINVAL;
1205 }
1206
1207 return 0;
1208}
1209
960static int ath10k_snoc_setup_resource(struct ath10k *ar) 1210static int ath10k_snoc_setup_resource(struct ath10k *ar)
961{ 1211{
962 struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); 1212 struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
@@ -1281,9 +1531,9 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
1281 struct ath10k_snoc *ar_snoc; 1531 struct ath10k_snoc *ar_snoc;
1282 struct device *dev; 1532 struct device *dev;
1283 struct ath10k *ar; 1533 struct ath10k *ar;
1534 u32 msa_size;
1284 int ret; 1535 int ret;
1285 u32 i; 1536 u32 i;
1286 struct ath10k_bus_params bus_params;
1287 1537
1288 of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev); 1538 of_id = of_match_device(ath10k_snoc_dt_match, &pdev->dev);
1289 if (!of_id) { 1539 if (!of_id) {
@@ -1313,6 +1563,7 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
1313 ar_snoc->ar = ar; 1563 ar_snoc->ar = ar;
1314 ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops; 1564 ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops;
1315 ar->ce_priv = &ar_snoc->ce; 1565 ar->ce_priv = &ar_snoc->ce;
1566 msa_size = drv_data->msa_size;
1316 1567
1317 ret = ath10k_snoc_resource_init(ar); 1568 ret = ath10k_snoc_resource_init(ar);
1318 if (ret) { 1569 if (ret) {
@@ -1351,12 +1602,10 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
1351 goto err_free_irq; 1602 goto err_free_irq;
1352 } 1603 }
1353 1604
1354 bus_params.dev_type = ATH10K_DEV_TYPE_LL; 1605 ret = ath10k_qmi_init(ar, msa_size);
1355 bus_params.chip_id = drv_data->hw_rev;
1356 ret = ath10k_core_register(ar, &bus_params);
1357 if (ret) { 1606 if (ret) {
1358 ath10k_err(ar, "failed to register driver core: %d\n", ret); 1607 ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);
1359 goto err_hw_power_off; 1608 goto err_core_destroy;
1360 } 1609 }
1361 1610
1362 ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n"); 1611 ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");
@@ -1364,9 +1613,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
1364 1613
1365 return 0; 1614 return 0;
1366 1615
1367err_hw_power_off:
1368 ath10k_hw_power_off(ar);
1369
1370err_free_irq: 1616err_free_irq:
1371 ath10k_snoc_free_irq(ar); 1617 ath10k_snoc_free_irq(ar);
1372 1618
@@ -1388,6 +1634,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
1388 ath10k_hw_power_off(ar); 1634 ath10k_hw_power_off(ar);
1389 ath10k_snoc_free_irq(ar); 1635 ath10k_snoc_free_irq(ar);
1390 ath10k_snoc_release_resource(ar); 1636 ath10k_snoc_release_resource(ar);
1637 ath10k_qmi_deinit(ar);
1391 ath10k_core_destroy(ar); 1638 ath10k_core_destroy(ar);
1392 1639
1393 return 0; 1640 return 0;
diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h
index f9e530189d48..e1d2d6675556 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.h
+++ b/drivers/net/wireless/ath/ath10k/snoc.h
@@ -19,10 +19,12 @@
19 19
20#include "hw.h" 20#include "hw.h"
21#include "ce.h" 21#include "ce.h"
22#include "qmi.h"
22 23
23struct ath10k_snoc_drv_priv { 24struct ath10k_snoc_drv_priv {
24 enum ath10k_hw_rev hw_rev; 25 enum ath10k_hw_rev hw_rev;
25 u64 dma_mask; 26 u64 dma_mask;
27 u32 msa_size;
26}; 28};
27 29
28struct snoc_state { 30struct snoc_state {
@@ -81,6 +83,7 @@ struct ath10k_snoc {
81 struct timer_list rx_post_retry; 83 struct timer_list rx_post_retry;
82 struct ath10k_wcn3990_vreg_info *vreg; 84 struct ath10k_wcn3990_vreg_info *vreg;
83 struct ath10k_wcn3990_clk_info *clk; 85 struct ath10k_wcn3990_clk_info *clk;
86 struct ath10k_qmi *qmi;
84}; 87};
85 88
86static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) 89static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
@@ -90,5 +93,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
90 93
91void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value); 94void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value);
92u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset); 95u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset);
96int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type);
93 97
94#endif /* _SNOC_H_ */ 98#endif /* _SNOC_H_ */