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

Commit ff11dc8f authored by Linux Build Service Account's avatar Linux Build Service Account
Browse files

Merge 45a8e8f2 on remote branch

Change-Id: Ib292dd3d470bb9eaa5ad20b3b788ce101596eb93
parents 0f27b6b1 45a8e8f2
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -292,6 +292,28 @@ TRACE_EVENT(dfc_adjust_grant,
		__entry->rx_bytes, __entry->inflight, __entry->a_grant)
);

TRACE_EVENT(dfc_watchdog,

	TP_PROTO(u8 mux_id, u8 bearer_id, u8 event),

	TP_ARGS(mux_id, bearer_id, event),

	TP_STRUCT__entry(
		__field(u8, mux_id)
		__field(u8, bearer_id)
		__field(u8, event)
	),

	TP_fast_assign(
		__entry->mux_id = mux_id;
		__entry->bearer_id = bearer_id;
		__entry->event = event;
	),

	TP_printk("mid=%u bid=%u event=%u",
		__entry->mux_id, __entry->bearer_id, __entry->event)
);

#endif /* _TRACE_DFC_H */

/* This part must be outside protection */
+14 −7
Original line number Diff line number Diff line
@@ -127,10 +127,11 @@ static struct dfc_tx_link_status_ind_msg_v01 qmap_tx_ind;
static struct dfc_qmi_data __rcu *qmap_dfc_data;
static atomic_t qmap_txid;
static void *rmnet_ctl_handle;
static bool dfc_config_acked;

extern struct rmnet_ctl_client_if rmnet_ctl_if;
static struct rmnet_ctl_client_if *rmnet_ctl;

static void dfc_qmap_send_config(struct dfc_qmi_data *data);
static void dfc_qmap_send_end_marker_cnf(struct qos_info *qos,
					 u8 bearer_id, u16 seq, u32 tx_id);

@@ -320,6 +321,9 @@ static void dfc_qmap_cmd_handler(struct sk_buff *skb)
		if (cmd->cmd_type != QMAP_CMD_ACK)
			goto free_skb;
	} else if (cmd->cmd_type != QMAP_CMD_REQUEST) {
		if (cmd->cmd_type == QMAP_CMD_ACK &&
		    cmd->cmd_name == QMAP_DFC_CONFIG)
			dfc_config_acked = true;
		goto free_skb;
	}

@@ -331,6 +335,12 @@ static void dfc_qmap_cmd_handler(struct sk_buff *skb)
		goto free_skb;
	}

	/* Re-send DFC config once if needed */
	if (unlikely(!dfc_config_acked)) {
		dfc_qmap_send_config(dfc);
		dfc_config_acked = true;
	}

	switch (cmd->cmd_name) {
	case QMAP_DFC_IND:
		rc = dfc_qmap_handle_ind(dfc, skb);
@@ -504,7 +514,7 @@ int dfc_qmap_client_init(void *port, int index, struct svc_info *psvc,

	atomic_set(&qmap_txid, 0);

	rmnet_ctl = symbol_get(rmnet_ctl_if);
	rmnet_ctl = rmnet_ctl_if();
	if (!rmnet_ctl) {
		pr_err("rmnet_ctl module not loaded\n");
		goto out;
@@ -521,6 +531,7 @@ int dfc_qmap_client_init(void *port, int index, struct svc_info *psvc,

	pr_info("DFC QMAP init\n");

	dfc_config_acked = false;
	dfc_qmap_send_config(data);

out:
@@ -547,11 +558,7 @@ void dfc_qmap_client_exit(void *dfc_data)
	synchronize_rcu();

	kfree(data);

	if (rmnet_ctl) {
		symbol_put(rmnet_ctl_if);
	rmnet_ctl = NULL;
	}

	pr_info("DFC QMAP exit\n");
}
+8 −3
Original line number Diff line number Diff line
@@ -1034,14 +1034,18 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos,
		itm->grant_size = adjusted_grant;

		/* No further query if the adjusted grant is less
		 * than 20% of the original grant
		 * than 20% of the original grant. Add to watch to
		 * recover if no indication is received.
		 */
		if (dfc_qmap && is_query &&
		    itm->grant_size < (fc_info->num_bytes / 5))
		    itm->grant_size < (fc_info->num_bytes / 5)) {
			itm->grant_thresh = itm->grant_size;
		else
			qmi_rmnet_watchdog_add(itm);
		} else {
			itm->grant_thresh =
				qmi_rmnet_grant_per(itm->grant_size);
			qmi_rmnet_watchdog_remove(itm);
		}

		itm->seq = fc_info->seq_num;
		itm->ack_req = ack_req;
@@ -1143,6 +1147,7 @@ static void dfc_update_tx_link_status(struct net_device *dev,
		itm->grant_size = 0;
		itm->tcp_bidir = false;
		itm->bytes_in_flight = 0;
		qmi_rmnet_watchdog_remove(itm);
		dfc_bearer_flow_ctl(dev, itm, qos);
	} else if (itm->grant_size == 0 && tx_status && !itm->rat_switch) {
		itm->grant_size = DEFAULT_GRANT;
+126 −9
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/rtnetlink.h>
#include <uapi/linux/rtnetlink.h>
#include <net/pkt_sched.h>
#include <net/tcp.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h>
@@ -53,6 +54,7 @@ unsigned int rmnet_wq_frequency __read_mostly = 1000;
					1 : rmnet_wq_frequency/10) * (HZ/100))
#define NO_DELAY (0x0000 * HZ)
#define PS_INTERVAL_KT (ms_to_ktime(1000))
#define WATCHDOG_EXPIRE_JF (msecs_to_jiffies(50))

#ifdef CONFIG_QTI_QMI_DFC
static unsigned int qmi_rmnet_scale_factor = 5;
@@ -233,6 +235,89 @@ static void qmi_rmnet_reset_txq(struct net_device *dev, unsigned int txq)
	}
}

/**
 * qmi_rmnet_watchdog_fn - watchdog timer func
 */
static void qmi_rmnet_watchdog_fn(struct timer_list *t)
{
	struct rmnet_bearer_map *bearer;

	bearer = container_of(t, struct rmnet_bearer_map, watchdog);

	trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 2);

	spin_lock_bh(&bearer->qos->qos_lock);

	if (bearer->watchdog_quit)
		goto done;

	/*
	 * Possible stall, try to recover. Enable 80% query and jumpstart
	 * the bearer if disabled.
	 */
	bearer->watchdog_expire_cnt++;
	bearer->bytes_in_flight = 0;
	if (!bearer->grant_size) {
		bearer->grant_size = DEFAULT_CALL_GRANT;
		bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size);
		dfc_bearer_flow_ctl(bearer->qos->vnd_dev, bearer, bearer->qos);
	} else {
		bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size);
	}

done:
	bearer->watchdog_started = false;
	spin_unlock_bh(&bearer->qos->qos_lock);
}

/**
 * qmi_rmnet_watchdog_add - add the bearer to watch
 * Needs to be called with qos_lock
 */
void qmi_rmnet_watchdog_add(struct rmnet_bearer_map *bearer)
{
	bearer->watchdog_quit = false;

	if (bearer->watchdog_started)
		return;

	bearer->watchdog_started = true;
	mod_timer(&bearer->watchdog, jiffies + WATCHDOG_EXPIRE_JF);

	trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 1);
}

/**
 * qmi_rmnet_watchdog_remove - remove the bearer from watch
 * Needs to be called with qos_lock
 */
void qmi_rmnet_watchdog_remove(struct rmnet_bearer_map *bearer)
{
	bearer->watchdog_quit = true;

	if (!bearer->watchdog_started)
		return;

	del_timer(&bearer->watchdog);
	bearer->watchdog_started = false;

	trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 0);
}

/**
 * qmi_rmnet_bearer_clean - clean the removed bearer
 * Needs to be called with rtn_lock but not qos_lock
 */
static void qmi_rmnet_bearer_clean(struct qos_info *qos)
{
	if (qos->removed_bearer) {
		qos->removed_bearer->watchdog_quit = true;
		del_timer_sync(&qos->removed_bearer->watchdog);
		kfree(qos->removed_bearer);
		qos->removed_bearer = NULL;
	}
}

static struct rmnet_bearer_map *__qmi_rmnet_bearer_get(
				struct qos_info *qos_info, u8 bearer_id)
{
@@ -252,6 +337,8 @@ static struct rmnet_bearer_map *__qmi_rmnet_bearer_get(
		bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size);
		bearer->mq_idx = INVALID_MQ;
		bearer->ack_mq_idx = INVALID_MQ;
		bearer->qos = qos_info;
		timer_setup(&bearer->watchdog, qmi_rmnet_watchdog_fn, 0);
		list_add(&bearer->list, &qos_info->bearer_head);
	}

@@ -287,7 +374,7 @@ static void __qmi_rmnet_bearer_put(struct net_device *dev,

		/* Remove from bearer map */
		list_del(&bearer->list);
		kfree(bearer);
		qos_info->removed_bearer = bearer;
	}
}

@@ -415,6 +502,9 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm,

done:
	spin_unlock_bh(&qos_info->qos_lock);

	qmi_rmnet_bearer_clean(qos_info);

	return rc;
}

@@ -458,6 +548,9 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm,
		netif_tx_wake_all_queues(dev);

	spin_unlock_bh(&qos_info->qos_lock);

	qmi_rmnet_bearer_clean(qos_info);

	return 0;
}

@@ -726,6 +819,8 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev)
		bearer->tcp_bidir = false;
		bearer->rat_switch = false;

		qmi_rmnet_watchdog_remove(bearer);

		if (bearer->tx_off)
			continue;

@@ -779,16 +874,14 @@ void qmi_rmnet_burst_fc_check(struct net_device *dev,
}
EXPORT_SYMBOL(qmi_rmnet_burst_fc_check);

static bool qmi_rmnet_is_tcp_ack(struct sk_buff *skb)
static bool _qmi_rmnet_is_tcp_ack(struct sk_buff *skb)
{
	unsigned int len = skb->len;

	switch (skb->protocol) {
	/* TCPv4 ACKs */
	case htons(ETH_P_IP):
		if ((ip_hdr(skb)->protocol == IPPROTO_TCP) &&
		    (ip_hdr(skb)->ihl == 5) &&
		    (len == 40 || len == 52) &&
		    (ntohs(ip_hdr(skb)->tot_len) - (ip_hdr(skb)->ihl << 2) ==
		      tcp_hdr(skb)->doff << 2) &&
		    ((tcp_flag_word(tcp_hdr(skb)) &
		      cpu_to_be32(0x00FF0000)) == TCP_FLAG_ACK))
			return true;
@@ -797,7 +890,8 @@ static bool qmi_rmnet_is_tcp_ack(struct sk_buff *skb)
	/* TCPv6 ACKs */
	case htons(ETH_P_IPV6):
		if ((ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) &&
		    (len == 60 || len == 72) &&
		    (ntohs(ipv6_hdr(skb)->payload_len) ==
		      (tcp_hdr(skb)->doff) << 2) &&
		    ((tcp_flag_word(tcp_hdr(skb)) &
		      cpu_to_be32(0x00FF0000)) == TCP_FLAG_ACK))
			return true;
@@ -807,6 +901,19 @@ static bool qmi_rmnet_is_tcp_ack(struct sk_buff *skb)
	return false;
}

static inline bool qmi_rmnet_is_tcp_ack(struct sk_buff *skb)
{
	/* Locally generated TCP acks */
	if (skb_is_tcp_pure_ack(skb))
		return true;

	/* Forwarded */
	if (unlikely(_qmi_rmnet_is_tcp_ack(skb)))
		return true;

	return false;
}

static int qmi_rmnet_get_queue_sa(struct qos_info *qos, struct sk_buff *skb)
{
	struct rmnet_flow_map *itm;
@@ -873,7 +980,8 @@ inline unsigned int qmi_rmnet_grant_per(unsigned int grant)
}
EXPORT_SYMBOL(qmi_rmnet_grant_per);

void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id)
void *qmi_rmnet_qos_init(struct net_device *real_dev,
			 struct net_device *vnd_dev, u8 mux_id)
{
	struct qos_info *qos;

@@ -883,6 +991,7 @@ void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id)

	qos->mux_id = mux_id;
	qos->real_dev = real_dev;
	qos->vnd_dev = vnd_dev;
	qos->tran_num = 0;
	INIT_LIST_HEAD(&qos->flow_head);
	INIT_LIST_HEAD(&qos->bearer_head);
@@ -894,10 +1003,18 @@ EXPORT_SYMBOL(qmi_rmnet_qos_init);

void qmi_rmnet_qos_exit_pre(void *qos)
{
	struct qos_info *qosi = (struct qos_info *)qos;
	struct rmnet_bearer_map *bearer;

	if (!qos)
		return;

	list_add(&((struct qos_info *)qos)->list, &qos_cleanup_list);
	list_for_each_entry(bearer, &qosi->bearer_head, list) {
		bearer->watchdog_quit = true;
		del_timer_sync(&bearer->watchdog);
	}

	list_add(&qosi->list, &qos_cleanup_list);
}
EXPORT_SYMBOL(qmi_rmnet_qos_exit_pre);

+4 −2
Original line number Diff line number Diff line
@@ -55,7 +55,8 @@ qmi_rmnet_all_flows_enabled(struct net_device *dev)
#endif

#ifdef CONFIG_QTI_QMI_DFC
void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id);
void *qmi_rmnet_qos_init(struct net_device *real_dev,
			 struct net_device *vnd_dev, u8 mux_id);
void qmi_rmnet_qos_exit_pre(void *qos);
void qmi_rmnet_qos_exit_post(void);
void qmi_rmnet_burst_fc_check(struct net_device *dev,
@@ -63,7 +64,8 @@ void qmi_rmnet_burst_fc_check(struct net_device *dev,
int qmi_rmnet_get_queue(struct net_device *dev, struct sk_buff *skb);
#else
static inline void *
qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id)
qmi_rmnet_qos_init(struct net_device *real_dev,
		   struct net_device *vnd_dev, u8 mux_id)
{
	return NULL;
}
Loading