Loading drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +24 −0 Original line number Diff line number Diff line Loading @@ -610,6 +610,30 @@ void rmnet_enable_all_flows(void *port) } EXPORT_SYMBOL(rmnet_enable_all_flows); bool rmnet_all_flows_enabled(void *port) { struct rmnet_endpoint *ep; unsigned long bkt; bool ret = true; if (unlikely(!port)) return true; rcu_read_lock(); hash_for_each_rcu(((struct rmnet_port *)port)->muxed_ep, bkt, ep, hlnode) { if (!qmi_rmnet_all_flows_enabled(ep->egress_dev)) { ret = false; goto out; } } out: rcu_read_unlock(); return ret; } EXPORT_SYMBOL(rmnet_all_flows_enabled); int rmnet_get_powersave_notif(void *port) { if (!port) Loading drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +1 −3 Original line number Diff line number Diff line Loading @@ -219,6 +219,7 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, qmap = (struct rmnet_map_header *)rmnet_map_data_ptr(skb); if (qmap->cd_bit) { qmi_rmnet_set_dl_msg_active(port); if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER) { if (!rmnet_map_flow_command(skb, port, false)) return; Loading Loading @@ -349,9 +350,6 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, return -ENOMEM; } if (port->data_format & RMNET_INGRESS_FORMAT_PS) qmi_rmnet_work_maybe_restart(port); if (csum_type) rmnet_map_checksum_uplink_packet(skb, orig_dev, csum_type); Loading drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +2 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "rmnet_vnd.h" #include <soc/qcom/qmi_rmnet.h> #include <soc/qcom/rmnet_qmi.h> #define CREATE_TRACE_POINTS #include <trace/events/rmnet.h> Loading Loading @@ -75,6 +76,7 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, trace_rmnet_xmit_skb(skb); rmnet_egress_handler(skb); qmi_rmnet_burst_fc_check(dev, ip_type, mark, len); qmi_rmnet_work_maybe_restart(rmnet_get_rmnet_port(dev)); } else { this_cpu_inc(priv->pcpu_stats->stats.tx_drops); kfree_skb(skb); Loading drivers/soc/qcom/dfc_qmi.c +29 −9 Original line number Diff line number Diff line Loading @@ -15,11 +15,17 @@ #include <net/pkt_sched.h> #include <linux/soc/qcom/qmi.h> #include <soc/qcom/rmnet_qmi.h> #include <soc/qcom/qmi_rmnet.h> #include "qmi_rmnet_i.h" #define CREATE_TRACE_POINTS #include <trace/events/dfc.h> #define DFC_MASK_TCP_BIDIR 0x1 #define DFC_MASK_RAT_SWITCH 0x2 #define DFC_IS_TCP_BIDIR(r) (bool)((r) & DFC_MASK_TCP_BIDIR) #define DFC_IS_RAT_SWITCH(r) (bool)((r) & DFC_MASK_RAT_SWITCH) #define DFC_IS_ANCILLARY(type) ((type) != AF_INET && (type) != AF_INET6) #define DFC_MAX_QOS_ID_V01 2 Loading Loading @@ -851,7 +857,7 @@ static int dfc_bearer_flow_ctl(struct net_device *dev, /* * Do not flow disable ancillary q if ancillary is true */ if (bearer->ancillary && enable == 0 && if (bearer->tcp_bidir && enable == 0 && DFC_IS_ANCILLARY(itm->ip_type)) continue; Loading Loading @@ -889,7 +895,9 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, qmi_rmnet_grant_per(bearer_itm->grant_size); bearer_itm->seq = fc_info->seq_num; bearer_itm->ack_req = ack_req; bearer_itm->ancillary = ancillary; bearer_itm->tcp_bidir = DFC_IS_TCP_BIDIR(ancillary); bearer_itm->last_grant = fc_info->num_bytes; bearer_itm->last_seq = fc_info->seq_num; } list_for_each_entry(flow_itm, &qos->flow_head, list) { Loading @@ -915,22 +923,32 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, { struct rmnet_bearer_map *itm = NULL; int rc = 0; int action = -1; bool action = false; itm = qmi_rmnet_get_bearer_map(qos, fc_info->bearer_id); if (itm) { 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; /* The RAT switch flag indicates the start and end of * the switch. Ignore indications in between. */ if (DFC_IS_RAT_SWITCH(ancillary)) itm->rat_switch = !fc_info->num_bytes; else if (itm->rat_switch) return 0; if ((itm->grant_size == 0 && fc_info->num_bytes > 0) || (itm->grant_size > 0 && fc_info->num_bytes == 0)) action = true; itm->grant_size = fc_info->num_bytes; itm->grant_thresh = qmi_rmnet_grant_per(itm->grant_size); itm->seq = fc_info->seq_num; itm->ack_req = ack_req; itm->ancillary = ancillary; itm->tcp_bidir = DFC_IS_TCP_BIDIR(ancillary); itm->last_grant = fc_info->num_bytes; itm->last_seq = fc_info->seq_num; if (action != -1) if (action) rc = dfc_bearer_flow_ctl(dev, itm, qos); } else { pr_debug("grant %u before flow activate", fc_info->num_bytes); Loading Loading @@ -1029,6 +1047,8 @@ static void dfc_qmi_ind_work(struct work_struct *work) } while (svc_ind != NULL); local_bh_enable(); qmi_rmnet_set_dl_msg_active(dfc->rmnet_port); } static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, Loading drivers/soc/qcom/qmi_rmnet.c +62 −16 Original line number Diff line number Diff line Loading @@ -575,7 +575,7 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev) { struct qos_info *qos; struct rmnet_bearer_map *bearer; int do_wake = 0; bool do_wake = false; qos = (struct qos_info *)rmnet_get_qos_pt(dev); if (!qos) Loading @@ -584,14 +584,14 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev) spin_lock_bh(&qos->qos_lock); list_for_each_entry(bearer, &qos->bearer_head, list) { bearer->grant_before_ps = bearer->grant_size; bearer->seq_before_ps = bearer->seq; if (!bearer->grant_size) do_wake = true; bearer->grant_size = DEFAULT_GRANT; bearer->grant_thresh = DEFAULT_GRANT; bearer->seq = 0; bearer->ack_req = 0; bearer->ancillary = 0; do_wake = 1; bearer->tcp_bidir = false; bearer->rat_switch = false; } if (do_wake) { Loading @@ -603,6 +603,31 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev) } EXPORT_SYMBOL(qmi_rmnet_enable_all_flows); bool qmi_rmnet_all_flows_enabled(struct net_device *dev) { struct qos_info *qos; struct rmnet_bearer_map *bearer; bool ret = true; qos = (struct qos_info *)rmnet_get_qos_pt(dev); if (!qos) return true; spin_lock_bh(&qos->qos_lock); list_for_each_entry(bearer, &qos->bearer_head, list) { if (!bearer->grant_size) { ret = false; break; } } spin_unlock_bh(&qos->qos_lock); return ret; } EXPORT_SYMBOL(qmi_rmnet_all_flows_enabled); #ifdef CONFIG_QCOM_QMI_DFC void qmi_rmnet_burst_fc_check(struct net_device *dev, int ip_type, u32 mark, unsigned int len) Loading Loading @@ -798,13 +823,12 @@ int qmi_rmnet_set_powersave_mode(void *port, uint8_t enable) } EXPORT_SYMBOL(qmi_rmnet_set_powersave_mode); void qmi_rmnet_work_restart(void *port) static void qmi_rmnet_work_restart(void *port) { if (!rmnet_ps_wq || !rmnet_work) return; queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, NO_DELAY); } EXPORT_SYMBOL(qmi_rmnet_work_restart); static void qmi_rmnet_check_stats(struct work_struct *work) { Loading @@ -812,6 +836,7 @@ static void qmi_rmnet_check_stats(struct work_struct *work) struct qmi_info *qmi; u64 rxd, txd; u64 rx, tx; bool dl_msg_active; real_work = container_of(to_delayed_work(work), struct rmnet_powersave_work, work); Loading @@ -824,17 +849,15 @@ static void qmi_rmnet_check_stats(struct work_struct *work) return; if (qmi->ps_enabled) { /* Retry after small delay if qmi error * This resumes UL grants by disabling * powersave mode if successful. */ /* Register to get QMI DFC and DL marker */ if (qmi_rmnet_set_powersave_mode(real_work->port, 0) < 0) { /* If this failed need to retry quickly */ queue_delayed_work(rmnet_ps_wq, &real_work->work, HZ / 50); return; } qmi->ps_enabled = 0; qmi->ps_enabled = false; if (rmnet_get_powersave_notif(real_work->port)) qmi_rmnet_ps_off_notify(real_work->port); Loading @@ -849,18 +872,29 @@ static void qmi_rmnet_check_stats(struct work_struct *work) real_work->old_rx_pkts = rx; real_work->old_tx_pkts = tx; dl_msg_active = qmi->dl_msg_active; qmi->dl_msg_active = false; if (!rxd && !txd) { /* If no DL msg received and there is a flow disabled, * (likely in RLF), no need to enter powersave */ if (!dl_msg_active && !rmnet_all_flows_enabled(real_work->port)) goto end; /* Deregister to suppress QMI DFC and DL marker */ if (qmi_rmnet_set_powersave_mode(real_work->port, 1) < 0) { queue_delayed_work(rmnet_ps_wq, &real_work->work, PS_INTERVAL); return; } qmi->ps_enabled = 1; clear_bit(PS_WORK_ACTIVE_BIT, &qmi->ps_work_active); qmi->ps_enabled = true; /* Enable flow after clear the bit so a new * work can be triggered. /* Clear the bit before enabling flow so pending packets * can trigger the work again */ clear_bit(PS_WORK_ACTIVE_BIT, &qmi->ps_work_active); rmnet_enable_all_flows(real_work->port); if (rmnet_get_powersave_notif(real_work->port)) Loading Loading @@ -936,4 +970,16 @@ void qmi_rmnet_work_exit(void *port) rmnet_work = NULL; } EXPORT_SYMBOL(qmi_rmnet_work_exit); void qmi_rmnet_set_dl_msg_active(void *port) { struct qmi_info *qmi; qmi = (struct qmi_info *)rmnet_get_qmi_pt(port); if (unlikely(!qmi)) return; qmi->dl_msg_active = true; } EXPORT_SYMBOL(qmi_rmnet_set_dl_msg_active); #endif Loading
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +24 −0 Original line number Diff line number Diff line Loading @@ -610,6 +610,30 @@ void rmnet_enable_all_flows(void *port) } EXPORT_SYMBOL(rmnet_enable_all_flows); bool rmnet_all_flows_enabled(void *port) { struct rmnet_endpoint *ep; unsigned long bkt; bool ret = true; if (unlikely(!port)) return true; rcu_read_lock(); hash_for_each_rcu(((struct rmnet_port *)port)->muxed_ep, bkt, ep, hlnode) { if (!qmi_rmnet_all_flows_enabled(ep->egress_dev)) { ret = false; goto out; } } out: rcu_read_unlock(); return ret; } EXPORT_SYMBOL(rmnet_all_flows_enabled); int rmnet_get_powersave_notif(void *port) { if (!port) Loading
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +1 −3 Original line number Diff line number Diff line Loading @@ -219,6 +219,7 @@ __rmnet_map_ingress_handler(struct sk_buff *skb, qmap = (struct rmnet_map_header *)rmnet_map_data_ptr(skb); if (qmap->cd_bit) { qmi_rmnet_set_dl_msg_active(port); if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER) { if (!rmnet_map_flow_command(skb, port, false)) return; Loading Loading @@ -349,9 +350,6 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, return -ENOMEM; } if (port->data_format & RMNET_INGRESS_FORMAT_PS) qmi_rmnet_work_maybe_restart(port); if (csum_type) rmnet_map_checksum_uplink_packet(skb, orig_dev, csum_type); Loading
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +2 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "rmnet_vnd.h" #include <soc/qcom/qmi_rmnet.h> #include <soc/qcom/rmnet_qmi.h> #define CREATE_TRACE_POINTS #include <trace/events/rmnet.h> Loading Loading @@ -75,6 +76,7 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, trace_rmnet_xmit_skb(skb); rmnet_egress_handler(skb); qmi_rmnet_burst_fc_check(dev, ip_type, mark, len); qmi_rmnet_work_maybe_restart(rmnet_get_rmnet_port(dev)); } else { this_cpu_inc(priv->pcpu_stats->stats.tx_drops); kfree_skb(skb); Loading
drivers/soc/qcom/dfc_qmi.c +29 −9 Original line number Diff line number Diff line Loading @@ -15,11 +15,17 @@ #include <net/pkt_sched.h> #include <linux/soc/qcom/qmi.h> #include <soc/qcom/rmnet_qmi.h> #include <soc/qcom/qmi_rmnet.h> #include "qmi_rmnet_i.h" #define CREATE_TRACE_POINTS #include <trace/events/dfc.h> #define DFC_MASK_TCP_BIDIR 0x1 #define DFC_MASK_RAT_SWITCH 0x2 #define DFC_IS_TCP_BIDIR(r) (bool)((r) & DFC_MASK_TCP_BIDIR) #define DFC_IS_RAT_SWITCH(r) (bool)((r) & DFC_MASK_RAT_SWITCH) #define DFC_IS_ANCILLARY(type) ((type) != AF_INET && (type) != AF_INET6) #define DFC_MAX_QOS_ID_V01 2 Loading Loading @@ -851,7 +857,7 @@ static int dfc_bearer_flow_ctl(struct net_device *dev, /* * Do not flow disable ancillary q if ancillary is true */ if (bearer->ancillary && enable == 0 && if (bearer->tcp_bidir && enable == 0 && DFC_IS_ANCILLARY(itm->ip_type)) continue; Loading Loading @@ -889,7 +895,9 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, qmi_rmnet_grant_per(bearer_itm->grant_size); bearer_itm->seq = fc_info->seq_num; bearer_itm->ack_req = ack_req; bearer_itm->ancillary = ancillary; bearer_itm->tcp_bidir = DFC_IS_TCP_BIDIR(ancillary); bearer_itm->last_grant = fc_info->num_bytes; bearer_itm->last_seq = fc_info->seq_num; } list_for_each_entry(flow_itm, &qos->flow_head, list) { Loading @@ -915,22 +923,32 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, { struct rmnet_bearer_map *itm = NULL; int rc = 0; int action = -1; bool action = false; itm = qmi_rmnet_get_bearer_map(qos, fc_info->bearer_id); if (itm) { 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; /* The RAT switch flag indicates the start and end of * the switch. Ignore indications in between. */ if (DFC_IS_RAT_SWITCH(ancillary)) itm->rat_switch = !fc_info->num_bytes; else if (itm->rat_switch) return 0; if ((itm->grant_size == 0 && fc_info->num_bytes > 0) || (itm->grant_size > 0 && fc_info->num_bytes == 0)) action = true; itm->grant_size = fc_info->num_bytes; itm->grant_thresh = qmi_rmnet_grant_per(itm->grant_size); itm->seq = fc_info->seq_num; itm->ack_req = ack_req; itm->ancillary = ancillary; itm->tcp_bidir = DFC_IS_TCP_BIDIR(ancillary); itm->last_grant = fc_info->num_bytes; itm->last_seq = fc_info->seq_num; if (action != -1) if (action) rc = dfc_bearer_flow_ctl(dev, itm, qos); } else { pr_debug("grant %u before flow activate", fc_info->num_bytes); Loading Loading @@ -1029,6 +1047,8 @@ static void dfc_qmi_ind_work(struct work_struct *work) } while (svc_ind != NULL); local_bh_enable(); qmi_rmnet_set_dl_msg_active(dfc->rmnet_port); } static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, Loading
drivers/soc/qcom/qmi_rmnet.c +62 −16 Original line number Diff line number Diff line Loading @@ -575,7 +575,7 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev) { struct qos_info *qos; struct rmnet_bearer_map *bearer; int do_wake = 0; bool do_wake = false; qos = (struct qos_info *)rmnet_get_qos_pt(dev); if (!qos) Loading @@ -584,14 +584,14 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev) spin_lock_bh(&qos->qos_lock); list_for_each_entry(bearer, &qos->bearer_head, list) { bearer->grant_before_ps = bearer->grant_size; bearer->seq_before_ps = bearer->seq; if (!bearer->grant_size) do_wake = true; bearer->grant_size = DEFAULT_GRANT; bearer->grant_thresh = DEFAULT_GRANT; bearer->seq = 0; bearer->ack_req = 0; bearer->ancillary = 0; do_wake = 1; bearer->tcp_bidir = false; bearer->rat_switch = false; } if (do_wake) { Loading @@ -603,6 +603,31 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev) } EXPORT_SYMBOL(qmi_rmnet_enable_all_flows); bool qmi_rmnet_all_flows_enabled(struct net_device *dev) { struct qos_info *qos; struct rmnet_bearer_map *bearer; bool ret = true; qos = (struct qos_info *)rmnet_get_qos_pt(dev); if (!qos) return true; spin_lock_bh(&qos->qos_lock); list_for_each_entry(bearer, &qos->bearer_head, list) { if (!bearer->grant_size) { ret = false; break; } } spin_unlock_bh(&qos->qos_lock); return ret; } EXPORT_SYMBOL(qmi_rmnet_all_flows_enabled); #ifdef CONFIG_QCOM_QMI_DFC void qmi_rmnet_burst_fc_check(struct net_device *dev, int ip_type, u32 mark, unsigned int len) Loading Loading @@ -798,13 +823,12 @@ int qmi_rmnet_set_powersave_mode(void *port, uint8_t enable) } EXPORT_SYMBOL(qmi_rmnet_set_powersave_mode); void qmi_rmnet_work_restart(void *port) static void qmi_rmnet_work_restart(void *port) { if (!rmnet_ps_wq || !rmnet_work) return; queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, NO_DELAY); } EXPORT_SYMBOL(qmi_rmnet_work_restart); static void qmi_rmnet_check_stats(struct work_struct *work) { Loading @@ -812,6 +836,7 @@ static void qmi_rmnet_check_stats(struct work_struct *work) struct qmi_info *qmi; u64 rxd, txd; u64 rx, tx; bool dl_msg_active; real_work = container_of(to_delayed_work(work), struct rmnet_powersave_work, work); Loading @@ -824,17 +849,15 @@ static void qmi_rmnet_check_stats(struct work_struct *work) return; if (qmi->ps_enabled) { /* Retry after small delay if qmi error * This resumes UL grants by disabling * powersave mode if successful. */ /* Register to get QMI DFC and DL marker */ if (qmi_rmnet_set_powersave_mode(real_work->port, 0) < 0) { /* If this failed need to retry quickly */ queue_delayed_work(rmnet_ps_wq, &real_work->work, HZ / 50); return; } qmi->ps_enabled = 0; qmi->ps_enabled = false; if (rmnet_get_powersave_notif(real_work->port)) qmi_rmnet_ps_off_notify(real_work->port); Loading @@ -849,18 +872,29 @@ static void qmi_rmnet_check_stats(struct work_struct *work) real_work->old_rx_pkts = rx; real_work->old_tx_pkts = tx; dl_msg_active = qmi->dl_msg_active; qmi->dl_msg_active = false; if (!rxd && !txd) { /* If no DL msg received and there is a flow disabled, * (likely in RLF), no need to enter powersave */ if (!dl_msg_active && !rmnet_all_flows_enabled(real_work->port)) goto end; /* Deregister to suppress QMI DFC and DL marker */ if (qmi_rmnet_set_powersave_mode(real_work->port, 1) < 0) { queue_delayed_work(rmnet_ps_wq, &real_work->work, PS_INTERVAL); return; } qmi->ps_enabled = 1; clear_bit(PS_WORK_ACTIVE_BIT, &qmi->ps_work_active); qmi->ps_enabled = true; /* Enable flow after clear the bit so a new * work can be triggered. /* Clear the bit before enabling flow so pending packets * can trigger the work again */ clear_bit(PS_WORK_ACTIVE_BIT, &qmi->ps_work_active); rmnet_enable_all_flows(real_work->port); if (rmnet_get_powersave_notif(real_work->port)) Loading Loading @@ -936,4 +970,16 @@ void qmi_rmnet_work_exit(void *port) rmnet_work = NULL; } EXPORT_SYMBOL(qmi_rmnet_work_exit); void qmi_rmnet_set_dl_msg_active(void *port) { struct qmi_info *qmi; qmi = (struct qmi_info *)rmnet_get_qmi_pt(port); if (unlikely(!qmi)) return; qmi->dl_msg_active = true; } EXPORT_SYMBOL(qmi_rmnet_set_dl_msg_active); #endif