soc: qcom: service-notifier: Use per-indication structs for PDR

When an indication is received from a PD during PDR, the
transaction ID, and other information relevant to that
particular indication, are saved inside the QMI data
structure for that PD. As a consequence of there being
one indication structure for all indications, if
the PD sends back-to-back indications, then it is possible
for the information pertaining to the first indication to
be overwritten.

Thus, allocate an indication data structure for each indication
that arrives, to prevent the indication state from being
corrupted because of the reception of another indication from
the same PD.

Change-Id: I68830773a186123c7d840056931176892e458f04
Signed-off-by: Isaac J. Manjarres <isaacm@codeaurora.org>
This commit is contained in:
Isaac J. Manjarres
2019-03-11 11:48:13 -07:00
parent 749953698f
commit 1db0ea5f56

View File

@@ -73,9 +73,10 @@ static LIST_HEAD(service_list);
static DEFINE_MUTEX(service_list_lock);
struct ind_req_resp {
char service_path[SERVREG_NOTIF_NAME_LENGTH];
int transaction_id;
int curr_state;
struct work_struct ind_ack;
struct qmi_client_info *client_data;
};
/*
@@ -91,7 +92,6 @@ struct qmi_client_info {
int instance_id;
char service_path[SERVREG_NOTIF_NAME_LENGTH];
enum pd_subsys_state subsys_state;
struct work_struct ind_ack;
struct work_struct new_server;
struct work_struct del_server;
struct workqueue_struct *svc_event_wq;
@@ -102,7 +102,6 @@ struct qmi_client_info {
struct notifier_block ssr_notifier;
bool service_connected;
struct list_head list;
struct ind_req_resp ind_msg;
struct sockaddr_qrtr s_addr;
};
static LIST_HEAD(qmi_client_list);
@@ -140,8 +139,9 @@ static int service_notif_queue_notification(struct service_notif_info
static void send_ind_ack(struct work_struct *work)
{
struct qmi_client_info *data = container_of(work,
struct qmi_client_info, ind_ack);
struct ind_req_resp *ind_info = container_of(work, struct ind_req_resp,
ind_ack);
struct qmi_client_info *data = ind_info->client_data;
struct qmi_servreg_notif_set_ack_req_msg_v01 req;
struct qmi_servreg_notif_set_ack_resp_msg_v01 resp = { { 0, 0 } };
struct qmi_txn txn;
@@ -149,29 +149,29 @@ static void send_ind_ack(struct work_struct *work)
enum pd_subsys_state state = USER_PD_STATE_CHANGE;
int rc;
service_notif = _find_service_info(data->ind_msg.service_path);
service_notif = _find_service_info(data->service_path);
if (!service_notif)
return;
if ((int)data->ind_msg.curr_state < QMI_STATE_MIN_VAL ||
(int)data->ind_msg.curr_state > QMI_STATE_MAX_VAL)
goto out;
if ((int)ind_info->curr_state < QMI_STATE_MIN_VAL ||
(int)ind_info->curr_state > QMI_STATE_MAX_VAL)
pr_err("Unexpected indication notification state %d\n",
data->ind_msg.curr_state);
ind_info->curr_state);
else {
mutex_lock(&notif_add_lock);
mutex_lock(&service_list_lock);
rc = service_notif_queue_notification(service_notif,
data->ind_msg.curr_state, &state);
ind_info->curr_state, &state);
if (rc & NOTIFY_STOP_MASK)
pr_err("Notifier callback aborted for %s with error %d\n",
data->ind_msg.service_path, rc);
service_notif->curr_state = data->ind_msg.curr_state;
data->service_path, rc);
service_notif->curr_state = ind_info->curr_state;
mutex_unlock(&service_list_lock);
mutex_unlock(&notif_add_lock);
}
req.transaction_id = data->ind_msg.transaction_id;
req.transaction_id = ind_info->transaction_id;
snprintf(req.service_name, ARRAY_SIZE(req.service_name), "%s",
data->ind_msg.service_path);
data->service_path);
rc = qmi_txn_init(&data->clnt_handle, &txn,
qmi_servreg_notif_set_ack_resp_msg_v01_ei,
@@ -179,8 +179,8 @@ static void send_ind_ack(struct work_struct *work)
if (rc < 0) {
pr_err("%s QMI tx init failed , ret - %d\n",
data->ind_msg.service_path, rc);
return;
data->service_path, rc);
goto out;
}
rc = qmi_send_request(&data->clnt_handle, &data->s_addr,
@@ -190,24 +190,26 @@ static void send_ind_ack(struct work_struct *work)
&req);
if (rc < 0) {
pr_err("%s: QMI send ACK failed, ret - %d\n",
data->ind_msg.service_path, rc);
data->service_path, rc);
qmi_txn_cancel(&txn);
return;
goto out;
}
rc = qmi_txn_wait(&txn, msecs_to_jiffies(SERVER_TIMEOUT));
if (rc < 0) {
pr_err("%s: QMI qmi txn wait failed, ret - %d\n",
data->ind_msg.service_path, rc);
return;
data->service_path, rc);
goto out;
}
/* Check the response */
if (resp.resp.result != QMI_RESULT_SUCCESS_V01)
pr_err("QMI request failed 0x%x\n", resp.resp.error);
pr_info("Indication ACKed for transid %d, service %s, instance %d!\n",
data->ind_msg.transaction_id, data->ind_msg.service_path,
ind_info->transaction_id, data->service_path,
data->instance_id);
out:
kfree(ind_info);
}
static void root_service_service_ind_cb(struct qmi_handle *qmi,
@@ -218,17 +220,20 @@ static void root_service_service_ind_cb(struct qmi_handle *qmi,
struct qmi_client_info, clnt_handle);
struct qmi_servreg_notif_state_updated_ind_msg_v01 ind_msg =
*((struct qmi_servreg_notif_state_updated_ind_msg_v01 *)data);
struct ind_req_resp *ind_info = kmalloc(sizeof(*ind_info), GFP_KERNEL);
if (!ind_info)
return;
pr_info("Indication received from %s, state: 0x%x, trans-id: %d\n",
ind_msg.service_name, ind_msg.curr_state,
ind_msg.transaction_id);
qmi_data->ind_msg.transaction_id = ind_msg.transaction_id;
qmi_data->ind_msg.curr_state = ind_msg.curr_state;
snprintf(qmi_data->ind_msg.service_path,
ARRAY_SIZE(qmi_data->ind_msg.service_path), "%s",
ind_msg.service_name);
queue_work(qmi_data->ind_ack_wq, &qmi_data->ind_ack);
ind_info->transaction_id = ind_msg.transaction_id;
ind_info->curr_state = ind_msg.curr_state;
ind_info->client_data = qmi_data;
INIT_WORK(&ind_info->ind_ack, send_ind_ack);
queue_work(qmi_data->ind_ack_wq, &ind_info->ind_ack);
}
static int send_notif_listener_msg_req(struct service_notif_info *service_notif,
@@ -251,7 +256,7 @@ static int send_notif_listener_msg_req(struct service_notif_info *service_notif,
if (rc < 0) {
pr_err("%s QMI tx init failed , ret - %d\n",
data->ind_msg.service_path, rc);
service_notif->service_path, rc);
return rc;
}
@@ -513,7 +518,6 @@ static void *add_service_notif(const char *service_path, int instance_id,
goto exit;
}
INIT_WORK(&qmi_data->ind_ack, send_ind_ack);
INIT_WORK(&qmi_data->new_server, new_server_work);
INIT_WORK(&qmi_data->del_server, del_server_work);
@@ -586,8 +590,7 @@ static int send_pd_restart_req(const char *service_path,
&resp);
if (rc < 0) {
pr_err("%s QMI tx init failed , ret - %d\n",
data->ind_msg.service_path, rc);
pr_err("%s QMI tx init failed , ret - %d\n", service_path, rc);
return rc;
}