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

Commit e1de9991 authored by Subash Abhinov Kasiviswanathan's avatar Subash Abhinov Kasiviswanathan Committed by Gerrit - the friendly Code Review server
Browse files

rmnet: flow control optimization



Reduce unnecessary DFC flow control operations.
Correctly handle FC messages when bearer_id is 0xFF.

Change-Id: Iba353d4be39b57167dbdab5df4cf9d348285464b
Acked-by: default avatarWeiyi Chen <weiyic@qti.qualcomm.com>
Signed-off-by: default avatarSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>
parent 8c856f2d
Loading
Loading
Loading
Loading
+66 −87
Original line number Diff line number Diff line
@@ -23,11 +23,6 @@
#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;
@@ -519,91 +514,89 @@ static int dfc_init_service(struct dfc_qmi_data *data, struct qmi_info *qmi)
	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, 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;

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

		if (unlikely(!itm))
			return 0;
			continue;

		if (itm->bearer_id == bearer_id) {
			tc_qdisc_flow_control(dev, itm->tcm_handle, 0);
			tc_qdisc_flow_control(dev, 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;

	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);

		if (unlikely(!bearer_itm))
			continue;

		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);

		if (unlikely(!flow_itm))
			continue;

		tc_qdisc_flow_control(dev, 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, 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)
@@ -645,22 +638,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:
@@ -862,18 +844,15 @@ 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;

			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, 0);
		} else {
			rtnl_unlock();
			bearer->grant_size -= skb->len;
		}
	} else {
		rtnl_unlock();
	}

	rtnl_unlock();
}

void dfc_reset_port_pt(void *dfc_data)
+0 −1
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;
};