ath10k: register qmi service notifier for ath10k snoc

Add support to configure the bus and wlan copy engine
component. Register event notifier to communicate with
the WLAN firmware over qmi communication interface.

Define data structure and method to process the QMI service
arrive, exit, msa ready and firmware event.

This feature adds support to maintain the SSR state machine
and ath10k core restart handler for the ath10k snoc driver.

Change-Id: I594611a104ef4eef499270996990a278e151101c
Signed-off-by: Sarada Prasanna Garnayak <sgarna@codeaurora.org>
This commit is contained in:
Sarada Prasanna Garnayak 2017-03-17 17:03:47 +05:30
parent 3915a67448
commit 781c40f73c
4 changed files with 580 additions and 69 deletions

View file

@ -12,10 +12,14 @@
#include <soc/qcom/subsystem_notif.h> #include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/service-notifier.h> #include <soc/qcom/service-notifier.h>
#include <soc/qcom/msm_qmi_interface.h>
#include <soc/qcom/service-locator.h>
#include "core.h" #include "core.h"
#include "qmi.h" #include "qmi.h"
#include "snoc.h" #include "snoc.h"
#include <soc/qcom/icnss.h> #include "wcn3990_qmi_service_v01.h"
static DECLARE_WAIT_QUEUE_HEAD(ath10k_fw_ready_wait_event);
static int static int
ath10k_snoc_service_notifier_notify(struct notifier_block *nb, ath10k_snoc_service_notifier_notify(struct notifier_block *nb,
@ -228,3 +232,438 @@ int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar)
return 0; return 0;
} }
static char *
ath10k_snoc_driver_event_to_str(enum ath10k_snoc_driver_event_type type)
{
switch (type) {
case ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE:
return "SERVER_ARRIVE";
case ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT:
return "SERVER_EXIT";
case ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND:
return "FW_READY";
case ATH10K_SNOC_DRIVER_EVENT_MAX:
return "EVENT_MAX";
}
return "UNKNOWN";
};
static int
ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type,
u32 flags, void *data)
{
int ret = 0;
int i = 0;
struct ath10k *ar = (struct ath10k *)data;
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Posting event: %s type: %d\n",
ath10k_snoc_driver_event_to_str(type), type);
if (type >= ATH10K_SNOC_DRIVER_EVENT_MAX) {
ath10k_err(ar, "Invalid Event type: %d, can't post", type);
return -EINVAL;
}
spin_lock_bh(&qmi_cfg->event_lock);
for (i = 0; i < ATH10K_SNOC_DRIVER_EVENT_MAX; i++) {
if (atomic_read(&qmi_cfg->qmi_ev_list[i].event_handled)) {
qmi_cfg->qmi_ev_list[i].type = type;
qmi_cfg->qmi_ev_list[i].data = data;
init_completion(&qmi_cfg->qmi_ev_list[i].complete);
qmi_cfg->qmi_ev_list[i].ret =
ATH10K_SNOC_EVENT_PENDING;
qmi_cfg->qmi_ev_list[i].sync =
!!(flags & ATH10K_SNOC_EVENT_SYNC);
atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 0);
list_add_tail(&qmi_cfg->qmi_ev_list[i].list,
&qmi_cfg->event_list);
break;
}
}
if (i >= ATH10K_SNOC_DRIVER_EVENT_MAX)
i = ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE;
spin_unlock_bh(&qmi_cfg->event_lock);
queue_work(qmi_cfg->event_wq, &qmi_cfg->event_work);
if (!(flags & ATH10K_SNOC_EVENT_SYNC))
goto out;
if (flags & ATH10K_SNOC_EVENT_UNINTERRUPTIBLE)
wait_for_completion(&qmi_cfg->qmi_ev_list[i].complete);
else
ret = wait_for_completion_interruptible(
&qmi_cfg->qmi_ev_list[i].complete);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Completed event: %s(%d)\n",
ath10k_snoc_driver_event_to_str(type), type);
spin_lock_bh(&qmi_cfg->event_lock);
if (ret == -ERESTARTSYS &&
qmi_cfg->qmi_ev_list[i].ret == ATH10K_SNOC_EVENT_PENDING) {
qmi_cfg->qmi_ev_list[i].sync = false;
atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 1);
spin_unlock_bh(&qmi_cfg->event_lock);
ret = -EINTR;
goto out;
}
spin_unlock_bh(&qmi_cfg->event_lock);
out:
return ret;
}
static int ath10k_snoc_ind_register_send_sync_msg(struct ath10k *ar)
{
int ret;
struct wlfw_ind_register_req_msg_v01 req;
struct wlfw_ind_register_resp_msg_v01 resp;
struct msg_desc req_desc, resp_desc;
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
ath10k_dbg(ar, ATH10K_DBG_SNOC,
"Sending indication register message,\n");
memset(&req, 0, sizeof(req));
memset(&resp, 0, sizeof(resp));
req.client_id_valid = 1;
req.client_id = WLFW_CLIENT_ID;
req.fw_ready_enable_valid = 1;
req.fw_ready_enable = 1;
req.msa_ready_enable_valid = 1;
req.msa_ready_enable = 1;
req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN;
req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01;
req_desc.ei_array = wlfw_ind_register_req_msg_v01_ei;
resp_desc.max_msg_len = WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN;
resp_desc.msg_id = QMI_WLFW_IND_REGISTER_RESP_V01;
resp_desc.ei_array = wlfw_ind_register_resp_msg_v01_ei;
ret = qmi_send_req_wait(qmi_cfg->wlfw_clnt,
&req_desc, &req, sizeof(req),
&resp_desc, &resp, sizeof(resp),
WLFW_TIMEOUT_MS);
if (ret < 0) {
ath10k_err(ar, "Send indication register req failed %d\n", ret);
return ret;
}
if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
ath10k_err(ar, "QMI indication register request rejected:");
ath10k_err(ar, "resut:%d error:%d\n",
resp.resp.result, resp.resp.error);
ret = resp.resp.result;
return ret;
}
return 0;
}
static void ath10k_snoc_qmi_wlfw_clnt_notify_work(struct work_struct *work)
{
int ret;
struct ath10k_snoc_qmi_config *qmi_cfg =
container_of(work, struct ath10k_snoc_qmi_config,
qmi_recv_msg_work);
struct ath10k_snoc *ar_snoc =
container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
struct ath10k *ar = ar_snoc->ar;
ath10k_dbg(ar, ATH10K_DBG_SNOC,
"Receiving Event in work queue context\n");
do {
} while ((ret = qmi_recv_msg(qmi_cfg->wlfw_clnt)) == 0);
if (ret != -ENOMSG)
ath10k_err(ar, "Error receiving message: %d\n", ret);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Receiving Event completed\n");
}
static void
ath10k_snoc_qmi_wlfw_clnt_notify(struct qmi_handle *handle,
enum qmi_event_type event,
void *notify_priv)
{
struct ath10k_snoc_qmi_config *qmi_cfg =
(struct ath10k_snoc_qmi_config *)notify_priv;
struct ath10k_snoc *ar_snoc =
container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
struct ath10k *ar = ar_snoc->ar;
ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI client notify: %d\n", event);
if (!qmi_cfg || !qmi_cfg->wlfw_clnt)
return;
switch (event) {
case QMI_RECV_MSG:
schedule_work(&qmi_cfg->qmi_recv_msg_work);
break;
default:
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Unknown Event: %d\n", event);
break;
}
}
static void
ath10k_snoc_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
unsigned int msg_len, void *ind_cb_priv)
{
struct ath10k_snoc_qmi_config *qmi_cfg =
(struct ath10k_snoc_qmi_config *)ind_cb_priv;
struct ath10k_snoc *ar_snoc =
container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
struct ath10k *ar = ar_snoc->ar;
ath10k_dbg(ar, ATH10K_DBG_SNOC,
"Received Ind 0x%x, msg_len: %d\n", msg_id, msg_len);
switch (msg_id) {
case QMI_WLFW_FW_READY_IND_V01:
ath10k_snoc_driver_event_post(
ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND, 0, ar);
break;
case QMI_WLFW_MSA_READY_IND_V01:
qmi_cfg->msa_ready = true;
ath10k_dbg(ar, ATH10K_DBG_SNOC,
"Received MSA Ready, ind = 0x%x\n", msg_id);
break;
default:
ath10k_err(ar, "Invalid msg_id 0x%x\n", msg_id);
break;
}
}
static int ath10k_snoc_driver_event_server_arrive(struct ath10k *ar)
{
int ret = 0;
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
if (!qmi_cfg)
return -ENODEV;
qmi_cfg->wlfw_clnt = qmi_handle_create(
ath10k_snoc_qmi_wlfw_clnt_notify, qmi_cfg);
if (!qmi_cfg->wlfw_clnt) {
ath10k_dbg(ar, ATH10K_DBG_SNOC,
"QMI client handle create failed\n");
return -ENOMEM;
}
ret = qmi_connect_to_service(qmi_cfg->wlfw_clnt,
WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01,
WLFW_SERVICE_INS_ID_V01);
if (ret < 0) {
ath10k_err(ar, "QMI WLAN Service not found : %d\n", ret);
goto err_qmi_config;
}
ret = qmi_register_ind_cb(qmi_cfg->wlfw_clnt,
ath10k_snoc_qmi_wlfw_clnt_ind, qmi_cfg);
if (ret < 0) {
ath10k_err(ar, "Failed to register indication callback: %d\n",
ret);
goto err_qmi_config;
}
ret = ath10k_snoc_ind_register_send_sync_msg(ar);
if (ret) {
ath10k_err(ar, "Failed to config qmi ind register\n");
goto err_qmi_config;
}
ath10k_dbg(ar, ATH10K_DBG_SNOC,
"QMI Server Arrive Configuration Success\n");
return 0;
err_qmi_config:
qmi_handle_destroy(qmi_cfg->wlfw_clnt);
qmi_cfg->wlfw_clnt = NULL;
return ret;
}
static int ath10k_snoc_driver_event_server_exit(struct ath10k *ar)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI Server Exit event received\n");
ar_snoc->qmi_cfg.fw_ready = false;
ar_snoc->qmi_cfg.msa_ready = false;
return 0;
}
static int ath10k_snoc_driver_event_fw_ready_ind(struct ath10k *ar)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "FW Ready event received.\n");
ar_snoc->qmi_cfg.fw_ready = true;
wake_up_all(&ath10k_fw_ready_wait_event);
return 0;
}
static void ath10k_snoc_driver_event_work(struct work_struct *work)
{
struct ath10k_snoc_qmi_driver_event *event;
int ret;
struct ath10k_snoc_qmi_config *qmi_cfg =
container_of(work, struct ath10k_snoc_qmi_config, event_work);
struct ath10k_snoc *ar_snoc =
container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
struct ath10k *ar = ar_snoc->ar;
spin_lock_bh(&qmi_cfg->event_lock);
while (!list_empty(&qmi_cfg->event_list)) {
event = list_first_entry(&qmi_cfg->event_list,
struct ath10k_snoc_qmi_driver_event,
list);
list_del(&event->list);
spin_unlock_bh(&qmi_cfg->event_lock);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Processing event: %s%s(%d)\n",
ath10k_snoc_driver_event_to_str(event->type),
event->sync ? "-sync" : "", event->type);
switch (event->type) {
case ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE:
ret = ath10k_snoc_driver_event_server_arrive(ar);
break;
case ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT:
ret = ath10k_snoc_driver_event_server_exit(ar);
break;
case ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND:
ret = ath10k_snoc_driver_event_fw_ready_ind(ar);
break;
default:
ath10k_err(ar, "Invalid Event type: %d", event->type);
kfree(event);
continue;
}
atomic_set(&event->event_handled, 1);
ath10k_dbg(ar, ATH10K_DBG_SNOC,
"Event Processed: %s%s(%d), ret: %d\n",
ath10k_snoc_driver_event_to_str(event->type),
event->sync ? "-sync" : "", event->type, ret);
spin_lock_bh(&qmi_cfg->event_lock);
if (event->sync) {
event->ret = ret;
complete(&event->complete);
continue;
}
spin_unlock_bh(&qmi_cfg->event_lock);
spin_lock_bh(&qmi_cfg->event_lock);
}
spin_unlock_bh(&qmi_cfg->event_lock);
}
static int
ath10k_snoc_qmi_wlfw_clnt_svc_event_notify(struct notifier_block *this,
unsigned long code,
void *_cmd)
{
int ret = 0;
struct ath10k_snoc_qmi_config *qmi_cfg =
container_of(this, struct ath10k_snoc_qmi_config, wlfw_clnt_nb);
struct ath10k_snoc *ar_snoc =
container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
struct ath10k *ar = ar_snoc->ar;
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Event Notify: code: %ld", code);
switch (code) {
case QMI_SERVER_ARRIVE:
ret = ath10k_snoc_driver_event_post(
ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE, 0, ar);
break;
case QMI_SERVER_EXIT:
ret = ath10k_snoc_driver_event_post(
ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT, 0, ar);
break;
default:
ath10k_err(ar, "Invalid code: %ld", code);
break;
}
return ret;
}
int ath10k_snoc_start_qmi_service(struct ath10k *ar)
{
int ret;
int i;
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
qmi_cfg->event_wq = alloc_workqueue("ath10k_snoc_driver_event",
WQ_UNBOUND, 1);
if (!qmi_cfg->event_wq) {
ath10k_err(ar, "Workqueue creation failed\n");
return -EFAULT;
}
spin_lock_init(&qmi_cfg->event_lock);
qmi_cfg->fw_ready = false;
INIT_WORK(&qmi_cfg->event_work, ath10k_snoc_driver_event_work);
INIT_WORK(&qmi_cfg->qmi_recv_msg_work,
ath10k_snoc_qmi_wlfw_clnt_notify_work);
INIT_LIST_HEAD(&qmi_cfg->event_list);
for (i = 0; i < ATH10K_SNOC_DRIVER_EVENT_MAX; i++)
atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 1);
qmi_cfg->wlfw_clnt_nb.notifier_call =
ath10k_snoc_qmi_wlfw_clnt_svc_event_notify;
ret = qmi_svc_event_notifier_register(WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01,
WLFW_SERVICE_INS_ID_V01,
&qmi_cfg->wlfw_clnt_nb);
if (ret < 0) {
ath10k_err(ar, "Notifier register failed: %d\n", ret);
ret = -EFAULT;
goto out_destroy_wq;
}
ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI service started successfully\n");
return 0;
out_destroy_wq:
destroy_workqueue(qmi_cfg->event_wq);
return ret;
}
void ath10k_snoc_stop_qmi_service(struct ath10k *ar)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Removing QMI service..\n");
qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01,
WLFW_SERVICE_VERS_V01,
WLFW_SERVICE_INS_ID_V01,
&qmi_cfg->wlfw_clnt_nb);
wake_up_all(&ath10k_fw_ready_wait_event);
destroy_workqueue(qmi_cfg->event_wq);
qmi_cfg = NULL;
}

View file

@ -11,9 +11,139 @@
*/ */
#ifndef _QMI_H_ #ifndef _QMI_H_
#define _QMI_H_ #define _QMI_H_
#define ATH10K_SNOC_EVENT_PENDING 2989
#define ATH10K_SNOC_EVENT_SYNC BIT(0)
#define ATH10K_SNOC_EVENT_UNINTERRUPTIBLE BIT(1)
#define ATH10K_SNOC_WLAN_FW_READY_TIMEOUT 6000
#define WLFW_SERVICE_INS_ID_V01 0
#define WLFW_CLIENT_ID 0x4b4e454c
#define WLFW_TIMEOUT_MS 20000
enum ath10k_snoc_driver_event_type {
ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE,
ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT,
ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND,
ATH10K_SNOC_DRIVER_EVENT_MAX,
};
/* enum ath10k_driver_mode: ath10k driver mode
* @ATH10K_MISSION: mission mode
* @ATH10K_FTM: ftm mode
* @ATH10K_EPPING: epping mode
* @ATH10K_OFF: off mode
*/
enum ath10k_driver_mode {
ATH10K_MISSION,
ATH10K_FTM,
ATH10K_EPPING,
ATH10K_OFF
};
/* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration
* @pipe_num: pipe number
* @pipe_dir: pipe direction
* @nentries: entries in pipe
* @nbytes_max: pipe max size
* @flags: pipe flags
* @reserved: reserved
*/
struct ath10k_ce_tgt_pipe_cfg {
u32 pipe_num;
u32 pipe_dir;
u32 nentries;
u32 nbytes_max;
u32 flags;
u32 reserved;
};
/* struct ath10k_ce_svc_pipe_cfg: service pipe configuration
* @service_id: target version
* @pipe_dir: pipe direction
* @pipe_num: pipe number
*/
struct ath10k_ce_svc_pipe_cfg {
u32 service_id;
u32 pipe_dir;
u32 pipe_num;
};
/* struct ath10k_shadow_reg_cfg: shadow register configuration
* @ce_id: copy engine id
* @reg_offset: offset to copy engine
*/
struct ath10k_shadow_reg_cfg {
u16 ce_id;
u16 reg_offset;
};
/* struct ath10k_wlan_enable_cfg: wlan enable configuration
* @num_ce_tgt_cfg: no of ce target configuration
* @ce_tgt_cfg: target ce configuration
* @num_ce_svc_pipe_cfg: no of ce service configuration
* @ce_svc_cfg: ce service configuration
* @num_shadow_reg_cfg: no of shadow registers
* @shadow_reg_cfg: shadow register configuration
*/
struct ath10k_wlan_enable_cfg {
u32 num_ce_tgt_cfg;
struct ath10k_ce_tgt_pipe_cfg *ce_tgt_cfg;
u32 num_ce_svc_pipe_cfg;
struct ath10k_ce_svc_pipe_cfg *ce_svc_cfg;
u32 num_shadow_reg_cfg;
struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
};
/* struct ath10k_snoc_qmi_driver_event: qmi driver event
* event_handled: event handled by event work handler
* sync: event synced
* ret: event received return value
* list: list to queue qmi event for process
* type: driver event type
* complete: completion for event handle complete
* data: encapsulate driver data for event handler callback
*/
struct ath10k_snoc_qmi_driver_event {
atomic_t event_handled;
bool sync;
int ret;
struct list_head list;
enum ath10k_snoc_driver_event_type type;
struct completion complete;
void *data;
};
/* struct ath10k_snoc_qmi_config: qmi service configuration
* fw_ready: wlan firmware ready for wlan operation
* msa_ready: wlan firmware msa memory ready for board data download
* event_work: QMI event work
* event_list: QMI event list
* qmi_recv_msg_work: QMI message receive work
* event_wq: QMI event work queue
* wlfw_clnt_nb: WLAN firmware indication callback
* wlfw_clnt: QMI notifier handler for wlan firmware
* qmi_ev_list: QMI event list
* event_lock: spinlock for qmi event work queue
*/
struct ath10k_snoc_qmi_config {
bool fw_ready;
bool msa_ready;
struct work_struct event_work;
struct list_head event_list;
struct work_struct qmi_recv_msg_work;
struct workqueue_struct *event_wq;
struct notifier_block wlfw_clnt_nb;
struct qmi_handle *wlfw_clnt;
struct ath10k_snoc_qmi_driver_event
qmi_ev_list[ATH10K_SNOC_DRIVER_EVENT_MAX];
spinlock_t event_lock; /* spinlock for qmi event work queue */
};
int ath10k_snoc_pd_restart_enable(struct ath10k *ar); int ath10k_snoc_pd_restart_enable(struct ath10k *ar);
int ath10k_snoc_modem_ssr_register_notifier(struct ath10k *ar); int ath10k_snoc_modem_ssr_register_notifier(struct ath10k *ar);
int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar); int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar);
int ath10k_snoc_pdr_unregister_notifier(struct ath10k *ar); int ath10k_snoc_pdr_unregister_notifier(struct ath10k *ar);
int ath10k_snoc_start_qmi_service(struct ath10k *ar);
void ath10k_snoc_stop_qmi_service(struct ath10k *ar);
#endif #endif

View file

@ -1245,6 +1245,12 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ar); platform_set_drvdata(pdev, ar);
ar_snoc->ar = ar; ar_snoc->ar = ar;
ret = ath10k_snoc_start_qmi_service(ar);
if (ret) {
ath10k_err(ar, "failed to start QMI service: %d\n", ret);
goto err_core_destroy;
}
spin_lock_init(&ar_snoc->opaque_ctx.ce_lock); spin_lock_init(&ar_snoc->opaque_ctx.ce_lock);
ar_snoc->opaque_ctx.bus_ops = &ath10k_snoc_bus_ops; ar_snoc->opaque_ctx.bus_ops = &ath10k_snoc_bus_ops;
ath10k_snoc_resource_init(ar); ath10k_snoc_resource_init(ar);
@ -1325,6 +1331,7 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
ath10k_snoc_free_irq(ar); ath10k_snoc_free_irq(ar);
ath10k_snoc_release_resource(ar); ath10k_snoc_release_resource(ar);
ath10k_snoc_free_pipes(ar); ath10k_snoc_free_pipes(ar);
ath10k_snoc_stop_qmi_service(ar);
ath10k_core_destroy(ar); ath10k_core_destroy(ar);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__); ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__);

View file

@ -16,6 +16,7 @@
#include "hw.h" #include "hw.h"
#include "ce.h" #include "ce.h"
#include "pci.h" #include "pci.h"
#include "qmi.h"
#include <soc/qcom/service-locator.h> #include <soc/qcom/service-locator.h>
#define ATH10K_SNOC_RX_POST_RETRY_MS 50 #define ATH10K_SNOC_RX_POST_RETRY_MS 50
#define CE_POLL_PIPE 4 #define CE_POLL_PIPE 4
@ -143,60 +144,7 @@ struct ath10k_snoc {
int total_domains; int total_domains;
struct notifier_block get_service_nb; struct notifier_block get_service_nb;
atomic_t fw_crashed; atomic_t fw_crashed;
}; struct ath10k_snoc_qmi_config qmi_cfg;
/* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration
* @pipe_num: pipe number
* @pipe_dir: pipe direction
* @nentries: entries in pipe
* @nbytes_max: pipe max size
* @flags: pipe flags
* @reserved: reserved
*/
struct ath10k_ce_tgt_pipe_cfg {
u32 pipe_num;
u32 pipe_dir;
u32 nentries;
u32 nbytes_max;
u32 flags;
u32 reserved;
};
/* struct ath10k_ce_svc_pipe_cfg: service pipe configuration
* @service_id: target version
* @pipe_dir: pipe direction
* @pipe_num: pipe number
*/
struct ath10k_ce_svc_pipe_cfg {
u32 service_id;
u32 pipe_dir;
u32 pipe_num;
};
/* struct ath10k_shadow_reg_cfg: shadow register configuration
* @ce_id: copy engine id
* @reg_offset: offset to copy engine
*/
struct ath10k_shadow_reg_cfg {
u16 ce_id;
u16 reg_offset;
};
/* struct ath10k_wlan_enable_cfg: wlan enable configuration
* @num_ce_tgt_cfg: no of ce target configuration
* @ce_tgt_cfg: target ce configuration
* @num_ce_svc_pipe_cfg: no of ce service configuration
* @ce_svc_cfg: ce service configuration
* @num_shadow_reg_cfg: no of shadow registers
* @shadow_reg_cfg: shadow register configuration
*/
struct ath10k_wlan_enable_cfg {
u32 num_ce_tgt_cfg;
struct ath10k_ce_tgt_pipe_cfg *ce_tgt_cfg;
u32 num_ce_svc_pipe_cfg;
struct ath10k_ce_svc_pipe_cfg *ce_svc_cfg;
u32 num_shadow_reg_cfg;
struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
}; };
struct ath10k_event_pd_down_data { struct ath10k_event_pd_down_data {
@ -204,19 +152,6 @@ struct ath10k_event_pd_down_data {
bool fw_rejuvenate; bool fw_rejuvenate;
}; };
/* enum ath10k_driver_mode: ath10k driver mode
* @ATH10K_MISSION: mission mode
* @ATH10K_FTM: ftm mode
* @ATH10K_EPPING: epping mode
* @ATH10K_OFF: off mode
*/
enum ath10k_driver_mode {
ATH10K_MISSION,
ATH10K_FTM,
ATH10K_EPPING,
ATH10K_OFF
};
static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
{ {
return (struct ath10k_snoc *)ar->drv_priv; return (struct ath10k_snoc *)ar->drv_priv;