Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7048b1a8 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: dfc: Improve QMI message handling"

parents fa5d4746 ca5592a4
Loading
Loading
Loading
Loading
+86 −51
Original line number Diff line number Diff line
@@ -58,12 +58,15 @@ struct dfc_qmi_data {
	struct work_struct svc_arrive;
	struct qmi_handle handle;
	struct sockaddr_qrtr ssctl;
	struct svc_info svc;
	struct work_struct qmi_ind_work;
	struct list_head qmi_ind_q;
	spinlock_t qmi_ind_lock;
	int index;
	int restart_state;
};

static void dfc_svc_init(struct work_struct *work);
static void dfc_do_burst_flow_control(struct work_struct *work);

/* **************************************************** */
#define DFC_SERVICE_ID_V01 0x4E
@@ -307,8 +310,7 @@ struct dfc_flow_status_ind_msg_v01 {
};

struct dfc_svc_ind {
	struct work_struct work;
	struct dfc_qmi_data *data;
	struct list_head list;
	struct dfc_flow_status_ind_msg_v01 dfc_info;
};

@@ -618,12 +620,11 @@ dfc_indication_register_req(struct qmi_handle *dfc_handle,
	return ret;
}

static int dfc_init_service(struct dfc_qmi_data *data, struct qmi_info *qmi)
static int dfc_init_service(struct dfc_qmi_data *data)
{
	int rc;

	rc = dfc_bind_client_req(&data->handle, &data->ssctl,
				 &qmi->fc_info[data->index].svc);
	rc = dfc_bind_client_req(&data->handle, &data->ssctl, &data->svc);
	if (rc < 0)
		return rc;

@@ -674,16 +675,13 @@ static int dfc_bearer_flow_ctl(struct net_device *dev,
			       struct rmnet_bearer_map *bearer,
			       struct qos_info *qos)
{
	struct list_head *p;
	struct rmnet_flow_map *itm;
	int rc = 0, qlen;
	int enable;

	enable = bearer->grant_size ? 1 : 0;

	list_for_each(p, &qos->flow_head) {
		itm = list_entry(p, struct rmnet_flow_map, list);

	list_for_each_entry(itm, &qos->flow_head, list) {
		if (itm->bearer_id == bearer->bearer_id) {
			/*
			 * Do not flow disable ancillary q if ancillary is true
@@ -713,14 +711,14 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev,
				struct qos_info *qos, u8 ack_req, u32 ancillary,
				struct dfc_flow_status_info_type_v01 *fc_info)
{
	struct list_head *p;
	struct rmnet_bearer_map *bearer_itm = NULL;
	int enable;
	int rc = 0;
	struct rmnet_bearer_map *bearer_itm;
	struct rmnet_flow_map *flow_itm;
	int rc = 0, qlen;
	bool enable;

	list_for_each(p, &qos->bearer_head) {
		bearer_itm = list_entry(p, struct rmnet_bearer_map, list);
	enable = fc_info->num_bytes > 0 ? 1 : 0;

	list_for_each_entry(bearer_itm, &qos->bearer_head, list) {
		bearer_itm->grant_size = fc_info->num_bytes;
		bearer_itm->grant_thresh =
			qmi_rmnet_grant_per(bearer_itm->grant_size);
@@ -729,14 +727,14 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev,
		bearer_itm->ancillary = ancillary;
	}

	enable = fc_info->num_bytes > 0 ? 1 : 0;

	if (enable)
		netif_tx_wake_all_queues(dev);
	else
		netif_tx_stop_all_queues(dev);

	trace_dfc_qmi_tc(dev->name, 0xFF, 0, fc_info->num_bytes, 0, 0, enable);
	list_for_each_entry(flow_itm, &qos->flow_head, list) {
		qlen = qmi_rmnet_flow_control(dev, flow_itm->tcm_handle,
					      enable);
		trace_dfc_qmi_tc(dev->name, flow_itm->bearer_id,
				 flow_itm->flow_id, fc_info->num_bytes,
				 qlen, flow_itm->tcm_handle, enable);
		rc++;
	}

	if (enable == 0 && ack_req)
		dfc_send_ack(dev, fc_info->bearer_id,
@@ -776,9 +774,9 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos,
	return rc;
}

static void dfc_do_burst_flow_control(struct work_struct *work)
static void dfc_do_burst_flow_control(struct dfc_qmi_data *dfc,
				      struct dfc_svc_ind *svc_ind)
{
	struct dfc_svc_ind *svc_ind = (struct dfc_svc_ind *)work;
	struct dfc_flow_status_ind_msg_v01 *ind = &svc_ind->dfc_info;
	struct net_device *dev;
	struct qos_info *qos;
@@ -788,11 +786,6 @@ static void dfc_do_burst_flow_control(struct work_struct *work)
	u32 ancillary;
	int i, j;

	if (unlikely(svc_ind->data->restart_state)) {
		kfree(svc_ind);
		return;
	}

	rcu_read_lock();

	for (i = 0; i < ind->flow_status_len; i++) {
@@ -810,7 +803,7 @@ static void dfc_do_burst_flow_control(struct work_struct *work)
			}
		}

		trace_dfc_flow_ind(svc_ind->data->index,
		trace_dfc_flow_ind(dfc->index,
				   i, flow_status->mux_id,
				   flow_status->bearer_id,
				   flow_status->num_bytes,
@@ -818,7 +811,7 @@ static void dfc_do_burst_flow_control(struct work_struct *work)
				   ack_req,
				   ancillary);

		dev = rmnet_get_rmnet_dev(svc_ind->data->rmnet_port,
		dev = rmnet_get_rmnet_dev(dfc->rmnet_port,
					  flow_status->mux_id);
		if (!dev)
			goto clean_out;
@@ -841,8 +834,37 @@ static void dfc_do_burst_flow_control(struct work_struct *work)

clean_out:
	rcu_read_unlock();
}

static void dfc_qmi_ind_work(struct work_struct *work)
{
	struct dfc_qmi_data *dfc = container_of(work, struct dfc_qmi_data,
						qmi_ind_work);
	struct dfc_svc_ind *svc_ind;
	unsigned long flags;

	if (!dfc)
		return;

	local_bh_disable();

	do {
		spin_lock_irqsave(&dfc->qmi_ind_lock, flags);
		svc_ind = list_first_entry_or_null(&dfc->qmi_ind_q,
						   struct dfc_svc_ind, list);
		if (svc_ind)
			list_del(&svc_ind->list);
		spin_unlock_irqrestore(&dfc->qmi_ind_lock, flags);

		if (svc_ind) {
			if (!dfc->restart_state)
				dfc_do_burst_flow_control(dfc, svc_ind);
			kfree(svc_ind);
		}
	} while (svc_ind != NULL);

	local_bh_enable();
}

static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
			    struct qmi_txn *txn, const void *data)
@@ -851,6 +873,7 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
						handle);
	struct dfc_flow_status_ind_msg_v01 *ind_msg;
	struct dfc_svc_ind *svc_ind;
	unsigned long flags;

	if (qmi != &dfc->handle)
		return;
@@ -867,13 +890,13 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
		if (!svc_ind)
			return;

		INIT_WORK((struct work_struct *)svc_ind,
			  dfc_do_burst_flow_control);

		memcpy(&svc_ind->dfc_info, ind_msg, sizeof(*ind_msg));
		svc_ind->data = dfc;

		queue_work(dfc->dfc_wq, (struct work_struct *)svc_ind);
		spin_lock_irqsave(&dfc->qmi_ind_lock, flags);
		list_add_tail(&svc_ind->list, &dfc->qmi_ind_q);
		spin_unlock_irqrestore(&dfc->qmi_ind_lock, flags);

		queue_work(dfc->dfc_wq, &dfc->qmi_ind_work);
	}
}

@@ -884,19 +907,26 @@ static void dfc_svc_init(struct work_struct *work)
						 svc_arrive);
	struct qmi_info *qmi;

	qmi = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port);
	if (!qmi)
		goto clean_out;

	rc = dfc_init_service(data, qmi);
	rc = dfc_init_service(data);
	if (rc < 0)
		goto clean_out;

	qmi->fc_info[data->index].dfc_client = (void *)data;
	trace_dfc_client_state_up(data->index,
				  qmi->fc_info[data->index].svc.instance,
				  qmi->fc_info[data->index].svc.ep_type,
				  qmi->fc_info[data->index].svc.iface_id);
			   data->svc.instance,
			   data->svc.ep_type,
			   data->svc.iface_id);

	rtnl_lock();
	qmi = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port);
	if (!qmi) {
		rtnl_unlock();
		goto clean_out;
	}

	qmi->dfc_clients[data->index] = (void *)data;
	rtnl_unlock();

	pr_info("Connection established with the DFC Service\n");
	return;

clean_out:
@@ -944,7 +974,7 @@ static struct qmi_msg_handler qmi_indication_handler[] = {
	{},
};

int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi)
int dfc_qmi_client_init(void *port, int index, struct svc_info *psvc)
{
	struct dfc_qmi_data *data;
	int rc = -ENOMEM;
@@ -956,6 +986,11 @@ int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi)
	data->rmnet_port = port;
	data->index = index;
	data->restart_state = 0;
	memcpy(&data->svc, psvc, sizeof(data->svc));

	INIT_WORK(&data->qmi_ind_work, dfc_qmi_ind_work);
	INIT_LIST_HEAD(&data->qmi_ind_q);
	spin_lock_init(&data->qmi_ind_lock);

	data->dfc_wq = create_singlethread_workqueue("dfc_wq");
	if (!data->dfc_wq) {
@@ -974,7 +1009,7 @@ int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi)

	rc = qmi_add_lookup(&data->handle, DFC_SERVICE_ID_V01,
			    DFC_SERVICE_VERS_V01,
			    qmi->fc_info[index].svc.instance);
			    psvc->instance);
	if (rc < 0) {
		pr_err("%s: failed qmi_add_lookup - rc[%d]\n", __func__, rc);
		goto err2;
@@ -1058,7 +1093,7 @@ void dfc_qmi_wq_flush(struct qmi_info *qmi)
	int i;

	for (i = 0; i < MAX_CLIENT_NUM; i++) {
		dfc_data = (struct dfc_qmi_data *)(qmi->fc_info[i].dfc_client);
		dfc_data = (struct dfc_qmi_data *)(qmi->dfc_clients[i]);
		if (dfc_data)
			flush_workqueue(dfc_data->dfc_wq);
	}
+13 −13
Original line number Diff line number Diff line
@@ -87,8 +87,8 @@ void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi)
		return NULL;

	for (i = 0; i < MAX_CLIENT_NUM; i++) {
		if (qmi->fc_info[i].dfc_client)
			return qmi->fc_info[i].dfc_client;
		if (qmi->dfc_clients[i])
			return qmi->dfc_clients[i];
	}

	return NULL;
@@ -365,6 +365,7 @@ static int
qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm)
{
	int idx, rc, err = 0;
	struct svc_info svc;

	ASSERT_RTNL();

@@ -375,7 +376,7 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm)
	idx = (tcm->tcm_handle == 0) ? 0 : 1;

	if (!qmi) {
		qmi = kzalloc(sizeof(struct qmi_info), GFP_KERNEL);
		qmi = kzalloc(sizeof(struct qmi_info), GFP_ATOMIC);
		if (!qmi)
			return -ENOMEM;

@@ -383,20 +384,20 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm)
	}

	qmi->flag = tcm->tcm_ifindex;
	qmi->fc_info[idx].svc.instance = tcm->tcm_handle;
	qmi->fc_info[idx].svc.ep_type = tcm->tcm_info;
	qmi->fc_info[idx].svc.iface_id = tcm->tcm_parent;
	svc.instance = tcm->tcm_handle;
	svc.ep_type = tcm->tcm_info;
	svc.iface_id = tcm->tcm_parent;

	if (((tcm->tcm_ifindex & FLAG_DFC_MASK) == DFC_MODE_MULTIQ) &&
	    (qmi->fc_info[idx].dfc_client == NULL)) {
		rc = dfc_qmi_client_init(port, idx, qmi);
	    (qmi->dfc_clients[idx] == NULL)) {
		rc = dfc_qmi_client_init(port, idx, &svc);
		if (rc < 0)
			err = rc;
	}

	if ((tcm->tcm_ifindex & FLAG_POWERSAVE_MASK) &&
	    (idx == 0) && (qmi->wda_client == NULL)) {
		rc = wda_qmi_client_init(port, tcm->tcm_handle);
		rc = wda_qmi_client_init(port, &svc);
		if (rc < 0)
			err = rc;
	}
@@ -407,12 +408,11 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm)
static int
__qmi_rmnet_delete_client(void *port, struct qmi_info *qmi, int idx)
{

	ASSERT_RTNL();

	if (qmi->fc_info[idx].dfc_client) {
		dfc_qmi_client_exit(qmi->fc_info[idx].dfc_client);
		qmi->fc_info[idx].dfc_client = NULL;
	if (qmi->dfc_clients[idx]) {
		dfc_qmi_client_exit(qmi->dfc_clients[idx]);
		qmi->dfc_clients[idx] = NULL;
	}

	if (!qmi_rmnet_has_client(qmi)) {
+8 −13
Original line number Diff line number Diff line
@@ -51,11 +51,6 @@ struct svc_info {
	u32 iface_id;
};

struct fc_info {
	struct svc_info svc;
	void *dfc_client;
};

struct qos_info {
	u8 mux_id;
	struct net_device *real_dev;
@@ -74,7 +69,7 @@ struct flow_info {
struct qmi_info {
	int flag;
	void *wda_client;
	struct fc_info fc_info[MAX_CLIENT_NUM];
	void *dfc_clients[MAX_CLIENT_NUM];
	unsigned long ps_work_active;
	int ps_enabled;
};
@@ -109,7 +104,7 @@ qmi_rmnet_get_bearer_map(struct qos_info *qos_info, u8 bearer_id);

unsigned int qmi_rmnet_grant_per(unsigned int grant);

int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi);
int dfc_qmi_client_init(void *port, int index, struct svc_info *psvc);

void dfc_qmi_client_exit(void *dfc_data);

@@ -129,13 +124,13 @@ qmi_rmnet_get_flow_map(struct qos_info *qos_info,
}

static inline struct rmnet_bearer_map *
qmi_rmnet_get_bearer_map(struct qos_info *qos_info, uint8_t bearer_id)
qmi_rmnet_get_bearer_map(struct qos_info *qos_info, u8 bearer_id)
{
	return NULL;
}

static inline int
dfc_qmi_client_init(void *port, int modem, struct qmi_info *qmi)
dfc_qmi_client_init(void *port, int index, struct svc_info *psvc)
{
	return -EINVAL;
}
@@ -157,11 +152,11 @@ dfc_qmi_wq_flush(struct qmi_info *qmi)
#endif

#ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE
int wda_qmi_client_init(void *port, uint32_t instance);
int wda_qmi_client_init(void *port, struct svc_info *psvc);
void wda_qmi_client_exit(void *wda_data);
int wda_set_powersave_mode(void *wda_data, uint8_t enable);
int wda_set_powersave_mode(void *wda_data, u8 enable);
#else
static inline int wda_qmi_client_init(void *port, uint32_t instance)
static inline int wda_qmi_client_init(void *port, struct svc_info *psvc)
{
	return -EINVAL;
}
@@ -170,7 +165,7 @@ static inline void wda_qmi_client_exit(void *wda_data)
{
}

static inline int wda_set_powersave_mode(void *wda_data, uint8_t enable)
static inline int wda_set_powersave_mode(void *wda_data, u8 enable)
{
	return -EINVAL;
}
+21 −14
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 *
 */

#include <linux/rtnetlink.h>
#include <linux/soc/qcom/qmi.h>
#include <soc/qcom/rmnet_qmi.h>
#define CREATE_TRACE_POINTS
@@ -23,6 +24,7 @@ struct wda_qmi_data {
	struct work_struct svc_arrive;
	struct qmi_handle handle;
	struct sockaddr_qrtr ssctl;
	struct svc_info svc;
};

static void wda_svc_config(struct work_struct *work);
@@ -255,8 +257,7 @@ static int wda_set_powersave_mode_req(void *wda_data, uint8_t enable)
	return ret;
}

static int wda_set_powersave_config_req(struct qmi_handle *wda_handle,
					struct qmi_info *qmi)
static int wda_set_powersave_config_req(struct qmi_handle *wda_handle)
{
	struct wda_qmi_data *data = container_of(wda_handle,
						 struct wda_qmi_data, handle);
@@ -283,8 +284,8 @@ static int wda_set_powersave_config_req(struct qmi_handle *wda_handle,
		goto out;
	}

	req->ep_id.ep_type = qmi->fc_info[0].svc.ep_type;
	req->ep_id.iface_id = qmi->fc_info[0].svc.iface_id;
	req->ep_id.ep_type = data->svc.ep_type;
	req->ep_id.iface_id = data->svc.iface_id;
	req->req_data_cfg_valid = 1;
	req->req_data_cfg = WDA_DATA_POWERSAVE_CONFIG_ALL_MASK_V01;
	ret = qmi_send_request(wda_handle, &data->ssctl, &txn,
@@ -319,20 +320,25 @@ static void wda_svc_config(struct work_struct *work)
						 svc_arrive);
	struct qmi_info *qmi;

	qmi = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port);
	if (!qmi)
		goto clean_out;

	if (wda_set_powersave_config_req(&data->handle, qmi) < 0) {
	if (wda_set_powersave_config_req(&data->handle) < 0) {
		pr_err("%s() failed, qmi handle pt: %p\n",
			__func__, &data->handle);
		goto clean_out;
	}

	trace_wda_client_state_up(qmi->fc_info[0].svc.instance,
				  qmi->fc_info[0].svc.ep_type,
				  qmi->fc_info[0].svc.iface_id);
	trace_wda_client_state_up(data->svc.instance,
				  data->svc.ep_type,
				  data->svc.iface_id);
	rtnl_lock();
	qmi = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port);
	if (!qmi) {
		rtnl_unlock();
		goto clean_out;
	}

	qmi->wda_client = (void *)data;
	rtnl_unlock();

	pr_info("Connection established with the WDA Service\n");
	return;

@@ -370,7 +376,7 @@ static struct qmi_ops server_ops = {
	.del_server = wda_svc_exit,
};

int wda_qmi_client_init(void *port, uint32_t instance)
int wda_qmi_client_init(void *port, struct svc_info *psvc)
{
	struct wda_qmi_data *data;
	int rc = 0;
@@ -392,6 +398,7 @@ int wda_qmi_client_init(void *port, uint32_t instance)
	}

	data->rmnet_port = port;
	memcpy(&data->svc, psvc, sizeof(data->svc));
	INIT_WORK(&data->svc_arrive, wda_svc_config);

	rc = qmi_handle_init(&data->handle,
@@ -404,7 +411,7 @@ int wda_qmi_client_init(void *port, uint32_t instance)
	}

	rc = qmi_add_lookup(&data->handle, WDA_SERVICE_ID_V01,
			    WDA_SERVICE_VERS_V01, instance);
			    WDA_SERVICE_VERS_V01, psvc->instance);
	if (rc < 0) {
		pr_err("%s(): Failed qmi_add_lookup, err: %d\n", __func__, rc);
		qmi_handle_release(&data->handle);