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

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

Merge "net: rmnet: Add trace subsystem"

parents ae0db13b 033cba8a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@
#include "rmnet_vnd.h"

#include <soc/qcom/qmi_rmnet.h>
#define CREATE_TRACE_POINTS
#include <trace/events/rmnet.h>

/* RX/TX Fixup */

@@ -62,6 +64,7 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,

	priv = netdev_priv(dev);
	if (priv->real_dev) {
		trace_rmnet_xmit_skb(skb);
		qmi_rmnet_burst_fc_check(dev, skb);
		rmnet_egress_handler(skb);
	} else {
+91 −97
Original line number Diff line number Diff line
@@ -18,23 +18,20 @@

#include <linux/ip.h>
#include "qmi_rmnet_i.h"
#define CREATE_TRACE_POINTS
#include <trace/events/dfc.h>

#define DFC_MAX_BEARERS_V01 16
#define DFC_MAX_QOS_ID_V01 2
#define DEFAULT_FLOW_ID 0

/* bearer list update result */
#define NO_BEARER 0
#define NO_CHANGE 1
#define UPDATED 2

struct dfc_qmi_data {
	void *rmnet_port;
	struct workqueue_struct *dfc_wq;
	struct work_struct svc_arrive;
	struct qmi_handle handle;
	struct sockaddr_qrtr ssctl;
	int modem;
	int index;
};

struct dfc_svc_ind {
@@ -512,98 +509,94 @@ static int dfc_init_service(struct dfc_qmi_data *data, struct qmi_info *qmi)
	int rc;

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

	return dfc_indication_register_req(&data->handle, &data->ssctl, 1);
}

static int dfc_disable_bearer_flows(struct net_device *dev, u8 bearer_id)
static int dfc_bearer_flow_ctl(struct net_device *dev, struct qos_info *qos,
			       u8 bearer_id, u32 grant_size, int enable)
{
	struct qos_info *qos = (struct qos_info *)rmnet_get_qos_pt(dev);
	struct list_head *p;
	struct rmnet_flow_map *itm;
	int rc = 0;

	if (!qos)
		return 0;
	int rc = 0, qlen;

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

		if (unlikely(!itm))
			return 0;

		if (itm->bearer_id == bearer_id) {
			tc_qdisc_flow_control(dev, itm->tcm_handle, 0);
			qlen = tc_qdisc_flow_control(dev, itm->tcm_handle,
						    enable);
			trace_dfc_qmi_tc(itm->bearer_id, itm->flow_id,
					 grant_size, qlen, itm->tcm_handle,
					 enable);
			rc++;
		}
	}
	return rc;
}

static int dfc_update_fc_map(struct qos_info *qos, u8 ack_req,
static int dfc_all_bearer_flow_ctl(struct net_device *dev,
				struct qos_info *qos, u8 ack_req,
				struct dfc_flow_status_info_type_v01 *fc_info)
{
	struct rmnet_bearer_map *itm = NULL;
	int rc = NO_BEARER;
	struct list_head *p;
	struct rmnet_flow_map *flow_itm;
	struct rmnet_bearer_map *bearer_itm;
	int enable;
	int rc = 0, len;

	itm = qmi_rmnet_get_bearer_map(qos, fc_info->bearer_id);
	if (itm) {
		if ((itm->grant_size == fc_info->num_bytes) &&
		    (itm->counter > 0)) {
			/*flow is enabled and grant_size is the same*/
			rc = NO_CHANGE;
		} else {
			itm->grant_size = fc_info->num_bytes;
			itm->seq = fc_info->seq_num;
			itm->ack_req = ack_req;
			rc = UPDATED;
	list_for_each(p, &qos->bearer_head) {
		bearer_itm = list_entry(p, struct rmnet_bearer_map, list);

		bearer_itm->grant_size = fc_info->num_bytes;
		bearer_itm->seq = fc_info->seq_num;
		bearer_itm->ack_req = ack_req;
	}
		itm->counter = 0;

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

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

		len = tc_qdisc_flow_control(dev, flow_itm->tcm_handle, enable);
		trace_dfc_qmi_tc(flow_itm->bearer_id, flow_itm->flow_id,
				 fc_info->num_bytes, len,
				 flow_itm->tcm_handle, enable);
		rc++;
	}
	return rc;
}

static int dfc_do_fc(struct net_device *dev, u32 flow_id,
		     int ip_type, int enable)
static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos,
			     u8 ack_req,
			     struct dfc_flow_status_info_type_v01 *fc_info)
{
	struct qos_info *qos = (struct qos_info *)rmnet_get_qos_pt(dev);
	struct rmnet_flow_map *itm = NULL;
	int len = 0;

	if (!qos)
		return 0;
	struct rmnet_bearer_map *itm = NULL;
	int rc = 0;
	int action = -1;

	itm = qmi_rmnet_get_flow_map(qos, flow_id, ip_type);
	itm = qmi_rmnet_get_bearer_map(qos, fc_info->bearer_id);
	if (itm) {
		len = tc_qdisc_flow_control(dev, itm->tcm_handle, enable);
	}
	return len;
}
		if (itm->grant_size == 0 && fc_info->num_bytes > 0)
			action = 1;
		else if (itm->grant_size > 0 && fc_info->num_bytes == 0)
			action = 0;

static void dfc_do_flow_controls(struct net_device *dev,
				 struct dfc_flow_status_info_type_v01 *flow)
{
	int i;
	int enable = (flow->num_bytes > 0) ? 1 : 0;
	int qdisc_len;
		itm->grant_size = fc_info->num_bytes;
		itm->seq = fc_info->seq_num;
		itm->ack_req = ack_req;

	for (i = 0; i < flow->qos_ids_len; i++) {
		/* do flow control per specified flow */
		if (flow->qos_ids[i].ip_type == DFC_IPV4_TYPE_V01) {
			qdisc_len = dfc_do_fc(dev, flow->qos_ids[i].qos_id,
					      AF_INET, enable);
			pr_debug("%s() qdisc_len=%d\n", __func__, qdisc_len);
		} else if (flow->qos_ids[i].ip_type == DFC_IPV6_TYPE_V01) {
			qdisc_len = dfc_do_fc(dev, flow->qos_ids[i].qos_id,
					      AF_INET6, enable);
		if (action != -1)
			rc = dfc_bearer_flow_ctl(dev, qos, fc_info->bearer_id,
						itm->grant_size, action);
	} else {
			pr_err("%s() ip type[%d] not supported\n",
				__func__, flow->qos_ids[i].ip_type);
		}
		pr_debug("grant %u before flow activate", fc_info->num_bytes);
		qos->default_grant = fc_info->num_bytes;
	}
	return rc;
}

static void dfc_do_burst_flow_control(struct work_struct *work)
@@ -636,6 +629,12 @@ static void dfc_do_burst_flow_control(struct work_struct *work)

	for (i = 0; i < ind->flow_status_len; i++) {
		flow_status = &ind->flow_status[i];
		trace_dfc_flow_ind(svc_ind->data->index,
				   i, flow_status->mux_id,
				   flow_status->bearer_id,
				   flow_status->num_bytes,
				   flow_status->seq_num,
				   ack_req);
		dev = rmnet_get_rmnet_dev(svc_ind->data->rmnet_port,
					  flow_status->mux_id);
		if (!dev)
@@ -645,22 +644,11 @@ static void dfc_do_burst_flow_control(struct work_struct *work)
		if (!qos)
			continue;

		rc = dfc_update_fc_map(qos, ack_req, flow_status);
		if (rc == NO_BEARER) {
			pr_debug("%s: num_bytes[%u]\n",
				 __func__, flow_status->num_bytes);
			qos->default_grant = flow_status->num_bytes;
			continue;
		} else if (rc == NO_CHANGE) {
			continue;
		} else {
			if ((flow_status->num_bytes > 0) ||
			    (flow_status->bearer_id != 0xFF))
				dfc_do_flow_controls(dev, flow_status);
		if (unlikely(flow_status->bearer_id == 0xFF))
			rc = dfc_all_bearer_flow_ctl(
				dev, qos, ack_req, flow_status);
		else
				netif_stop_queue(dev);

		}
			rc = dfc_update_fc_map(dev, qos, ack_req, flow_status);
	}

clean_out:
@@ -729,7 +717,11 @@ static void dfc_svc_init(struct work_struct *work)
		return;
	}

	qmi->fc_info[data->modem].dfc_client = (void *)data;
	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);
}

static int dfc_svc_arrive(struct qmi_handle *qmi, struct qmi_service *svc)
@@ -753,9 +745,10 @@ static void dfc_svc_exit(struct qmi_handle *qmi, struct qmi_service *svc)
	struct qmi_info *qmi_pt;
	int client;

	trace_dfc_client_state_down(data->index, 1);
	qmi_pt = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port);
	if (qmi_pt) {
		for (client = 0; client < 2; client++) {
		for (client = 0; client < MAX_CLIENT_NUM; client++) {
			if (qmi_pt->fc_info[client].dfc_client == (void *)data)
				qmi_pt->fc_info[client].dfc_client = NULL;
			break;
@@ -781,7 +774,7 @@ static struct qmi_msg_handler qmi_indication_handler[] = {
	{},
};

int dfc_qmi_client_init(void *port, int modem, struct qmi_info *qmi)
int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi)
{
	struct dfc_qmi_data *data;
	int rc = -ENOMEM;
@@ -791,7 +784,7 @@ int dfc_qmi_client_init(void *port, int modem, struct qmi_info *qmi)
		return -ENOMEM;

	data->rmnet_port = port;
	data->modem = modem;
	data->index = index;

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

	rc = qmi_add_lookup(&data->handle, DFC_SERVICE_ID_V01,
			    DFC_SERVICE_VERS_V01,
			    qmi->fc_info[modem].svc.instance);
			    qmi->fc_info[index].svc.instance);
	if (rc < 0) {
		pr_err("%s: failed qmi_add_lookup - rc[%d]\n", __func__, rc);
		goto err2;
@@ -834,7 +827,7 @@ void dfc_qmi_client_exit(void *dfc_data)
	/* Skip this call for now due to error in qmi layer
	 * qmi_handle_release(&data->handle);
	 */

	trace_dfc_client_state_down(data->index, 0);
	drain_workqueue(data->dfc_wq);
	destroy_workqueue(data->dfc_wq);
	kfree(data);
@@ -862,18 +855,19 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos,
			return;
		}

		bearer->counter += skb->len;
		if (bearer->counter >= bearer->grant_size) {
			bearer->counter = 0;
		trace_dfc_flow_check(bearer->bearer_id,
				     skb->len, bearer->grant_size);

			dfc_disable_bearer_flows(dev, bearer->bearer_id);
			rtnl_unlock();
		if (skb->len >= bearer->grant_size) {
			bearer->grant_size = 0;
			dfc_bearer_flow_ctl(dev, qos, bearer->bearer_id,
					    bearer->grant_size, 0);
		} else {
			rtnl_unlock();
			bearer->grant_size -= skb->len;
		}
	} else {
		rtnl_unlock();
	}

	rtnl_unlock();
}

void dfc_reset_port_pt(void *dfc_data)
+7 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/rtnetlink.h>
#include <uapi/linux/rtnetlink.h>
#include "qmi_rmnet_i.h"
#include <trace/events/dfc.h>

#define NLMSG_FLOW_ACTIVATE 1
#define NLMSG_FLOW_DEACTIVATE 2
@@ -148,6 +149,8 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm)
	new_map.flow_id = tcm->tcm_parent;
	new_map.ip_type = tcm->tcm_ifindex;
	new_map.tcm_handle = tcm->tcm_handle;
	trace_dfc_flow_info(new_map.bearer_id, new_map.flow_id,
			    new_map.ip_type, new_map.tcm_handle, 1);

	itm = qmi_rmnet_get_flow_map(qos_info, new_map.flow_id,
				     new_map.ip_type);
@@ -202,8 +205,11 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm)
	new_map.ip_type = tcm->tcm_ifindex;
	itm = qmi_rmnet_get_flow_map(qos_info, new_map.flow_id,
				     new_map.ip_type);
	if (itm)
	if (itm) {
		trace_dfc_flow_info(new_map.bearer_id, new_map.flow_id,
				    new_map.ip_type, itm->tcm_handle, 0);
		list_del(&itm->list);
	}

	/*clear bearer map*/
	bearer = qmi_rmnet_get_bearer_map(qos_info, new_map.bearer_id);
+1 −2
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ struct rmnet_bearer_map {
	u8 bearer_id;
	int flow_ref;
	u32 grant_size;
	u32 counter;
	u16 seq;
	u8  ack_req;
};
@@ -91,7 +90,7 @@ qmi_rmnet_get_flow_map(struct qos_info *qos_info,
struct rmnet_bearer_map *
qmi_rmnet_get_bearer_map(struct qos_info *qos_info, u8 bearer_id);

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

void dfc_qmi_client_exit(void *dfc_data);

+185 −0
Original line number Diff line number Diff line
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#undef TRACE_SYSTEM
#define TRACE_SYSTEM dfc

#if !defined(_TRACE_DFC_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_DFC_H

#include <linux/tracepoint.h>

TRACE_EVENT(dfc_qmi_tc,

	TP_PROTO(u8 bearer_id, u32 flow_id, u32 grant, int qlen,
		 u32 tcm_handle, int enable),

	TP_ARGS(bearer_id, flow_id, grant, qlen, tcm_handle, enable),

	TP_STRUCT__entry(
		__field(u8, bid)
		__field(u32, fid)
		__field(u32, grant)
		__field(int, qlen)
		__field(u32, tcm_handle)
		__field(int, enable)
	),

	TP_fast_assign(
		__entry->bid = bearer_id;
		__entry->fid = flow_id;
		__entry->grant = grant;
		__entry->qlen = qlen;
		__entry->tcm_handle = tcm_handle;
		__entry->enable = enable;
	),

	TP_printk("bearer_id=%u grant=%u qdisc_len=%d flow_id=%u "
		  "tcm_handle=0x%x %s",
		__entry->bid, __entry->grant, __entry->qlen, __entry->fid,
		__entry->tcm_handle,
		__entry->enable ? "enable" : "disable")
);

TRACE_EVENT(dfc_flow_ind,

	TP_PROTO(int src, int idx, u8 mux_id, u8 bearer_id, u32 grant,
		 u16 seq_num, u8 ack_req),

	TP_ARGS(src, idx, mux_id, bearer_id, grant, seq_num, ack_req),

	TP_STRUCT__entry(
		__field(int, src)
		__field(int, idx)
		__field(u8, mid)
		__field(u8, bid)
		__field(u32, grant)
		__field(u16, seq)
		__field(u8, ack_req)
	),

	TP_fast_assign(
		__entry->src = src;
		__entry->idx = idx;
		__entry->mid = mux_id;
		__entry->bid = bearer_id;
		__entry->grant = grant;
		__entry->seq = seq_num;
		__entry->ack_req = ack_req;
	),

	TP_printk("src=%d idx[%d]: mux_id=%u bearer_id=%u grant=%u "
		  "seq_num=%u ack_req=%u",
		__entry->src, __entry->idx, __entry->mid, __entry->bid,
		__entry->grant, __entry->seq, __entry->ack_req)
);

TRACE_EVENT(dfc_flow_check,

	TP_PROTO(u8 bearer_id, unsigned int len, u32 grant),

	TP_ARGS(bearer_id, len, grant),

	TP_STRUCT__entry(
		__field(u8, bearer_id)
		__field(unsigned int, len)
		__field(u32, grant)
	),

	TP_fast_assign(
		__entry->bearer_id = bearer_id;
		__entry->len = len;
		__entry->grant = grant;
	),

	TP_printk("bearer_id=%u skb_len=%u current_grant=%u",
		__entry->bearer_id, __entry->len, __entry->grant)
);

TRACE_EVENT(dfc_flow_info,

	TP_PROTO(u8 bearer_id, u32 flow_id, int ip_type, u32 handle, int add),

	TP_ARGS(bearer_id, flow_id, ip_type, handle, add),

	TP_STRUCT__entry(
		__field(u8, bid)
		__field(u32, fid)
		__field(int, ip)
		__field(u32, handle)
		__field(int, action)
	),

	TP_fast_assign(
		__entry->bid = bearer_id;
		__entry->fid = flow_id;
		__entry->ip = ip_type;
		__entry->handle = handle;
		__entry->action = add;
	),

	TP_printk("%s: bearer_id=%u flow_id=%u ip_type=%d tcm_handle=0x%x",
		__entry->action ? "add flow" : "delete flow",
		__entry->bid, __entry->fid, __entry->ip, __entry->handle)
);

TRACE_EVENT(dfc_client_state_up,

	TP_PROTO(int idx, u32 instance, u32 ep_type, u32 iface),

	TP_ARGS(idx, instance, ep_type, iface),

	TP_STRUCT__entry(
		__field(int, idx)
		__field(u32, instance)
		__field(u32, ep_type)
		__field(u32, iface)
	),

	TP_fast_assign(
		__entry->idx = idx;
		__entry->instance = instance;
		__entry->ep_type = ep_type;
		__entry->iface = iface;
	),

	TP_printk("Client[%d]: Connection established with DFC Service "
		  "instance=%u ep_type=%u iface_id=%u",
		__entry->idx, __entry->instance,
		__entry->ep_type, __entry->iface)
);

TRACE_EVENT(dfc_client_state_down,

	TP_PROTO(int idx, int from_cb),

	TP_ARGS(idx, from_cb),

	TP_STRUCT__entry(
		__field(int, idx)
		__field(int, from_cb)
	),

	TP_fast_assign(
		__entry->idx = idx;
		__entry->from_cb = from_cb;
	),

	TP_printk("Client[%d]: Connection with DFC service lost. "
		  "Exit by callback %d",
		  __entry->idx, __entry->from_cb)
);

#endif /* _TRACE_DFC_H */

/* This part must be outside protection */
#include <trace/define_trace.h>
Loading