Loading drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +4 −8 Original line number Original line Diff line number Diff line Loading @@ -496,7 +496,8 @@ EXPORT_SYMBOL(rmnet_get_qmi_pt); void *rmnet_get_qos_pt(struct net_device *dev) void *rmnet_get_qos_pt(struct net_device *dev) { { if (dev) if (dev) return ((struct rmnet_priv *)netdev_priv(dev))->qos_info; return rcu_dereference( ((struct rmnet_priv *)netdev_priv(dev))->qos_info); return NULL; return NULL; } } Loading @@ -520,14 +521,9 @@ struct net_device *rmnet_get_rmnet_dev(void *port, u8 mux_id) struct rmnet_endpoint *ep; struct rmnet_endpoint *ep; if (port) { if (port) { struct net_device *dev; ep = rmnet_get_endpoint((struct rmnet_port *)port, mux_id); ep = rmnet_get_endpoint((struct rmnet_port *)port, mux_id); if (ep) { if (ep) dev = ep->egress_dev; return ep->egress_dev; return dev; } } } return NULL; return NULL; Loading drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -107,7 +107,7 @@ struct rmnet_priv { struct rmnet_pcpu_stats __percpu *pcpu_stats; struct rmnet_pcpu_stats __percpu *pcpu_stats; struct gro_cells gro_cells; struct gro_cells gro_cells; struct rmnet_priv_stats stats; struct rmnet_priv_stats stats; void *qos_info; void __rcu *qos_info; }; }; int rmnet_is_real_dev_registered(const struct net_device *real_dev); int rmnet_is_real_dev_registered(const struct net_device *real_dev); Loading drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +23 −3 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/etherdevice.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> #include <linux/if_arp.h> #include <linux/ip.h> #include <net/pkt_sched.h> #include <net/pkt_sched.h> #include "rmnet_config.h" #include "rmnet_config.h" #include "rmnet_handlers.h" #include "rmnet_handlers.h" Loading Loading @@ -61,12 +62,19 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, struct net_device *dev) struct net_device *dev) { { struct rmnet_priv *priv; struct rmnet_priv *priv; int ip_type; u32 mark; unsigned int len; priv = netdev_priv(dev); priv = netdev_priv(dev); if (priv->real_dev) { if (priv->real_dev) { ip_type = (ip_hdr(skb)->version == 4) ? AF_INET : AF_INET6; mark = skb->mark; len = skb->len; trace_rmnet_xmit_skb(skb); trace_rmnet_xmit_skb(skb); qmi_rmnet_burst_fc_check(dev, skb); rmnet_egress_handler(skb); rmnet_egress_handler(skb); qmi_rmnet_burst_fc_check(dev, ip_type, mark, len); } else { } else { this_cpu_inc(priv->pcpu_stats->stats.tx_drops); this_cpu_inc(priv->pcpu_stats->stats.tx_drops); kfree_skb(skb); kfree_skb(skb); Loading Loading @@ -111,12 +119,15 @@ static int rmnet_vnd_init(struct net_device *dev) static void rmnet_vnd_uninit(struct net_device *dev) static void rmnet_vnd_uninit(struct net_device *dev) { { struct rmnet_priv *priv = netdev_priv(dev); struct rmnet_priv *priv = netdev_priv(dev); void *qos; gro_cells_destroy(&priv->gro_cells); gro_cells_destroy(&priv->gro_cells); free_percpu(priv->pcpu_stats); free_percpu(priv->pcpu_stats); qmi_rmnet_qos_exit(dev); qos = priv->qos_info; priv->qos_info = NULL; RCU_INIT_POINTER(priv->qos_info, NULL); synchronize_rcu(); qmi_rmnet_qos_exit(dev, qos); } } static void rmnet_get_stats64(struct net_device *dev, static void rmnet_get_stats64(struct net_device *dev, Loading Loading @@ -150,6 +161,14 @@ static void rmnet_get_stats64(struct net_device *dev, s->tx_dropped = total_stats.tx_drops; s->tx_dropped = total_stats.tx_drops; } } static u16 rmnet_vnd_select_queue(struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { return 0; } static const struct net_device_ops rmnet_vnd_ops = { static const struct net_device_ops rmnet_vnd_ops = { .ndo_start_xmit = rmnet_vnd_start_xmit, .ndo_start_xmit = rmnet_vnd_start_xmit, .ndo_change_mtu = rmnet_vnd_change_mtu, .ndo_change_mtu = rmnet_vnd_change_mtu, Loading @@ -159,6 +178,7 @@ static const struct net_device_ops rmnet_vnd_ops = { .ndo_init = rmnet_vnd_init, .ndo_init = rmnet_vnd_init, .ndo_uninit = rmnet_vnd_uninit, .ndo_uninit = rmnet_vnd_uninit, .ndo_get_stats64 = rmnet_get_stats64, .ndo_get_stats64 = rmnet_get_stats64, .ndo_select_queue = rmnet_vnd_select_queue, }; }; static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = { static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = { Loading drivers/soc/qcom/dfc_qmi.c +40 −140 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,6 @@ #include <linux/soc/qcom/qmi.h> #include <linux/soc/qcom/qmi.h> #include <soc/qcom/rmnet_qmi.h> #include <soc/qcom/rmnet_qmi.h> #include <linux/ip.h> #include "qmi_rmnet_i.h" #include "qmi_rmnet_i.h" #define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS #include <trace/events/dfc.h> #include <trace/events/dfc.h> Loading Loading @@ -61,20 +60,6 @@ struct dfc_qmi_data { int restart_state; int restart_state; }; }; struct dfc_svc_ind { struct work_struct work; struct dfc_qmi_data *data; void *dfc_info; }; struct dfc_burst_ind { struct work_struct work; struct net_device *dev; struct qos_info *qos; struct rmnet_bearer_map *bearer; struct dfc_qmi_data *data; }; static void dfc_svc_init(struct work_struct *work); static void dfc_svc_init(struct work_struct *work); static void dfc_do_burst_flow_control(struct work_struct *work); static void dfc_do_burst_flow_control(struct work_struct *work); Loading Loading @@ -257,6 +242,12 @@ struct dfc_flow_status_ind_msg_v01 { u8 eod_ack_reqd; u8 eod_ack_reqd; }; }; struct dfc_svc_ind { struct work_struct work; struct dfc_qmi_data *data; struct dfc_flow_status_ind_msg_v01 dfc_info; }; static struct qmi_elem_info dfc_bind_client_req_msg_v01_ei[] = { static struct qmi_elem_info dfc_bind_client_req_msg_v01_ei[] = { { { .data_type = QMI_OPT_FLAG, .data_type = QMI_OPT_FLAG, Loading Loading @@ -596,7 +587,7 @@ static int dfc_bearer_flow_ctl(struct net_device *dev, itm = list_entry(p, struct rmnet_flow_map, list); itm = list_entry(p, struct rmnet_flow_map, list); if (itm->bearer_id == bearer->bearer_id) { if (itm->bearer_id == bearer->bearer_id) { qlen = tc_qdisc_flow_control(dev, itm->tcm_handle, qlen = qmi_rmnet_flow_control(dev, itm->tcm_handle, enable); enable); trace_dfc_qmi_tc(itm->bearer_id, itm->flow_id, trace_dfc_qmi_tc(itm->bearer_id, itm->flow_id, bearer->grant_size, qlen, bearer->grant_size, qlen, Loading @@ -618,10 +609,9 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, struct dfc_flow_status_info_type_v01 *fc_info) struct dfc_flow_status_info_type_v01 *fc_info) { { struct list_head *p; struct list_head *p; struct rmnet_flow_map *flow_itm; struct rmnet_bearer_map *bearer_itm = NULL; struct rmnet_bearer_map *bearer_itm; int enable; int enable; int rc = 0, len; int rc = 0; list_for_each(p, &qos->bearer_head) { list_for_each(p, &qos->bearer_head) { bearer_itm = list_entry(p, struct rmnet_bearer_map, list); bearer_itm = list_entry(p, struct rmnet_bearer_map, list); Loading @@ -635,15 +625,12 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, enable = fc_info->num_bytes > 0 ? 1 : 0; enable = fc_info->num_bytes > 0 ? 1 : 0; list_for_each(p, &qos->flow_head) { if (enable) flow_itm = list_entry(p, struct rmnet_flow_map, list); netif_tx_wake_all_queues(dev); else netif_tx_stop_all_queues(dev); len = tc_qdisc_flow_control(dev, flow_itm->tcm_handle, enable); trace_dfc_qmi_tc(0xFF, 0, fc_info->num_bytes, 0, 0, enable); trace_dfc_qmi_tc(flow_itm->bearer_id, flow_itm->flow_id, fc_info->num_bytes, len, flow_itm->tcm_handle, enable); rc++; } if (enable == 0 && ack_req) if (enable == 0 && ack_req) dfc_send_ack(dev, fc_info->bearer_id, dfc_send_ack(dev, fc_info->bearer_id, Loading Loading @@ -686,31 +673,19 @@ static void dfc_do_burst_flow_control(struct work_struct *work) { { struct dfc_svc_ind *svc_ind = (struct dfc_svc_ind *)work; struct dfc_svc_ind *svc_ind = (struct dfc_svc_ind *)work; struct dfc_flow_status_ind_msg_v01 *ind = struct dfc_flow_status_ind_msg_v01 *ind = (struct dfc_flow_status_ind_msg_v01 *)svc_ind->dfc_info; (struct dfc_flow_status_ind_msg_v01 *)&svc_ind->dfc_info; struct net_device *dev; struct net_device *dev; struct qos_info *qos; struct qos_info *qos; struct dfc_flow_status_info_type_v01 *flow_status; struct dfc_flow_status_info_type_v01 *flow_status; u8 ack_req = ind->eod_ack_reqd_valid ? ind->eod_ack_reqd : 0; u8 ack_req = ind->eod_ack_reqd_valid ? ind->eod_ack_reqd : 0; int i, rc; int i; if (!svc_ind->data->rmnet_port) { kfree(ind); kfree(svc_ind); return; } while (!rtnl_trylock()) { if (unlikely(svc_ind->data->restart_state)) { if (!svc_ind->data->restart_state) { cond_resched(); } else { kfree(ind); kfree(svc_ind); kfree(svc_ind); return; return; } } } if (unlikely(svc_ind->data->restart_state)) rcu_read_lock(); goto clean_out; for (i = 0; i < ind->flow_status_len; i++) { for (i = 0; i < ind->flow_status_len; i++) { flow_status = &ind->flow_status[i]; flow_status = &ind->flow_status[i]; Loading @@ -729,67 +704,20 @@ static void dfc_do_burst_flow_control(struct work_struct *work) if (!qos) if (!qos) continue; continue; spin_lock_bh(&qos->qos_lock); if (unlikely(flow_status->bearer_id == 0xFF)) if (unlikely(flow_status->bearer_id == 0xFF)) rc = dfc_all_bearer_flow_ctl( dfc_all_bearer_flow_ctl( dev, qos, ack_req, flow_status); dev, qos, ack_req, flow_status); else else rc = dfc_update_fc_map(dev, qos, ack_req, flow_status); dfc_update_fc_map(dev, qos, ack_req, flow_status); spin_unlock_bh(&qos->qos_lock); } } clean_out: clean_out: kfree(ind); rcu_read_unlock(); kfree(svc_ind); kfree(svc_ind); rtnl_unlock(); } static void dfc_bearer_limit_work(struct work_struct *work) { struct dfc_burst_ind *dfc_ind = (struct dfc_burst_ind *)work; struct rmnet_flow_map *itm; struct list_head *p; int qlen, fc; /* enable transmit on device so that the other * flows which transmit proceed normally. */ netif_start_queue(dfc_ind->dev); while (!rtnl_trylock()) { if (!dfc_ind->data->restart_state) { cond_resched(); } else { kfree(dfc_ind); return; } } fc = dfc_ind->bearer->grant_size ? 1 : 0; /* if grant size is non zero here, we must have already * got an updated grant. do nothing in that case */ if (fc) goto done; list_for_each(p, &dfc_ind->qos->flow_head) { itm = list_entry(p, struct rmnet_flow_map, list); if (itm->bearer_id == dfc_ind->bearer->bearer_id) { qlen = tc_qdisc_flow_control(dfc_ind->dev, itm->tcm_handle, fc); trace_dfc_qmi_tc_limit(itm->bearer_id, itm->flow_id, dfc_ind->bearer->grant_size, qlen, itm->tcm_handle, fc); } } if (dfc_ind->bearer->ack_req) dfc_send_ack(dfc_ind->dev, dfc_ind->bearer->bearer_id, dfc_ind->bearer->seq, dfc_ind->qos->mux_id, DFC_ACK_TYPE_DISABLE); done: kfree(dfc_ind); rtnl_unlock(); } } static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, Loading @@ -800,9 +728,6 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct dfc_flow_status_ind_msg_v01 *ind_msg; struct dfc_flow_status_ind_msg_v01 *ind_msg; struct dfc_svc_ind *svc_ind; struct dfc_svc_ind *svc_ind; if (!dfc->rmnet_port) return; if (qmi != &dfc->handle) if (qmi != &dfc->handle) return; return; Loading @@ -820,14 +745,10 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, INIT_WORK((struct work_struct *)svc_ind, INIT_WORK((struct work_struct *)svc_ind, dfc_do_burst_flow_control); dfc_do_burst_flow_control); svc_ind->dfc_info = kzalloc(sizeof(*ind_msg), GFP_ATOMIC); if (!svc_ind->dfc_info) { kfree(svc_ind); return; } memcpy(svc_ind->dfc_info, ind_msg, sizeof(*ind_msg)); memcpy(&svc_ind->dfc_info, ind_msg, sizeof(*ind_msg)); svc_ind->data = dfc; svc_ind->data = dfc; queue_work(dfc->dfc_wq, (struct work_struct *)svc_ind); queue_work(dfc->dfc_wq, (struct work_struct *)svc_ind); } } } } Loading Loading @@ -965,35 +886,32 @@ void dfc_qmi_client_exit(void *dfc_data) } } void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, struct sk_buff *skb, struct qmi_info *qmi) int ip_type, u32 mark, unsigned int len) { { struct rmnet_bearer_map *bearer; struct rmnet_bearer_map *bearer; struct dfc_burst_ind *dfc_ind; struct rmnet_flow_map *itm; struct rmnet_flow_map *itm; struct dfc_qmi_data *data; int ip_type; u32 start_grant; u32 start_grant; ip_type = (ip_hdr(skb)->version == IP_VER_6) ? AF_INET6 : AF_INET; spin_lock(&qos->qos_lock); itm = qmi_rmnet_get_flow_map(qos, skb->mark, ip_type); itm = qmi_rmnet_get_flow_map(qos, mark, ip_type); if (unlikely(!itm)) if (unlikely(!itm)) return; goto out; bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); if (unlikely(!bearer)) if (unlikely(!bearer)) return; goto out; trace_dfc_flow_check(bearer->bearer_id, skb->len, bearer->grant_size); trace_dfc_flow_check(bearer->bearer_id, len, bearer->grant_size); if (!bearer->grant_size) if (!bearer->grant_size) return; goto out; start_grant = bearer->grant_size; start_grant = bearer->grant_size; if (skb->len >= bearer->grant_size) if (len >= bearer->grant_size) bearer->grant_size = 0; bearer->grant_size = 0; else else bearer->grant_size -= skb->len; bearer->grant_size -= len; if (start_grant > bearer->grant_thresh && if (start_grant > bearer->grant_thresh && bearer->grant_size <= bearer->grant_thresh) { bearer->grant_size <= bearer->grant_thresh) { Loading @@ -1002,27 +920,9 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, DFC_ACK_TYPE_THRESHOLD); DFC_ACK_TYPE_THRESHOLD); } } if (bearer->grant_size) if (!bearer->grant_size) return; dfc_bearer_flow_ctl(dev, bearer, qos); data = (struct dfc_qmi_data *)qmi_rmnet_has_dfc_client(qmi); if (!data) return; dfc_ind = kzalloc(sizeof(*dfc_ind), GFP_ATOMIC); if (!dfc_ind) return; INIT_WORK((struct work_struct *)dfc_ind, dfc_bearer_limit_work); dfc_ind->dev = dev; dfc_ind->qos = qos; dfc_ind->bearer = bearer; dfc_ind->data = data; /* stop the flow in hope that the worker thread is out: * immediately scheduled beyond this point of time spin_unlock(&qos->qos_lock); */ netif_stop_queue(dev); queue_work(data->dfc_wq, (struct work_struct *)dfc_ind); } } drivers/soc/qcom/qmi_rmnet.c +71 −42 Original line number Original line Diff line number Diff line Loading @@ -26,8 +26,9 @@ #define NLMSG_CLIENT_SETUP 4 #define NLMSG_CLIENT_SETUP 4 #define NLMSG_CLIENT_DELETE 5 #define NLMSG_CLIENT_DELETE 5 #define FLAG_DFC_MASK 0x0001 #define FLAG_DFC_MASK 0x000F #define FLAG_POWERSAVE_MASK 0x0010 #define FLAG_POWERSAVE_MASK 0x0010 #define DFC_MODE_MULTIQ 2 #define PS_INTERVAL (0x0004 * HZ) #define PS_INTERVAL (0x0004 * HZ) #define NO_DELAY (0x0000 * HZ) #define NO_DELAY (0x0000 * HZ) Loading Loading @@ -69,22 +70,11 @@ struct qmi_elem_info data_ep_id_type_v01_ei[] = { }; }; EXPORT_SYMBOL(data_ep_id_type_v01_ei); EXPORT_SYMBOL(data_ep_id_type_v01_ei); static struct qmi_info *qmi_rmnet_qmi_init(void) { struct qmi_info *qmi_info; qmi_info = kzalloc(sizeof(*qmi_info), GFP_KERNEL); if (!qmi_info) return NULL; return qmi_info; } void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) { { int i; int i; if (!qmi || !(qmi->flag & FLAG_DFC_MASK)) if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ)) return NULL; return NULL; for (i = 0; i < MAX_CLIENT_NUM; i++) { for (i = 0; i < MAX_CLIENT_NUM; i++) { Loading Loading @@ -197,6 +187,25 @@ static void qmi_rmnet_update_flow_map(struct rmnet_flow_map *itm, itm->tcm_handle = new_map->tcm_handle; itm->tcm_handle = new_map->tcm_handle; } } int qmi_rmnet_flow_control(struct net_device *dev, u32 tcm_handle, int enable) { struct netdev_queue *q; if (unlikely(tcm_handle >= dev->num_tx_queues)) return 0; q = netdev_get_tx_queue(dev, tcm_handle); if (unlikely(!q)) return 0; if (enable) netif_tx_wake_queue(q); else netif_tx_stop_queue(q); return 0; } static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, struct qmi_info *qmi) struct qmi_info *qmi) { { Loading @@ -221,14 +230,18 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, trace_dfc_flow_info(new_map.bearer_id, new_map.flow_id, trace_dfc_flow_info(new_map.bearer_id, new_map.flow_id, new_map.ip_type, new_map.tcm_handle, 1); new_map.ip_type, new_map.tcm_handle, 1); spin_lock_bh(&qos_info->qos_lock); itm = qmi_rmnet_get_flow_map(qos_info, new_map.flow_id, itm = qmi_rmnet_get_flow_map(qos_info, new_map.flow_id, new_map.ip_type); new_map.ip_type); if (itm) { if (itm) { qmi_rmnet_update_flow_map(itm, &new_map); qmi_rmnet_update_flow_map(itm, &new_map); } else { } else { itm = kzalloc(sizeof(*itm), GFP_KERNEL); itm = kzalloc(sizeof(*itm), GFP_ATOMIC); if (!itm) if (!itm) { spin_unlock_bh(&qos_info->qos_lock); return -ENOMEM; return -ENOMEM; } qmi_rmnet_update_flow_link(qmi, dev, itm, 1); qmi_rmnet_update_flow_link(qmi, dev, itm, 1); qmi_rmnet_update_flow_map(itm, &new_map); qmi_rmnet_update_flow_map(itm, &new_map); Loading @@ -238,9 +251,11 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, if (bearer) { if (bearer) { bearer->flow_ref++; bearer->flow_ref++; } else { } else { bearer = kzalloc(sizeof(*bearer), GFP_KERNEL); bearer = kzalloc(sizeof(*bearer), GFP_ATOMIC); if (!bearer) if (!bearer) { spin_unlock_bh(&qos_info->qos_lock); return -ENOMEM; return -ENOMEM; } bearer->bearer_id = new_map.bearer_id; bearer->bearer_id = new_map.bearer_id; bearer->flow_ref = 1; bearer->flow_ref = 1; Loading @@ -251,10 +266,12 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, list_add(&bearer->list, &qos_info->bearer_head); list_add(&bearer->list, &qos_info->bearer_head); } } tc_qdisc_flow_control(dev, itm->tcm_handle, qmi_rmnet_flow_control(dev, itm->tcm_handle, bearer->grant_size > 0 ? 1 : 0); bearer->grant_size > 0 ? 1 : 0); } } spin_unlock_bh(&qos_info->qos_lock); return 0; return 0; } } Loading @@ -277,6 +294,8 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, * tcm->tcm_ifindex - ip_type * tcm->tcm_ifindex - ip_type */ */ spin_lock_bh(&qos_info->qos_lock); new_map.bearer_id = tcm->tcm__pad1; new_map.bearer_id = tcm->tcm__pad1; new_map.flow_id = tcm->tcm_parent; new_map.flow_id = tcm->tcm_parent; new_map.ip_type = tcm->tcm_ifindex; new_map.ip_type = tcm->tcm_ifindex; Loading @@ -300,6 +319,8 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, kfree(bearer); kfree(bearer); } } spin_unlock_bh(&qos_info->qos_lock); return 0; return 0; } } Loading @@ -309,7 +330,7 @@ static int qmi_rmnet_enable_all_flows(struct qmi_info *qmi) struct qos_info *qos; struct qos_info *qos; struct rmnet_flow_map *m; struct rmnet_flow_map *m; struct rmnet_bearer_map *bearer; struct rmnet_bearer_map *bearer; int qlen, need_enable = 0; int qlen; if (!qmi_rmnet_has_dfc_client(qmi) || (qmi->flow_cnt == 0)) if (!qmi_rmnet_has_dfc_client(qmi) || (qmi->flow_cnt == 0)) return 0; return 0; Loading @@ -319,21 +340,25 @@ static int qmi_rmnet_enable_all_flows(struct qmi_info *qmi) for (i = 0; i < qmi->flow_cnt; i++) { for (i = 0; i < qmi->flow_cnt; i++) { qos = (struct qos_info *)rmnet_get_qos_pt(qmi->flow[i].dev); qos = (struct qos_info *)rmnet_get_qos_pt(qmi->flow[i].dev); m = qmi->flow[i].itm; m = qmi->flow[i].itm; spin_lock_bh(&qos->qos_lock); bearer = qmi_rmnet_get_bearer_map(qos, m->bearer_id); bearer = qmi_rmnet_get_bearer_map(qos, m->bearer_id); if (bearer) { if (bearer) { if (bearer->grant_size == 0) need_enable = 1; bearer->grant_size = DEFAULT_GRANT; bearer->grant_size = DEFAULT_GRANT; bearer->grant_thresh = bearer->grant_thresh = qmi_rmnet_grant_per(DEFAULT_GRANT); qmi_rmnet_grant_per(DEFAULT_GRANT); if (need_enable) { bearer->seq = 0; qlen = tc_qdisc_flow_control(qmi->flow[i].dev, bearer->ack_req = 0; } qlen = qmi_rmnet_flow_control(qmi->flow[i].dev, m->tcm_handle, 1); m->tcm_handle, 1); trace_dfc_qmi_tc(m->bearer_id, m->flow_id, trace_dfc_qmi_tc(m->bearer_id, m->flow_id, bearer->grant_size, qlen, DEFAULT_GRANT, qlen, m->tcm_handle, 1); m->tcm_handle, 1); } } spin_unlock_bh(&qos->qos_lock); } } return 0; return 0; Loading Loading @@ -410,7 +435,7 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) idx = (tcm->tcm_handle == 0) ? 0 : 1; idx = (tcm->tcm_handle == 0) ? 0 : 1; if (!qmi) { if (!qmi) { qmi = qmi_rmnet_qmi_init(); qmi = kzalloc(sizeof(struct qmi_info), GFP_KERNEL); if (!qmi) if (!qmi) return -ENOMEM; return -ENOMEM; Loading @@ -422,7 +447,7 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) qmi->fc_info[idx].svc.ep_type = tcm->tcm_info; qmi->fc_info[idx].svc.ep_type = tcm->tcm_info; qmi->fc_info[idx].svc.iface_id = tcm->tcm_parent; qmi->fc_info[idx].svc.iface_id = tcm->tcm_parent; if ((tcm->tcm_ifindex & FLAG_DFC_MASK) && if (((tcm->tcm_ifindex & FLAG_DFC_MASK) == DFC_MODE_MULTIQ) && (qmi->fc_info[idx].dfc_client == NULL)) { (qmi->fc_info[idx].dfc_client == NULL)) { rc = dfc_qmi_client_init(port, idx, qmi); rc = dfc_qmi_client_init(port, idx, qmi); if (rc < 0) if (rc < 0) Loading Loading @@ -484,20 +509,20 @@ void qmi_rmnet_change_link(struct net_device *dev, void *port, void *tcm_pt) switch (tcm->tcm_family) { switch (tcm->tcm_family) { case NLMSG_FLOW_ACTIVATE: case NLMSG_FLOW_ACTIVATE: if (!qmi || !(qmi->flag & FLAG_DFC_MASK) || if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ) || !qmi_rmnet_has_dfc_client(qmi)) !qmi_rmnet_has_dfc_client(qmi)) return; return; qmi_rmnet_add_flow(dev, tcm, qmi); qmi_rmnet_add_flow(dev, tcm, qmi); break; break; case NLMSG_FLOW_DEACTIVATE: case NLMSG_FLOW_DEACTIVATE: if (!qmi || !(qmi->flag & FLAG_DFC_MASK)) if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ)) return; return; qmi_rmnet_del_flow(dev, tcm, qmi); qmi_rmnet_del_flow(dev, tcm, qmi); break; break; case NLMSG_CLIENT_SETUP: case NLMSG_CLIENT_SETUP: if (!(tcm->tcm_ifindex & FLAG_DFC_MASK) && if (((tcm->tcm_ifindex & FLAG_DFC_MASK) != DFC_MODE_MULTIQ) && !(tcm->tcm_ifindex & FLAG_POWERSAVE_MASK)) !(tcm->tcm_ifindex & FLAG_POWERSAVE_MASK)) return; return; Loading Loading @@ -553,16 +578,15 @@ void qmi_rmnet_qmi_exit(void *qmi_pt, void *port) EXPORT_SYMBOL(qmi_rmnet_qmi_exit); EXPORT_SYMBOL(qmi_rmnet_qmi_exit); #ifdef CONFIG_QCOM_QMI_DFC #ifdef CONFIG_QCOM_QMI_DFC void qmi_rmnet_burst_fc_check(struct net_device *dev, struct sk_buff *skb) void qmi_rmnet_burst_fc_check(struct net_device *dev, int ip_type, u32 mark, unsigned int len) { { void *port = rmnet_get_rmnet_port(dev); struct qmi_info *qmi = rmnet_get_qmi_pt(port); struct qos_info *qos = rmnet_get_qos_pt(dev); struct qos_info *qos = rmnet_get_qos_pt(dev); if (!qmi || !qos) if (!qos) return; return; dfc_qmi_burst_check(dev, qos, skb, qmi); dfc_qmi_burst_check(dev, qos, ip_type, mark, len); } } EXPORT_SYMBOL(qmi_rmnet_burst_fc_check); EXPORT_SYMBOL(qmi_rmnet_burst_fc_check); Loading @@ -586,21 +610,22 @@ void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) qos->tran_num = 0; qos->tran_num = 0; INIT_LIST_HEAD(&qos->flow_head); INIT_LIST_HEAD(&qos->flow_head); INIT_LIST_HEAD(&qos->bearer_head); INIT_LIST_HEAD(&qos->bearer_head); spin_lock_init(&qos->qos_lock); return qos; return qos; } } EXPORT_SYMBOL(qmi_rmnet_qos_init); EXPORT_SYMBOL(qmi_rmnet_qos_init); void qmi_rmnet_qos_exit(struct net_device *dev) void qmi_rmnet_qos_exit(struct net_device *dev, void *qos) { { void *port = rmnet_get_rmnet_port(dev); void *port = rmnet_get_rmnet_port(dev); struct qmi_info *qmi = rmnet_get_qmi_pt(port); struct qmi_info *qmi = rmnet_get_qmi_pt(port); struct qos_info *qos = (struct qos_info *)rmnet_get_qos_pt(dev); struct qos_info *qos_info = (struct qos_info *)qos; if (!qmi || !qos) if (!qmi || !qos) return; return; qmi_rmnet_clean_flow_list(qmi, dev, qos); qmi_rmnet_clean_flow_list(qmi, dev, qos_info); kfree(qos); kfree(qos); } } EXPORT_SYMBOL(qmi_rmnet_qos_exit); EXPORT_SYMBOL(qmi_rmnet_qos_exit); Loading Loading @@ -651,6 +676,7 @@ static void qmi_rmnet_check_stats(struct work_struct *work) struct rmnet_powersave_work *real_work; struct rmnet_powersave_work *real_work; u64 rxd, txd; u64 rxd, txd; u64 rx, tx; u64 rx, tx; unsigned long lock_delay; real_work = container_of(to_delayed_work(work), real_work = container_of(to_delayed_work(work), struct rmnet_powersave_work, work); struct rmnet_powersave_work, work); Loading @@ -658,8 +684,11 @@ static void qmi_rmnet_check_stats(struct work_struct *work) if (unlikely(!real_work || !real_work->port)) if (unlikely(!real_work || !real_work->port)) return; return; lock_delay = qmi_rmnet_work_get_active(real_work->port) ? PS_INTERVAL : (HZ / 50); if (!rtnl_trylock()) { if (!rtnl_trylock()) { queue_delayed_work(rmnet_ps_wq, &real_work->work, PS_INTERVAL); queue_delayed_work(rmnet_ps_wq, &real_work->work, lock_delay); return; return; } } if (!qmi_rmnet_work_get_active(real_work->port)) { if (!qmi_rmnet_work_get_active(real_work->port)) { Loading Loading
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +4 −8 Original line number Original line Diff line number Diff line Loading @@ -496,7 +496,8 @@ EXPORT_SYMBOL(rmnet_get_qmi_pt); void *rmnet_get_qos_pt(struct net_device *dev) void *rmnet_get_qos_pt(struct net_device *dev) { { if (dev) if (dev) return ((struct rmnet_priv *)netdev_priv(dev))->qos_info; return rcu_dereference( ((struct rmnet_priv *)netdev_priv(dev))->qos_info); return NULL; return NULL; } } Loading @@ -520,14 +521,9 @@ struct net_device *rmnet_get_rmnet_dev(void *port, u8 mux_id) struct rmnet_endpoint *ep; struct rmnet_endpoint *ep; if (port) { if (port) { struct net_device *dev; ep = rmnet_get_endpoint((struct rmnet_port *)port, mux_id); ep = rmnet_get_endpoint((struct rmnet_port *)port, mux_id); if (ep) { if (ep) dev = ep->egress_dev; return ep->egress_dev; return dev; } } } return NULL; return NULL; Loading
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -107,7 +107,7 @@ struct rmnet_priv { struct rmnet_pcpu_stats __percpu *pcpu_stats; struct rmnet_pcpu_stats __percpu *pcpu_stats; struct gro_cells gro_cells; struct gro_cells gro_cells; struct rmnet_priv_stats stats; struct rmnet_priv_stats stats; void *qos_info; void __rcu *qos_info; }; }; int rmnet_is_real_dev_registered(const struct net_device *real_dev); int rmnet_is_real_dev_registered(const struct net_device *real_dev); Loading
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +23 −3 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/etherdevice.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> #include <linux/if_arp.h> #include <linux/ip.h> #include <net/pkt_sched.h> #include <net/pkt_sched.h> #include "rmnet_config.h" #include "rmnet_config.h" #include "rmnet_handlers.h" #include "rmnet_handlers.h" Loading Loading @@ -61,12 +62,19 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, struct net_device *dev) struct net_device *dev) { { struct rmnet_priv *priv; struct rmnet_priv *priv; int ip_type; u32 mark; unsigned int len; priv = netdev_priv(dev); priv = netdev_priv(dev); if (priv->real_dev) { if (priv->real_dev) { ip_type = (ip_hdr(skb)->version == 4) ? AF_INET : AF_INET6; mark = skb->mark; len = skb->len; trace_rmnet_xmit_skb(skb); trace_rmnet_xmit_skb(skb); qmi_rmnet_burst_fc_check(dev, skb); rmnet_egress_handler(skb); rmnet_egress_handler(skb); qmi_rmnet_burst_fc_check(dev, ip_type, mark, len); } else { } else { this_cpu_inc(priv->pcpu_stats->stats.tx_drops); this_cpu_inc(priv->pcpu_stats->stats.tx_drops); kfree_skb(skb); kfree_skb(skb); Loading Loading @@ -111,12 +119,15 @@ static int rmnet_vnd_init(struct net_device *dev) static void rmnet_vnd_uninit(struct net_device *dev) static void rmnet_vnd_uninit(struct net_device *dev) { { struct rmnet_priv *priv = netdev_priv(dev); struct rmnet_priv *priv = netdev_priv(dev); void *qos; gro_cells_destroy(&priv->gro_cells); gro_cells_destroy(&priv->gro_cells); free_percpu(priv->pcpu_stats); free_percpu(priv->pcpu_stats); qmi_rmnet_qos_exit(dev); qos = priv->qos_info; priv->qos_info = NULL; RCU_INIT_POINTER(priv->qos_info, NULL); synchronize_rcu(); qmi_rmnet_qos_exit(dev, qos); } } static void rmnet_get_stats64(struct net_device *dev, static void rmnet_get_stats64(struct net_device *dev, Loading Loading @@ -150,6 +161,14 @@ static void rmnet_get_stats64(struct net_device *dev, s->tx_dropped = total_stats.tx_drops; s->tx_dropped = total_stats.tx_drops; } } static u16 rmnet_vnd_select_queue(struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { return 0; } static const struct net_device_ops rmnet_vnd_ops = { static const struct net_device_ops rmnet_vnd_ops = { .ndo_start_xmit = rmnet_vnd_start_xmit, .ndo_start_xmit = rmnet_vnd_start_xmit, .ndo_change_mtu = rmnet_vnd_change_mtu, .ndo_change_mtu = rmnet_vnd_change_mtu, Loading @@ -159,6 +178,7 @@ static const struct net_device_ops rmnet_vnd_ops = { .ndo_init = rmnet_vnd_init, .ndo_init = rmnet_vnd_init, .ndo_uninit = rmnet_vnd_uninit, .ndo_uninit = rmnet_vnd_uninit, .ndo_get_stats64 = rmnet_get_stats64, .ndo_get_stats64 = rmnet_get_stats64, .ndo_select_queue = rmnet_vnd_select_queue, }; }; static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = { static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = { Loading
drivers/soc/qcom/dfc_qmi.c +40 −140 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,6 @@ #include <linux/soc/qcom/qmi.h> #include <linux/soc/qcom/qmi.h> #include <soc/qcom/rmnet_qmi.h> #include <soc/qcom/rmnet_qmi.h> #include <linux/ip.h> #include "qmi_rmnet_i.h" #include "qmi_rmnet_i.h" #define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS #include <trace/events/dfc.h> #include <trace/events/dfc.h> Loading Loading @@ -61,20 +60,6 @@ struct dfc_qmi_data { int restart_state; int restart_state; }; }; struct dfc_svc_ind { struct work_struct work; struct dfc_qmi_data *data; void *dfc_info; }; struct dfc_burst_ind { struct work_struct work; struct net_device *dev; struct qos_info *qos; struct rmnet_bearer_map *bearer; struct dfc_qmi_data *data; }; static void dfc_svc_init(struct work_struct *work); static void dfc_svc_init(struct work_struct *work); static void dfc_do_burst_flow_control(struct work_struct *work); static void dfc_do_burst_flow_control(struct work_struct *work); Loading Loading @@ -257,6 +242,12 @@ struct dfc_flow_status_ind_msg_v01 { u8 eod_ack_reqd; u8 eod_ack_reqd; }; }; struct dfc_svc_ind { struct work_struct work; struct dfc_qmi_data *data; struct dfc_flow_status_ind_msg_v01 dfc_info; }; static struct qmi_elem_info dfc_bind_client_req_msg_v01_ei[] = { static struct qmi_elem_info dfc_bind_client_req_msg_v01_ei[] = { { { .data_type = QMI_OPT_FLAG, .data_type = QMI_OPT_FLAG, Loading Loading @@ -596,7 +587,7 @@ static int dfc_bearer_flow_ctl(struct net_device *dev, itm = list_entry(p, struct rmnet_flow_map, list); itm = list_entry(p, struct rmnet_flow_map, list); if (itm->bearer_id == bearer->bearer_id) { if (itm->bearer_id == bearer->bearer_id) { qlen = tc_qdisc_flow_control(dev, itm->tcm_handle, qlen = qmi_rmnet_flow_control(dev, itm->tcm_handle, enable); enable); trace_dfc_qmi_tc(itm->bearer_id, itm->flow_id, trace_dfc_qmi_tc(itm->bearer_id, itm->flow_id, bearer->grant_size, qlen, bearer->grant_size, qlen, Loading @@ -618,10 +609,9 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, struct dfc_flow_status_info_type_v01 *fc_info) struct dfc_flow_status_info_type_v01 *fc_info) { { struct list_head *p; struct list_head *p; struct rmnet_flow_map *flow_itm; struct rmnet_bearer_map *bearer_itm = NULL; struct rmnet_bearer_map *bearer_itm; int enable; int enable; int rc = 0, len; int rc = 0; list_for_each(p, &qos->bearer_head) { list_for_each(p, &qos->bearer_head) { bearer_itm = list_entry(p, struct rmnet_bearer_map, list); bearer_itm = list_entry(p, struct rmnet_bearer_map, list); Loading @@ -635,15 +625,12 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, enable = fc_info->num_bytes > 0 ? 1 : 0; enable = fc_info->num_bytes > 0 ? 1 : 0; list_for_each(p, &qos->flow_head) { if (enable) flow_itm = list_entry(p, struct rmnet_flow_map, list); netif_tx_wake_all_queues(dev); else netif_tx_stop_all_queues(dev); len = tc_qdisc_flow_control(dev, flow_itm->tcm_handle, enable); trace_dfc_qmi_tc(0xFF, 0, fc_info->num_bytes, 0, 0, enable); trace_dfc_qmi_tc(flow_itm->bearer_id, flow_itm->flow_id, fc_info->num_bytes, len, flow_itm->tcm_handle, enable); rc++; } if (enable == 0 && ack_req) if (enable == 0 && ack_req) dfc_send_ack(dev, fc_info->bearer_id, dfc_send_ack(dev, fc_info->bearer_id, Loading Loading @@ -686,31 +673,19 @@ static void dfc_do_burst_flow_control(struct work_struct *work) { { struct dfc_svc_ind *svc_ind = (struct dfc_svc_ind *)work; struct dfc_svc_ind *svc_ind = (struct dfc_svc_ind *)work; struct dfc_flow_status_ind_msg_v01 *ind = struct dfc_flow_status_ind_msg_v01 *ind = (struct dfc_flow_status_ind_msg_v01 *)svc_ind->dfc_info; (struct dfc_flow_status_ind_msg_v01 *)&svc_ind->dfc_info; struct net_device *dev; struct net_device *dev; struct qos_info *qos; struct qos_info *qos; struct dfc_flow_status_info_type_v01 *flow_status; struct dfc_flow_status_info_type_v01 *flow_status; u8 ack_req = ind->eod_ack_reqd_valid ? ind->eod_ack_reqd : 0; u8 ack_req = ind->eod_ack_reqd_valid ? ind->eod_ack_reqd : 0; int i, rc; int i; if (!svc_ind->data->rmnet_port) { kfree(ind); kfree(svc_ind); return; } while (!rtnl_trylock()) { if (unlikely(svc_ind->data->restart_state)) { if (!svc_ind->data->restart_state) { cond_resched(); } else { kfree(ind); kfree(svc_ind); kfree(svc_ind); return; return; } } } if (unlikely(svc_ind->data->restart_state)) rcu_read_lock(); goto clean_out; for (i = 0; i < ind->flow_status_len; i++) { for (i = 0; i < ind->flow_status_len; i++) { flow_status = &ind->flow_status[i]; flow_status = &ind->flow_status[i]; Loading @@ -729,67 +704,20 @@ static void dfc_do_burst_flow_control(struct work_struct *work) if (!qos) if (!qos) continue; continue; spin_lock_bh(&qos->qos_lock); if (unlikely(flow_status->bearer_id == 0xFF)) if (unlikely(flow_status->bearer_id == 0xFF)) rc = dfc_all_bearer_flow_ctl( dfc_all_bearer_flow_ctl( dev, qos, ack_req, flow_status); dev, qos, ack_req, flow_status); else else rc = dfc_update_fc_map(dev, qos, ack_req, flow_status); dfc_update_fc_map(dev, qos, ack_req, flow_status); spin_unlock_bh(&qos->qos_lock); } } clean_out: clean_out: kfree(ind); rcu_read_unlock(); kfree(svc_ind); kfree(svc_ind); rtnl_unlock(); } static void dfc_bearer_limit_work(struct work_struct *work) { struct dfc_burst_ind *dfc_ind = (struct dfc_burst_ind *)work; struct rmnet_flow_map *itm; struct list_head *p; int qlen, fc; /* enable transmit on device so that the other * flows which transmit proceed normally. */ netif_start_queue(dfc_ind->dev); while (!rtnl_trylock()) { if (!dfc_ind->data->restart_state) { cond_resched(); } else { kfree(dfc_ind); return; } } fc = dfc_ind->bearer->grant_size ? 1 : 0; /* if grant size is non zero here, we must have already * got an updated grant. do nothing in that case */ if (fc) goto done; list_for_each(p, &dfc_ind->qos->flow_head) { itm = list_entry(p, struct rmnet_flow_map, list); if (itm->bearer_id == dfc_ind->bearer->bearer_id) { qlen = tc_qdisc_flow_control(dfc_ind->dev, itm->tcm_handle, fc); trace_dfc_qmi_tc_limit(itm->bearer_id, itm->flow_id, dfc_ind->bearer->grant_size, qlen, itm->tcm_handle, fc); } } if (dfc_ind->bearer->ack_req) dfc_send_ack(dfc_ind->dev, dfc_ind->bearer->bearer_id, dfc_ind->bearer->seq, dfc_ind->qos->mux_id, DFC_ACK_TYPE_DISABLE); done: kfree(dfc_ind); rtnl_unlock(); } } static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, Loading @@ -800,9 +728,6 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct dfc_flow_status_ind_msg_v01 *ind_msg; struct dfc_flow_status_ind_msg_v01 *ind_msg; struct dfc_svc_ind *svc_ind; struct dfc_svc_ind *svc_ind; if (!dfc->rmnet_port) return; if (qmi != &dfc->handle) if (qmi != &dfc->handle) return; return; Loading @@ -820,14 +745,10 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, INIT_WORK((struct work_struct *)svc_ind, INIT_WORK((struct work_struct *)svc_ind, dfc_do_burst_flow_control); dfc_do_burst_flow_control); svc_ind->dfc_info = kzalloc(sizeof(*ind_msg), GFP_ATOMIC); if (!svc_ind->dfc_info) { kfree(svc_ind); return; } memcpy(svc_ind->dfc_info, ind_msg, sizeof(*ind_msg)); memcpy(&svc_ind->dfc_info, ind_msg, sizeof(*ind_msg)); svc_ind->data = dfc; svc_ind->data = dfc; queue_work(dfc->dfc_wq, (struct work_struct *)svc_ind); queue_work(dfc->dfc_wq, (struct work_struct *)svc_ind); } } } } Loading Loading @@ -965,35 +886,32 @@ void dfc_qmi_client_exit(void *dfc_data) } } void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, struct sk_buff *skb, struct qmi_info *qmi) int ip_type, u32 mark, unsigned int len) { { struct rmnet_bearer_map *bearer; struct rmnet_bearer_map *bearer; struct dfc_burst_ind *dfc_ind; struct rmnet_flow_map *itm; struct rmnet_flow_map *itm; struct dfc_qmi_data *data; int ip_type; u32 start_grant; u32 start_grant; ip_type = (ip_hdr(skb)->version == IP_VER_6) ? AF_INET6 : AF_INET; spin_lock(&qos->qos_lock); itm = qmi_rmnet_get_flow_map(qos, skb->mark, ip_type); itm = qmi_rmnet_get_flow_map(qos, mark, ip_type); if (unlikely(!itm)) if (unlikely(!itm)) return; goto out; bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); bearer = qmi_rmnet_get_bearer_map(qos, itm->bearer_id); if (unlikely(!bearer)) if (unlikely(!bearer)) return; goto out; trace_dfc_flow_check(bearer->bearer_id, skb->len, bearer->grant_size); trace_dfc_flow_check(bearer->bearer_id, len, bearer->grant_size); if (!bearer->grant_size) if (!bearer->grant_size) return; goto out; start_grant = bearer->grant_size; start_grant = bearer->grant_size; if (skb->len >= bearer->grant_size) if (len >= bearer->grant_size) bearer->grant_size = 0; bearer->grant_size = 0; else else bearer->grant_size -= skb->len; bearer->grant_size -= len; if (start_grant > bearer->grant_thresh && if (start_grant > bearer->grant_thresh && bearer->grant_size <= bearer->grant_thresh) { bearer->grant_size <= bearer->grant_thresh) { Loading @@ -1002,27 +920,9 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, DFC_ACK_TYPE_THRESHOLD); DFC_ACK_TYPE_THRESHOLD); } } if (bearer->grant_size) if (!bearer->grant_size) return; dfc_bearer_flow_ctl(dev, bearer, qos); data = (struct dfc_qmi_data *)qmi_rmnet_has_dfc_client(qmi); if (!data) return; dfc_ind = kzalloc(sizeof(*dfc_ind), GFP_ATOMIC); if (!dfc_ind) return; INIT_WORK((struct work_struct *)dfc_ind, dfc_bearer_limit_work); dfc_ind->dev = dev; dfc_ind->qos = qos; dfc_ind->bearer = bearer; dfc_ind->data = data; /* stop the flow in hope that the worker thread is out: * immediately scheduled beyond this point of time spin_unlock(&qos->qos_lock); */ netif_stop_queue(dev); queue_work(data->dfc_wq, (struct work_struct *)dfc_ind); } }
drivers/soc/qcom/qmi_rmnet.c +71 −42 Original line number Original line Diff line number Diff line Loading @@ -26,8 +26,9 @@ #define NLMSG_CLIENT_SETUP 4 #define NLMSG_CLIENT_SETUP 4 #define NLMSG_CLIENT_DELETE 5 #define NLMSG_CLIENT_DELETE 5 #define FLAG_DFC_MASK 0x0001 #define FLAG_DFC_MASK 0x000F #define FLAG_POWERSAVE_MASK 0x0010 #define FLAG_POWERSAVE_MASK 0x0010 #define DFC_MODE_MULTIQ 2 #define PS_INTERVAL (0x0004 * HZ) #define PS_INTERVAL (0x0004 * HZ) #define NO_DELAY (0x0000 * HZ) #define NO_DELAY (0x0000 * HZ) Loading Loading @@ -69,22 +70,11 @@ struct qmi_elem_info data_ep_id_type_v01_ei[] = { }; }; EXPORT_SYMBOL(data_ep_id_type_v01_ei); EXPORT_SYMBOL(data_ep_id_type_v01_ei); static struct qmi_info *qmi_rmnet_qmi_init(void) { struct qmi_info *qmi_info; qmi_info = kzalloc(sizeof(*qmi_info), GFP_KERNEL); if (!qmi_info) return NULL; return qmi_info; } void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) { { int i; int i; if (!qmi || !(qmi->flag & FLAG_DFC_MASK)) if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ)) return NULL; return NULL; for (i = 0; i < MAX_CLIENT_NUM; i++) { for (i = 0; i < MAX_CLIENT_NUM; i++) { Loading Loading @@ -197,6 +187,25 @@ static void qmi_rmnet_update_flow_map(struct rmnet_flow_map *itm, itm->tcm_handle = new_map->tcm_handle; itm->tcm_handle = new_map->tcm_handle; } } int qmi_rmnet_flow_control(struct net_device *dev, u32 tcm_handle, int enable) { struct netdev_queue *q; if (unlikely(tcm_handle >= dev->num_tx_queues)) return 0; q = netdev_get_tx_queue(dev, tcm_handle); if (unlikely(!q)) return 0; if (enable) netif_tx_wake_queue(q); else netif_tx_stop_queue(q); return 0; } static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, struct qmi_info *qmi) struct qmi_info *qmi) { { Loading @@ -221,14 +230,18 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, trace_dfc_flow_info(new_map.bearer_id, new_map.flow_id, trace_dfc_flow_info(new_map.bearer_id, new_map.flow_id, new_map.ip_type, new_map.tcm_handle, 1); new_map.ip_type, new_map.tcm_handle, 1); spin_lock_bh(&qos_info->qos_lock); itm = qmi_rmnet_get_flow_map(qos_info, new_map.flow_id, itm = qmi_rmnet_get_flow_map(qos_info, new_map.flow_id, new_map.ip_type); new_map.ip_type); if (itm) { if (itm) { qmi_rmnet_update_flow_map(itm, &new_map); qmi_rmnet_update_flow_map(itm, &new_map); } else { } else { itm = kzalloc(sizeof(*itm), GFP_KERNEL); itm = kzalloc(sizeof(*itm), GFP_ATOMIC); if (!itm) if (!itm) { spin_unlock_bh(&qos_info->qos_lock); return -ENOMEM; return -ENOMEM; } qmi_rmnet_update_flow_link(qmi, dev, itm, 1); qmi_rmnet_update_flow_link(qmi, dev, itm, 1); qmi_rmnet_update_flow_map(itm, &new_map); qmi_rmnet_update_flow_map(itm, &new_map); Loading @@ -238,9 +251,11 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, if (bearer) { if (bearer) { bearer->flow_ref++; bearer->flow_ref++; } else { } else { bearer = kzalloc(sizeof(*bearer), GFP_KERNEL); bearer = kzalloc(sizeof(*bearer), GFP_ATOMIC); if (!bearer) if (!bearer) { spin_unlock_bh(&qos_info->qos_lock); return -ENOMEM; return -ENOMEM; } bearer->bearer_id = new_map.bearer_id; bearer->bearer_id = new_map.bearer_id; bearer->flow_ref = 1; bearer->flow_ref = 1; Loading @@ -251,10 +266,12 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, list_add(&bearer->list, &qos_info->bearer_head); list_add(&bearer->list, &qos_info->bearer_head); } } tc_qdisc_flow_control(dev, itm->tcm_handle, qmi_rmnet_flow_control(dev, itm->tcm_handle, bearer->grant_size > 0 ? 1 : 0); bearer->grant_size > 0 ? 1 : 0); } } spin_unlock_bh(&qos_info->qos_lock); return 0; return 0; } } Loading @@ -277,6 +294,8 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, * tcm->tcm_ifindex - ip_type * tcm->tcm_ifindex - ip_type */ */ spin_lock_bh(&qos_info->qos_lock); new_map.bearer_id = tcm->tcm__pad1; new_map.bearer_id = tcm->tcm__pad1; new_map.flow_id = tcm->tcm_parent; new_map.flow_id = tcm->tcm_parent; new_map.ip_type = tcm->tcm_ifindex; new_map.ip_type = tcm->tcm_ifindex; Loading @@ -300,6 +319,8 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, kfree(bearer); kfree(bearer); } } spin_unlock_bh(&qos_info->qos_lock); return 0; return 0; } } Loading @@ -309,7 +330,7 @@ static int qmi_rmnet_enable_all_flows(struct qmi_info *qmi) struct qos_info *qos; struct qos_info *qos; struct rmnet_flow_map *m; struct rmnet_flow_map *m; struct rmnet_bearer_map *bearer; struct rmnet_bearer_map *bearer; int qlen, need_enable = 0; int qlen; if (!qmi_rmnet_has_dfc_client(qmi) || (qmi->flow_cnt == 0)) if (!qmi_rmnet_has_dfc_client(qmi) || (qmi->flow_cnt == 0)) return 0; return 0; Loading @@ -319,21 +340,25 @@ static int qmi_rmnet_enable_all_flows(struct qmi_info *qmi) for (i = 0; i < qmi->flow_cnt; i++) { for (i = 0; i < qmi->flow_cnt; i++) { qos = (struct qos_info *)rmnet_get_qos_pt(qmi->flow[i].dev); qos = (struct qos_info *)rmnet_get_qos_pt(qmi->flow[i].dev); m = qmi->flow[i].itm; m = qmi->flow[i].itm; spin_lock_bh(&qos->qos_lock); bearer = qmi_rmnet_get_bearer_map(qos, m->bearer_id); bearer = qmi_rmnet_get_bearer_map(qos, m->bearer_id); if (bearer) { if (bearer) { if (bearer->grant_size == 0) need_enable = 1; bearer->grant_size = DEFAULT_GRANT; bearer->grant_size = DEFAULT_GRANT; bearer->grant_thresh = bearer->grant_thresh = qmi_rmnet_grant_per(DEFAULT_GRANT); qmi_rmnet_grant_per(DEFAULT_GRANT); if (need_enable) { bearer->seq = 0; qlen = tc_qdisc_flow_control(qmi->flow[i].dev, bearer->ack_req = 0; } qlen = qmi_rmnet_flow_control(qmi->flow[i].dev, m->tcm_handle, 1); m->tcm_handle, 1); trace_dfc_qmi_tc(m->bearer_id, m->flow_id, trace_dfc_qmi_tc(m->bearer_id, m->flow_id, bearer->grant_size, qlen, DEFAULT_GRANT, qlen, m->tcm_handle, 1); m->tcm_handle, 1); } } spin_unlock_bh(&qos->qos_lock); } } return 0; return 0; Loading Loading @@ -410,7 +435,7 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) idx = (tcm->tcm_handle == 0) ? 0 : 1; idx = (tcm->tcm_handle == 0) ? 0 : 1; if (!qmi) { if (!qmi) { qmi = qmi_rmnet_qmi_init(); qmi = kzalloc(sizeof(struct qmi_info), GFP_KERNEL); if (!qmi) if (!qmi) return -ENOMEM; return -ENOMEM; Loading @@ -422,7 +447,7 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) qmi->fc_info[idx].svc.ep_type = tcm->tcm_info; qmi->fc_info[idx].svc.ep_type = tcm->tcm_info; qmi->fc_info[idx].svc.iface_id = tcm->tcm_parent; qmi->fc_info[idx].svc.iface_id = tcm->tcm_parent; if ((tcm->tcm_ifindex & FLAG_DFC_MASK) && if (((tcm->tcm_ifindex & FLAG_DFC_MASK) == DFC_MODE_MULTIQ) && (qmi->fc_info[idx].dfc_client == NULL)) { (qmi->fc_info[idx].dfc_client == NULL)) { rc = dfc_qmi_client_init(port, idx, qmi); rc = dfc_qmi_client_init(port, idx, qmi); if (rc < 0) if (rc < 0) Loading Loading @@ -484,20 +509,20 @@ void qmi_rmnet_change_link(struct net_device *dev, void *port, void *tcm_pt) switch (tcm->tcm_family) { switch (tcm->tcm_family) { case NLMSG_FLOW_ACTIVATE: case NLMSG_FLOW_ACTIVATE: if (!qmi || !(qmi->flag & FLAG_DFC_MASK) || if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ) || !qmi_rmnet_has_dfc_client(qmi)) !qmi_rmnet_has_dfc_client(qmi)) return; return; qmi_rmnet_add_flow(dev, tcm, qmi); qmi_rmnet_add_flow(dev, tcm, qmi); break; break; case NLMSG_FLOW_DEACTIVATE: case NLMSG_FLOW_DEACTIVATE: if (!qmi || !(qmi->flag & FLAG_DFC_MASK)) if (!qmi || ((qmi->flag & FLAG_DFC_MASK) != DFC_MODE_MULTIQ)) return; return; qmi_rmnet_del_flow(dev, tcm, qmi); qmi_rmnet_del_flow(dev, tcm, qmi); break; break; case NLMSG_CLIENT_SETUP: case NLMSG_CLIENT_SETUP: if (!(tcm->tcm_ifindex & FLAG_DFC_MASK) && if (((tcm->tcm_ifindex & FLAG_DFC_MASK) != DFC_MODE_MULTIQ) && !(tcm->tcm_ifindex & FLAG_POWERSAVE_MASK)) !(tcm->tcm_ifindex & FLAG_POWERSAVE_MASK)) return; return; Loading Loading @@ -553,16 +578,15 @@ void qmi_rmnet_qmi_exit(void *qmi_pt, void *port) EXPORT_SYMBOL(qmi_rmnet_qmi_exit); EXPORT_SYMBOL(qmi_rmnet_qmi_exit); #ifdef CONFIG_QCOM_QMI_DFC #ifdef CONFIG_QCOM_QMI_DFC void qmi_rmnet_burst_fc_check(struct net_device *dev, struct sk_buff *skb) void qmi_rmnet_burst_fc_check(struct net_device *dev, int ip_type, u32 mark, unsigned int len) { { void *port = rmnet_get_rmnet_port(dev); struct qmi_info *qmi = rmnet_get_qmi_pt(port); struct qos_info *qos = rmnet_get_qos_pt(dev); struct qos_info *qos = rmnet_get_qos_pt(dev); if (!qmi || !qos) if (!qos) return; return; dfc_qmi_burst_check(dev, qos, skb, qmi); dfc_qmi_burst_check(dev, qos, ip_type, mark, len); } } EXPORT_SYMBOL(qmi_rmnet_burst_fc_check); EXPORT_SYMBOL(qmi_rmnet_burst_fc_check); Loading @@ -586,21 +610,22 @@ void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) qos->tran_num = 0; qos->tran_num = 0; INIT_LIST_HEAD(&qos->flow_head); INIT_LIST_HEAD(&qos->flow_head); INIT_LIST_HEAD(&qos->bearer_head); INIT_LIST_HEAD(&qos->bearer_head); spin_lock_init(&qos->qos_lock); return qos; return qos; } } EXPORT_SYMBOL(qmi_rmnet_qos_init); EXPORT_SYMBOL(qmi_rmnet_qos_init); void qmi_rmnet_qos_exit(struct net_device *dev) void qmi_rmnet_qos_exit(struct net_device *dev, void *qos) { { void *port = rmnet_get_rmnet_port(dev); void *port = rmnet_get_rmnet_port(dev); struct qmi_info *qmi = rmnet_get_qmi_pt(port); struct qmi_info *qmi = rmnet_get_qmi_pt(port); struct qos_info *qos = (struct qos_info *)rmnet_get_qos_pt(dev); struct qos_info *qos_info = (struct qos_info *)qos; if (!qmi || !qos) if (!qmi || !qos) return; return; qmi_rmnet_clean_flow_list(qmi, dev, qos); qmi_rmnet_clean_flow_list(qmi, dev, qos_info); kfree(qos); kfree(qos); } } EXPORT_SYMBOL(qmi_rmnet_qos_exit); EXPORT_SYMBOL(qmi_rmnet_qos_exit); Loading Loading @@ -651,6 +676,7 @@ static void qmi_rmnet_check_stats(struct work_struct *work) struct rmnet_powersave_work *real_work; struct rmnet_powersave_work *real_work; u64 rxd, txd; u64 rxd, txd; u64 rx, tx; u64 rx, tx; unsigned long lock_delay; real_work = container_of(to_delayed_work(work), real_work = container_of(to_delayed_work(work), struct rmnet_powersave_work, work); struct rmnet_powersave_work, work); Loading @@ -658,8 +684,11 @@ static void qmi_rmnet_check_stats(struct work_struct *work) if (unlikely(!real_work || !real_work->port)) if (unlikely(!real_work || !real_work->port)) return; return; lock_delay = qmi_rmnet_work_get_active(real_work->port) ? PS_INTERVAL : (HZ / 50); if (!rtnl_trylock()) { if (!rtnl_trylock()) { queue_delayed_work(rmnet_ps_wq, &real_work->work, PS_INTERVAL); queue_delayed_work(rmnet_ps_wq, &real_work->work, lock_delay); return; return; } } if (!qmi_rmnet_work_get_active(real_work->port)) { if (!qmi_rmnet_work_get_active(real_work->port)) { Loading