linux/drivers/net/wireless/ath/ath10k/qmi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: ISC
   2/*
   3 * Copyright (c) 2018 The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/completion.h>
   7#include <linux/device.h>
   8#include <linux/debugfs.h>
   9#include <linux/idr.h>
  10#include <linux/kernel.h>
  11#include <linux/of.h>
  12#include <linux/of_address.h>
  13#include <linux/module.h>
  14#include <linux/net.h>
  15#include <linux/platform_device.h>
  16#include <linux/qcom_scm.h>
  17#include <linux/string.h>
  18#include <net/sock.h>
  19
  20#include "debug.h"
  21#include "snoc.h"
  22
  23#define ATH10K_QMI_CLIENT_ID            0x4b4e454c
  24#define ATH10K_QMI_TIMEOUT              30
  25
  26static int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi,
  27                                         struct ath10k_msa_mem_info *mem_info)
  28{
  29        struct qcom_scm_vmperm dst_perms[3];
  30        struct ath10k *ar = qmi->ar;
  31        unsigned int src_perms;
  32        u32 perm_count;
  33        int ret;
  34
  35        src_perms = BIT(QCOM_SCM_VMID_HLOS);
  36
  37        dst_perms[0].vmid = QCOM_SCM_VMID_MSS_MSA;
  38        dst_perms[0].perm = QCOM_SCM_PERM_RW;
  39        dst_perms[1].vmid = QCOM_SCM_VMID_WLAN;
  40        dst_perms[1].perm = QCOM_SCM_PERM_RW;
  41
  42        if (mem_info->secure) {
  43                perm_count = 2;
  44        } else {
  45                dst_perms[2].vmid = QCOM_SCM_VMID_WLAN_CE;
  46                dst_perms[2].perm = QCOM_SCM_PERM_RW;
  47                perm_count = 3;
  48        }
  49
  50        ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size,
  51                                  &src_perms, dst_perms, perm_count);
  52        if (ret < 0)
  53                ath10k_err(ar, "failed to assign msa map permissions: %d\n", ret);
  54
  55        return ret;
  56}
  57
  58static int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi,
  59                                           struct ath10k_msa_mem_info *mem_info)
  60{
  61        struct qcom_scm_vmperm dst_perms;
  62        struct ath10k *ar = qmi->ar;
  63        unsigned int src_perms;
  64        int ret;
  65
  66        src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN);
  67
  68        if (!mem_info->secure)
  69                src_perms |= BIT(QCOM_SCM_VMID_WLAN_CE);
  70
  71        dst_perms.vmid = QCOM_SCM_VMID_HLOS;
  72        dst_perms.perm = QCOM_SCM_PERM_RW;
  73
  74        ret = qcom_scm_assign_mem(mem_info->addr, mem_info->size,
  75                                  &src_perms, &dst_perms, 1);
  76        if (ret < 0)
  77                ath10k_err(ar, "failed to unmap msa permissions: %d\n", ret);
  78
  79        return ret;
  80}
  81
  82static int ath10k_qmi_setup_msa_permissions(struct ath10k_qmi *qmi)
  83{
  84        int ret;
  85        int i;
  86
  87        for (i = 0; i < qmi->nr_mem_region; i++) {
  88                ret = ath10k_qmi_map_msa_permission(qmi, &qmi->mem_region[i]);
  89                if (ret)
  90                        goto err_unmap;
  91        }
  92
  93        return 0;
  94
  95err_unmap:
  96        for (i--; i >= 0; i--)
  97                ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]);
  98        return ret;
  99}
 100
 101static void ath10k_qmi_remove_msa_permission(struct ath10k_qmi *qmi)
 102{
 103        int i;
 104
 105        for (i = 0; i < qmi->nr_mem_region; i++)
 106                ath10k_qmi_unmap_msa_permission(qmi, &qmi->mem_region[i]);
 107}
 108
 109static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi)
 110{
 111        struct wlfw_msa_info_resp_msg_v01 resp = {};
 112        struct wlfw_msa_info_req_msg_v01 req = {};
 113        struct ath10k *ar = qmi->ar;
 114        struct qmi_txn txn;
 115        int ret;
 116        int i;
 117
 118        req.msa_addr = qmi->msa_pa;
 119        req.size = qmi->msa_mem_size;
 120
 121        ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
 122                           wlfw_msa_info_resp_msg_v01_ei, &resp);
 123        if (ret < 0)
 124                goto out;
 125
 126        ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 127                               QMI_WLFW_MSA_INFO_REQ_V01,
 128                               WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN,
 129                               wlfw_msa_info_req_msg_v01_ei, &req);
 130        if (ret < 0) {
 131                qmi_txn_cancel(&txn);
 132                ath10k_err(ar, "failed to send msa mem info req: %d\n", ret);
 133                goto out;
 134        }
 135
 136        ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 137        if (ret < 0)
 138                goto out;
 139
 140        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 141                ath10k_err(ar, "msa info req rejected: %d\n", resp.resp.error);
 142                ret = -EINVAL;
 143                goto out;
 144        }
 145
 146        if (resp.mem_region_info_len > QMI_WLFW_MAX_MEM_REG_V01) {
 147                ath10k_err(ar, "invalid memory region length received: %d\n",
 148                           resp.mem_region_info_len);
 149                ret = -EINVAL;
 150                goto out;
 151        }
 152
 153        qmi->nr_mem_region = resp.mem_region_info_len;
 154        for (i = 0; i < resp.mem_region_info_len; i++) {
 155                qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr;
 156                qmi->mem_region[i].size = resp.mem_region_info[i].size;
 157                qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag;
 158                ath10k_dbg(ar, ATH10K_DBG_QMI,
 159                           "qmi msa mem region %d addr 0x%pa size 0x%x flag 0x%08x\n",
 160                           i, &qmi->mem_region[i].addr,
 161                           qmi->mem_region[i].size,
 162                           qmi->mem_region[i].secure);
 163        }
 164
 165        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n");
 166        return 0;
 167
 168out:
 169        return ret;
 170}
 171
 172static int ath10k_qmi_msa_ready_send_sync_msg(struct ath10k_qmi *qmi)
 173{
 174        struct wlfw_msa_ready_resp_msg_v01 resp = {};
 175        struct wlfw_msa_ready_req_msg_v01 req = {};
 176        struct ath10k *ar = qmi->ar;
 177        struct qmi_txn txn;
 178        int ret;
 179
 180        ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
 181                           wlfw_msa_ready_resp_msg_v01_ei, &resp);
 182        if (ret < 0)
 183                goto out;
 184
 185        ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 186                               QMI_WLFW_MSA_READY_REQ_V01,
 187                               WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN,
 188                               wlfw_msa_ready_req_msg_v01_ei, &req);
 189        if (ret < 0) {
 190                qmi_txn_cancel(&txn);
 191                ath10k_err(ar, "failed to send msa mem ready request: %d\n", ret);
 192                goto out;
 193        }
 194
 195        ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 196        if (ret < 0)
 197                goto out;
 198
 199        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 200                ath10k_err(ar, "msa ready request rejected: %d\n", resp.resp.error);
 201                ret = -EINVAL;
 202        }
 203
 204        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem ready request completed\n");
 205        return 0;
 206
 207out:
 208        return ret;
 209}
 210
 211static int ath10k_qmi_bdf_dnld_send_sync(struct ath10k_qmi *qmi)
 212{
 213        struct wlfw_bdf_download_resp_msg_v01 resp = {};
 214        struct wlfw_bdf_download_req_msg_v01 *req;
 215        struct ath10k *ar = qmi->ar;
 216        unsigned int remaining;
 217        struct qmi_txn txn;
 218        const u8 *temp;
 219        int ret;
 220
 221        req = kzalloc(sizeof(*req), GFP_KERNEL);
 222        if (!req)
 223                return -ENOMEM;
 224
 225        temp = ar->normal_mode_fw.board_data;
 226        remaining = ar->normal_mode_fw.board_len;
 227
 228        while (remaining) {
 229                req->valid = 1;
 230                req->file_id_valid = 1;
 231                req->file_id = 0;
 232                req->total_size_valid = 1;
 233                req->total_size = ar->normal_mode_fw.board_len;
 234                req->seg_id_valid = 1;
 235                req->data_valid = 1;
 236                req->end_valid = 1;
 237
 238                if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
 239                        req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
 240                } else {
 241                        req->data_len = remaining;
 242                        req->end = 1;
 243                }
 244
 245                memcpy(req->data, temp, req->data_len);
 246
 247                ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
 248                                   wlfw_bdf_download_resp_msg_v01_ei,
 249                                   &resp);
 250                if (ret < 0)
 251                        goto out;
 252
 253                ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 254                                       QMI_WLFW_BDF_DOWNLOAD_REQ_V01,
 255                                       WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
 256                                       wlfw_bdf_download_req_msg_v01_ei, req);
 257                if (ret < 0) {
 258                        qmi_txn_cancel(&txn);
 259                        goto out;
 260                }
 261
 262                ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 263
 264                if (ret < 0)
 265                        goto out;
 266
 267                if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 268                        ath10k_err(ar, "failed to download board data file: %d\n",
 269                                   resp.resp.error);
 270                        ret = -EINVAL;
 271                        goto out;
 272                }
 273
 274                remaining -= req->data_len;
 275                temp += req->data_len;
 276                req->seg_id++;
 277        }
 278
 279        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi bdf download request completed\n");
 280
 281        kfree(req);
 282        return 0;
 283
 284out:
 285        kfree(req);
 286        return ret;
 287}
 288
 289static int ath10k_qmi_send_cal_report_req(struct ath10k_qmi *qmi)
 290{
 291        struct wlfw_cal_report_resp_msg_v01 resp = {};
 292        struct wlfw_cal_report_req_msg_v01 req = {};
 293        struct ath10k *ar = qmi->ar;
 294        struct qmi_txn txn;
 295        int i, j = 0;
 296        int ret;
 297
 298        ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei,
 299                           &resp);
 300        if (ret < 0)
 301                goto out;
 302
 303        for (i = 0; i < QMI_WLFW_MAX_NUM_CAL_V01; i++) {
 304                if (qmi->cal_data[i].total_size &&
 305                    qmi->cal_data[i].data) {
 306                        req.meta_data[j] = qmi->cal_data[i].cal_id;
 307                        j++;
 308                }
 309        }
 310        req.meta_data_len = j;
 311
 312        ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 313                               QMI_WLFW_CAL_REPORT_REQ_V01,
 314                               WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN,
 315                               wlfw_cal_report_req_msg_v01_ei, &req);
 316        if (ret < 0) {
 317                qmi_txn_cancel(&txn);
 318                ath10k_err(ar, "failed to send calibration request: %d\n", ret);
 319                goto out;
 320        }
 321
 322        ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 323        if (ret < 0)
 324                goto out;
 325
 326        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 327                ath10k_err(ar, "calibration request rejected: %d\n", resp.resp.error);
 328                ret = -EINVAL;
 329                goto out;
 330        }
 331
 332        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi cal report request completed\n");
 333        return 0;
 334
 335out:
 336        return ret;
 337}
 338
 339static int
 340ath10k_qmi_mode_send_sync_msg(struct ath10k *ar, enum wlfw_driver_mode_enum_v01 mode)
 341{
 342        struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 343        struct ath10k_qmi *qmi = ar_snoc->qmi;
 344        struct wlfw_wlan_mode_resp_msg_v01 resp = {};
 345        struct wlfw_wlan_mode_req_msg_v01 req = {};
 346        struct qmi_txn txn;
 347        int ret;
 348
 349        ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
 350                           wlfw_wlan_mode_resp_msg_v01_ei,
 351                           &resp);
 352        if (ret < 0)
 353                goto out;
 354
 355        req.mode = mode;
 356        req.hw_debug_valid = 1;
 357        req.hw_debug = 0;
 358
 359        ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 360                               QMI_WLFW_WLAN_MODE_REQ_V01,
 361                               WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN,
 362                               wlfw_wlan_mode_req_msg_v01_ei, &req);
 363        if (ret < 0) {
 364                qmi_txn_cancel(&txn);
 365                ath10k_err(ar, "failed to send wlan mode %d request: %d\n", mode, ret);
 366                goto out;
 367        }
 368
 369        ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 370        if (ret < 0)
 371                goto out;
 372
 373        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 374                ath10k_err(ar, "more request rejected: %d\n", resp.resp.error);
 375                ret = -EINVAL;
 376                goto out;
 377        }
 378
 379        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wlan mode req completed: %d\n", mode);
 380        return 0;
 381
 382out:
 383        return ret;
 384}
 385
 386static int
 387ath10k_qmi_cfg_send_sync_msg(struct ath10k *ar,
 388                             struct ath10k_qmi_wlan_enable_cfg *config,
 389                             const char *version)
 390{
 391        struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 392        struct ath10k_qmi *qmi = ar_snoc->qmi;
 393        struct wlfw_wlan_cfg_resp_msg_v01 resp = {};
 394        struct wlfw_wlan_cfg_req_msg_v01 *req;
 395        struct qmi_txn txn;
 396        int ret;
 397        u32 i;
 398
 399        req = kzalloc(sizeof(*req), GFP_KERNEL);
 400        if (!req)
 401                return -ENOMEM;
 402
 403        ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
 404                           wlfw_wlan_cfg_resp_msg_v01_ei,
 405                           &resp);
 406        if (ret < 0)
 407                goto out;
 408
 409        req->host_version_valid = 0;
 410
 411        req->tgt_cfg_valid = 1;
 412        if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01)
 413                req->tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
 414        else
 415                req->tgt_cfg_len = config->num_ce_tgt_cfg;
 416        for (i = 0; i < req->tgt_cfg_len; i++) {
 417                req->tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
 418                req->tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
 419                req->tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
 420                req->tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
 421                req->tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
 422        }
 423
 424        req->svc_cfg_valid = 1;
 425        if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01)
 426                req->svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01;
 427        else
 428                req->svc_cfg_len = config->num_ce_svc_pipe_cfg;
 429        for (i = 0; i < req->svc_cfg_len; i++) {
 430                req->svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
 431                req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
 432                req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
 433        }
 434
 435        req->shadow_reg_valid = 1;
 436        if (config->num_shadow_reg_cfg >
 437            QMI_WLFW_MAX_NUM_SHADOW_REG_V01)
 438                req->shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01;
 439        else
 440                req->shadow_reg_len = config->num_shadow_reg_cfg;
 441
 442        memcpy(req->shadow_reg, config->shadow_reg_cfg,
 443               sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req->shadow_reg_len);
 444
 445        ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 446                               QMI_WLFW_WLAN_CFG_REQ_V01,
 447                               WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN,
 448                               wlfw_wlan_cfg_req_msg_v01_ei, req);
 449        if (ret < 0) {
 450                qmi_txn_cancel(&txn);
 451                ath10k_err(ar, "failed to send config request: %d\n", ret);
 452                goto out;
 453        }
 454
 455        ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 456        if (ret < 0)
 457                goto out;
 458
 459        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 460                ath10k_err(ar, "config request rejected: %d\n", resp.resp.error);
 461                ret = -EINVAL;
 462                goto out;
 463        }
 464
 465        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi config request completed\n");
 466        kfree(req);
 467        return 0;
 468
 469out:
 470        kfree(req);
 471        return ret;
 472}
 473
 474int ath10k_qmi_wlan_enable(struct ath10k *ar,
 475                           struct ath10k_qmi_wlan_enable_cfg *config,
 476                           enum wlfw_driver_mode_enum_v01 mode,
 477                           const char *version)
 478{
 479        int ret;
 480
 481        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi mode %d config %p\n",
 482                   mode, config);
 483
 484        ret = ath10k_qmi_cfg_send_sync_msg(ar, config, version);
 485        if (ret) {
 486                ath10k_err(ar, "failed to send qmi config: %d\n", ret);
 487                return ret;
 488        }
 489
 490        ret = ath10k_qmi_mode_send_sync_msg(ar, mode);
 491        if (ret) {
 492                ath10k_err(ar, "failed to send qmi mode: %d\n", ret);
 493                return ret;
 494        }
 495
 496        return 0;
 497}
 498
 499int ath10k_qmi_wlan_disable(struct ath10k *ar)
 500{
 501        return ath10k_qmi_mode_send_sync_msg(ar, QMI_WLFW_OFF_V01);
 502}
 503
 504static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi)
 505{
 506        struct wlfw_cap_resp_msg_v01 *resp;
 507        struct wlfw_cap_req_msg_v01 req = {};
 508        struct ath10k *ar = qmi->ar;
 509        struct qmi_txn txn;
 510        int ret;
 511
 512        resp = kzalloc(sizeof(*resp), GFP_KERNEL);
 513        if (!resp)
 514                return -ENOMEM;
 515
 516        ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cap_resp_msg_v01_ei, resp);
 517        if (ret < 0)
 518                goto out;
 519
 520        ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 521                               QMI_WLFW_CAP_REQ_V01,
 522                               WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN,
 523                               wlfw_cap_req_msg_v01_ei, &req);
 524        if (ret < 0) {
 525                qmi_txn_cancel(&txn);
 526                ath10k_err(ar, "failed to send capability request: %d\n", ret);
 527                goto out;
 528        }
 529
 530        ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 531        if (ret < 0)
 532                goto out;
 533
 534        if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
 535                ath10k_err(ar, "capability req rejected: %d\n", resp->resp.error);
 536                ret = -EINVAL;
 537                goto out;
 538        }
 539
 540        if (resp->chip_info_valid) {
 541                qmi->chip_info.chip_id = resp->chip_info.chip_id;
 542                qmi->chip_info.chip_family = resp->chip_info.chip_family;
 543        }
 544
 545        if (resp->board_info_valid)
 546                qmi->board_info.board_id = resp->board_info.board_id;
 547        else
 548                qmi->board_info.board_id = 0xFF;
 549
 550        if (resp->soc_info_valid)
 551                qmi->soc_info.soc_id = resp->soc_info.soc_id;
 552
 553        if (resp->fw_version_info_valid) {
 554                qmi->fw_version = resp->fw_version_info.fw_version;
 555                strlcpy(qmi->fw_build_timestamp, resp->fw_version_info.fw_build_timestamp,
 556                        sizeof(qmi->fw_build_timestamp));
 557        }
 558
 559        if (resp->fw_build_id_valid)
 560                strlcpy(qmi->fw_build_id, resp->fw_build_id,
 561                        MAX_BUILD_ID_LEN + 1);
 562
 563        ath10k_dbg(ar, ATH10K_DBG_QMI,
 564                   "qmi chip_id 0x%x chip_family 0x%x board_id 0x%x soc_id 0x%x",
 565                   qmi->chip_info.chip_id, qmi->chip_info.chip_family,
 566                   qmi->board_info.board_id, qmi->soc_info.soc_id);
 567        ath10k_dbg(ar, ATH10K_DBG_QMI,
 568                   "qmi fw_version 0x%x fw_build_timestamp %s fw_build_id %s",
 569                   qmi->fw_version, qmi->fw_build_timestamp, qmi->fw_build_id);
 570
 571        kfree(resp);
 572        return 0;
 573
 574out:
 575        kfree(resp);
 576        return ret;
 577}
 578
 579static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi)
 580{
 581        struct wlfw_host_cap_resp_msg_v01 resp = {};
 582        struct wlfw_host_cap_req_msg_v01 req = {};
 583        struct ath10k *ar = qmi->ar;
 584        struct qmi_txn txn;
 585        int ret;
 586
 587        req.daemon_support_valid = 1;
 588        req.daemon_support = 0;
 589
 590        ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
 591                           wlfw_host_cap_resp_msg_v01_ei, &resp);
 592        if (ret < 0)
 593                goto out;
 594
 595        ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 596                               QMI_WLFW_HOST_CAP_REQ_V01,
 597                               WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN,
 598                               wlfw_host_cap_req_msg_v01_ei, &req);
 599        if (ret < 0) {
 600                qmi_txn_cancel(&txn);
 601                ath10k_err(ar, "failed to send host capability request: %d\n", ret);
 602                goto out;
 603        }
 604
 605        ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 606        if (ret < 0)
 607                goto out;
 608
 609        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 610                ath10k_err(ar, "host capability request rejected: %d\n", resp.resp.error);
 611                ret = -EINVAL;
 612                goto out;
 613        }
 614
 615        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi host capability request completed\n");
 616        return 0;
 617
 618out:
 619        return ret;
 620}
 621
 622static int
 623ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi)
 624{
 625        struct wlfw_ind_register_resp_msg_v01 resp = {};
 626        struct wlfw_ind_register_req_msg_v01 req = {};
 627        struct ath10k *ar = qmi->ar;
 628        struct qmi_txn txn;
 629        int ret;
 630
 631        req.client_id_valid = 1;
 632        req.client_id = ATH10K_QMI_CLIENT_ID;
 633        req.fw_ready_enable_valid = 1;
 634        req.fw_ready_enable = 1;
 635        req.msa_ready_enable_valid = 1;
 636        req.msa_ready_enable = 1;
 637
 638        ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
 639                           wlfw_ind_register_resp_msg_v01_ei, &resp);
 640        if (ret < 0)
 641                goto out;
 642
 643        ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 644                               QMI_WLFW_IND_REGISTER_REQ_V01,
 645                               WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN,
 646                               wlfw_ind_register_req_msg_v01_ei, &req);
 647        if (ret < 0) {
 648                qmi_txn_cancel(&txn);
 649                ath10k_err(ar, "failed to send indication registered request: %d\n", ret);
 650                goto out;
 651        }
 652
 653        ret = qmi_txn_wait(&txn, ATH10K_QMI_TIMEOUT * HZ);
 654        if (ret < 0)
 655                goto out;
 656
 657        if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 658                ath10k_err(ar, "indication request rejected: %d\n", resp.resp.error);
 659                ret = -EINVAL;
 660                goto out;
 661        }
 662
 663        if (resp.fw_status_valid) {
 664                if (resp.fw_status & QMI_WLFW_FW_READY_V01)
 665                        qmi->fw_ready = true;
 666        }
 667        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi indication register request completed\n");
 668        return 0;
 669
 670out:
 671        return ret;
 672}
 673
 674static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi)
 675{
 676        struct ath10k *ar = qmi->ar;
 677        int ret;
 678
 679        ret = ath10k_qmi_ind_register_send_sync_msg(qmi);
 680        if (ret)
 681                return;
 682
 683        if (qmi->fw_ready) {
 684                ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND);
 685                return;
 686        }
 687
 688        ret = ath10k_qmi_host_cap_send_sync(qmi);
 689        if (ret)
 690                return;
 691
 692        ret = ath10k_qmi_msa_mem_info_send_sync_msg(qmi);
 693        if (ret)
 694                return;
 695
 696        ret = ath10k_qmi_setup_msa_permissions(qmi);
 697        if (ret)
 698                return;
 699
 700        ret = ath10k_qmi_msa_ready_send_sync_msg(qmi);
 701        if (ret)
 702                goto err_setup_msa;
 703
 704        ret = ath10k_qmi_cap_send_sync_msg(qmi);
 705        if (ret)
 706                goto err_setup_msa;
 707
 708        return;
 709
 710err_setup_msa:
 711        ath10k_qmi_remove_msa_permission(qmi);
 712}
 713
 714static int ath10k_qmi_fetch_board_file(struct ath10k_qmi *qmi)
 715{
 716        struct ath10k *ar = qmi->ar;
 717
 718        ar->hif.bus = ATH10K_BUS_SNOC;
 719        ar->id.qmi_ids_valid = true;
 720        ar->id.qmi_board_id = qmi->board_info.board_id;
 721        ar->hw_params.fw.dir = WCN3990_HW_1_0_FW_DIR;
 722
 723        return ath10k_core_fetch_board_file(qmi->ar, ATH10K_BD_IE_BOARD);
 724}
 725
 726static int
 727ath10k_qmi_driver_event_post(struct ath10k_qmi *qmi,
 728                             enum ath10k_qmi_driver_event_type type,
 729                             void *data)
 730{
 731        struct ath10k_qmi_driver_event *event;
 732
 733        event = kzalloc(sizeof(*event), GFP_ATOMIC);
 734        if (!event)
 735                return -ENOMEM;
 736
 737        event->type = type;
 738        event->data = data;
 739
 740        spin_lock(&qmi->event_lock);
 741        list_add_tail(&event->list, &qmi->event_list);
 742        spin_unlock(&qmi->event_lock);
 743
 744        queue_work(qmi->event_wq, &qmi->event_work);
 745
 746        return 0;
 747}
 748
 749static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi)
 750{
 751        struct ath10k *ar = qmi->ar;
 752
 753        ath10k_qmi_remove_msa_permission(qmi);
 754        ath10k_core_free_board_files(ar);
 755        ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND);
 756        ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n");
 757}
 758
 759static void ath10k_qmi_event_msa_ready(struct ath10k_qmi *qmi)
 760{
 761        int ret;
 762
 763        ret = ath10k_qmi_fetch_board_file(qmi);
 764        if (ret)
 765                goto out;
 766
 767        ret = ath10k_qmi_bdf_dnld_send_sync(qmi);
 768        if (ret)
 769                goto out;
 770
 771        ret = ath10k_qmi_send_cal_report_req(qmi);
 772
 773out:
 774        return;
 775}
 776
 777static int ath10k_qmi_event_fw_ready_ind(struct ath10k_qmi *qmi)
 778{
 779        struct ath10k *ar = qmi->ar;
 780
 781        ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw ready event received\n");
 782        ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_READY_IND);
 783
 784        return 0;
 785}
 786
 787static void ath10k_qmi_fw_ready_ind(struct qmi_handle *qmi_hdl,
 788                                    struct sockaddr_qrtr *sq,
 789                                    struct qmi_txn *txn, const void *data)
 790{
 791        struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
 792
 793        ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_FW_READY_IND, NULL);
 794}
 795
 796static void ath10k_qmi_msa_ready_ind(struct qmi_handle *qmi_hdl,
 797                                     struct sockaddr_qrtr *sq,
 798                                     struct qmi_txn *txn, const void *data)
 799{
 800        struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
 801
 802        ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_MSA_READY_IND, NULL);
 803}
 804
 805static struct qmi_msg_handler qmi_msg_handler[] = {
 806        {
 807                .type = QMI_INDICATION,
 808                .msg_id = QMI_WLFW_FW_READY_IND_V01,
 809                .ei = wlfw_fw_ready_ind_msg_v01_ei,
 810                .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01),
 811                .fn = ath10k_qmi_fw_ready_ind,
 812        },
 813        {
 814                .type = QMI_INDICATION,
 815                .msg_id = QMI_WLFW_MSA_READY_IND_V01,
 816                .ei = wlfw_msa_ready_ind_msg_v01_ei,
 817                .decoded_size = sizeof(struct wlfw_msa_ready_ind_msg_v01),
 818                .fn = ath10k_qmi_msa_ready_ind,
 819        },
 820        {}
 821};
 822
 823static int ath10k_qmi_new_server(struct qmi_handle *qmi_hdl,
 824                                 struct qmi_service *service)
 825{
 826        struct ath10k_qmi *qmi = container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
 827        struct sockaddr_qrtr *sq = &qmi->sq;
 828        struct ath10k *ar = qmi->ar;
 829        int ret;
 830
 831        sq->sq_family = AF_QIPCRTR;
 832        sq->sq_node = service->node;
 833        sq->sq_port = service->port;
 834
 835        ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service found\n");
 836
 837        ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)&qmi->sq,
 838                             sizeof(qmi->sq), 0);
 839        if (ret) {
 840                ath10k_err(ar, "failed to connect to a remote QMI service port\n");
 841                return ret;
 842        }
 843
 844        ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi wifi fw qmi service connected\n");
 845        ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_ARRIVE, NULL);
 846
 847        return ret;
 848}
 849
 850static void ath10k_qmi_del_server(struct qmi_handle *qmi_hdl,
 851                                  struct qmi_service *service)
 852{
 853        struct ath10k_qmi *qmi =
 854                container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl);
 855
 856        qmi->fw_ready = false;
 857        ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_SERVER_EXIT, NULL);
 858}
 859
 860static struct qmi_ops ath10k_qmi_ops = {
 861        .new_server = ath10k_qmi_new_server,
 862        .del_server = ath10k_qmi_del_server,
 863};
 864
 865static void ath10k_qmi_driver_event_work(struct work_struct *work)
 866{
 867        struct ath10k_qmi *qmi = container_of(work, struct ath10k_qmi,
 868                                              event_work);
 869        struct ath10k_qmi_driver_event *event;
 870        struct ath10k *ar = qmi->ar;
 871
 872        spin_lock(&qmi->event_lock);
 873        while (!list_empty(&qmi->event_list)) {
 874                event = list_first_entry(&qmi->event_list,
 875                                         struct ath10k_qmi_driver_event, list);
 876                list_del(&event->list);
 877                spin_unlock(&qmi->event_lock);
 878
 879                switch (event->type) {
 880                case ATH10K_QMI_EVENT_SERVER_ARRIVE:
 881                        ath10k_qmi_event_server_arrive(qmi);
 882                        break;
 883                case ATH10K_QMI_EVENT_SERVER_EXIT:
 884                        ath10k_qmi_event_server_exit(qmi);
 885                        break;
 886                case ATH10K_QMI_EVENT_FW_READY_IND:
 887                        ath10k_qmi_event_fw_ready_ind(qmi);
 888                        break;
 889                case ATH10K_QMI_EVENT_MSA_READY_IND:
 890                        ath10k_qmi_event_msa_ready(qmi);
 891                        break;
 892                default:
 893                        ath10k_warn(ar, "invalid event type: %d", event->type);
 894                        break;
 895                }
 896                kfree(event);
 897                spin_lock(&qmi->event_lock);
 898        }
 899        spin_unlock(&qmi->event_lock);
 900}
 901
 902static int ath10k_qmi_setup_msa_resources(struct ath10k_qmi *qmi, u32 msa_size)
 903{
 904        struct ath10k *ar = qmi->ar;
 905        struct device *dev = ar->dev;
 906        struct device_node *node;
 907        struct resource r;
 908        int ret;
 909
 910        node = of_parse_phandle(dev->of_node, "memory-region", 0);
 911        if (node) {
 912                ret = of_address_to_resource(node, 0, &r);
 913                if (ret) {
 914                        dev_err(dev, "failed to resolve msa fixed region\n");
 915                        return ret;
 916                }
 917                of_node_put(node);
 918
 919                qmi->msa_pa = r.start;
 920                qmi->msa_mem_size = resource_size(&r);
 921                qmi->msa_va = devm_memremap(dev, qmi->msa_pa, qmi->msa_mem_size,
 922                                            MEMREMAP_WT);
 923                if (IS_ERR(qmi->msa_va)) {
 924                        dev_err(dev, "failed to map memory region: %pa\n", &r.start);
 925                        return PTR_ERR(qmi->msa_va);
 926                }
 927        } else {
 928                qmi->msa_va = dmam_alloc_coherent(dev, msa_size,
 929                                                  &qmi->msa_pa, GFP_KERNEL);
 930                if (!qmi->msa_va) {
 931                        ath10k_err(ar, "failed to allocate dma memory for msa region\n");
 932                        return -ENOMEM;
 933                }
 934                qmi->msa_mem_size = msa_size;
 935        }
 936
 937        ath10k_dbg(ar, ATH10K_DBG_QMI, "msa pa: %pad , msa va: 0x%p\n",
 938                   &qmi->msa_pa,
 939                   qmi->msa_va);
 940
 941        return 0;
 942}
 943
 944int ath10k_qmi_init(struct ath10k *ar, u32 msa_size)
 945{
 946        struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 947        struct ath10k_qmi *qmi;
 948        int ret;
 949
 950        qmi = kzalloc(sizeof(*qmi), GFP_KERNEL);
 951        if (!qmi)
 952                return -ENOMEM;
 953
 954        qmi->ar = ar;
 955        ar_snoc->qmi = qmi;
 956
 957        ret = ath10k_qmi_setup_msa_resources(qmi, msa_size);
 958        if (ret)
 959                goto err;
 960
 961        ret = qmi_handle_init(&qmi->qmi_hdl,
 962                              WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
 963                              &ath10k_qmi_ops, qmi_msg_handler);
 964        if (ret)
 965                goto err;
 966
 967        qmi->event_wq = alloc_workqueue("ath10k_qmi_driver_event",
 968                                        WQ_UNBOUND, 1);
 969        if (!qmi->event_wq) {
 970                ath10k_err(ar, "failed to allocate workqueue\n");
 971                ret = -EFAULT;
 972                goto err_release_qmi_handle;
 973        }
 974
 975        INIT_LIST_HEAD(&qmi->event_list);
 976        spin_lock_init(&qmi->event_lock);
 977        INIT_WORK(&qmi->event_work, ath10k_qmi_driver_event_work);
 978
 979        ret = qmi_add_lookup(&qmi->qmi_hdl, WLFW_SERVICE_ID_V01,
 980                             WLFW_SERVICE_VERS_V01, 0);
 981        if (ret)
 982                goto err_qmi_lookup;
 983
 984        return 0;
 985
 986err_qmi_lookup:
 987        destroy_workqueue(qmi->event_wq);
 988
 989err_release_qmi_handle:
 990        qmi_handle_release(&qmi->qmi_hdl);
 991
 992err:
 993        kfree(qmi);
 994        return ret;
 995}
 996
 997int ath10k_qmi_deinit(struct ath10k *ar)
 998{
 999        struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
1000        struct ath10k_qmi *qmi = ar_snoc->qmi;
1001
1002        qmi_handle_release(&qmi->qmi_hdl);
1003        cancel_work_sync(&qmi->event_work);
1004        destroy_workqueue(qmi->event_wq);
1005        ar_snoc->qmi = NULL;
1006
1007        return 0;
1008}
1009