Loading drivers/soc/qcom/dfc_qmi.c +285 −16 Original line number Diff line number Diff line Loading @@ -77,11 +77,11 @@ static void dfc_svc_init(struct work_struct *work); #define QMI_DFC_INDICATION_REGISTER_REQ_V01 0x0001 #define QMI_DFC_INDICATION_REGISTER_RESP_V01 0x0001 #define QMI_DFC_INDICATION_REGISTER_REQ_V01_MAX_MSG_LEN 4 #define QMI_DFC_INDICATION_REGISTER_REQ_V01_MAX_MSG_LEN 8 #define QMI_DFC_INDICATION_REGISTER_RESP_V01_MAX_MSG_LEN 7 #define QMI_DFC_FLOW_STATUS_IND_V01 0x0022 #define QMI_DFC_FLOW_STATUS_IND_V01_MAX_MSG_LEN 540 #define QMI_DFC_TX_LINK_STATUS_IND_V01 0x0024 #define QMI_DFC_GET_FLOW_STATUS_REQ_V01 0x0023 #define QMI_DFC_GET_FLOW_STATUS_RESP_V01 0x0023 Loading @@ -100,6 +100,8 @@ struct dfc_bind_client_resp_msg_v01 { struct dfc_indication_register_req_msg_v01 { u8 report_flow_status_valid; u8 report_flow_status; u8 report_tx_link_status_valid; u8 report_tx_link_status; }; struct dfc_indication_register_resp_msg_v01 { Loading Loading @@ -311,6 +313,20 @@ struct dfc_flow_status_ind_msg_v01 { struct dfc_ancillary_info_type_v01 ancillary_info[DFC_MAX_BEARERS_V01]; }; struct dfc_bearer_info_type_v01 { u8 subs_id; u8 mux_id; u8 bearer_id; enum dfc_ip_type_enum_v01 ip_type; }; struct dfc_tx_link_status_ind_msg_v01 { u8 tx_status; u8 bearer_info_valid; u8 bearer_info_len; struct dfc_bearer_info_type_v01 bearer_info[DFC_MAX_BEARERS_V01]; }; struct dfc_get_flow_status_req_msg_v01 { u8 bearer_id_list_valid; u8 bearer_id_list_len; Loading @@ -326,7 +342,11 @@ struct dfc_get_flow_status_resp_msg_v01 { struct dfc_svc_ind { struct list_head list; u16 msg_id; union { struct dfc_flow_status_ind_msg_v01 dfc_info; struct dfc_tx_link_status_ind_msg_v01 tx_status; } d; }; static struct qmi_elem_info dfc_bind_client_req_msg_v01_ei[] = { Loading Loading @@ -398,6 +418,28 @@ static struct qmi_elem_info dfc_indication_register_req_msg_v01_ei[] = { report_flow_status), .ei_array = NULL, }, { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct dfc_indication_register_req_msg_v01, report_tx_link_status_valid), .ei_array = NULL, }, { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct dfc_indication_register_req_msg_v01, report_tx_link_status), .ei_array = NULL, }, { .data_type = QMI_EOTI, .array_type = NO_ARRAY, Loading Loading @@ -616,6 +658,111 @@ static struct qmi_elem_info dfc_get_flow_status_resp_msg_v01_ei[] = { }, }; static struct qmi_elem_info dfc_bearer_info_type_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct dfc_bearer_info_type_v01, subs_id), .ei_array = NULL, }, { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct dfc_bearer_info_type_v01, mux_id), .ei_array = NULL, }, { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct dfc_bearer_info_type_v01, bearer_id), .ei_array = NULL, }, { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum dfc_ip_type_enum_v01), .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct dfc_bearer_info_type_v01, ip_type), .ei_array = NULL, }, { .data_type = QMI_EOTI, .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, }, }; static struct qmi_elem_info dfc_tx_link_status_ind_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct dfc_tx_link_status_ind_msg_v01, tx_status), .ei_array = NULL, }, { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct dfc_tx_link_status_ind_msg_v01, bearer_info_valid), .ei_array = NULL, }, { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct dfc_tx_link_status_ind_msg_v01, bearer_info_len), .ei_array = NULL, }, { .data_type = QMI_STRUCT, .elem_len = DFC_MAX_BEARERS_V01, .elem_size = sizeof(struct dfc_bearer_info_type_v01), .array_type = VAR_LEN_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct dfc_tx_link_status_ind_msg_v01, bearer_info), .ei_array = dfc_bearer_info_type_v01_ei, }, { .data_type = QMI_EOTI, .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, }, }; static int dfc_bind_client_req(struct qmi_handle *dfc_handle, struct sockaddr_qrtr *ssctl, struct svc_info *svc) Loading Loading @@ -702,6 +849,9 @@ dfc_indication_register_req(struct qmi_handle *dfc_handle, req->report_flow_status_valid = 1; req->report_flow_status = reg; req->report_tx_link_status_valid = 1; req->report_tx_link_status = reg; ret = qmi_send_request(dfc_handle, ssctl, &txn, QMI_DFC_INDICATION_REGISTER_REQ_V01, QMI_DFC_INDICATION_REGISTER_REQ_V01_MAX_MSG_LEN, Loading Loading @@ -834,7 +984,7 @@ dfc_send_ack(struct net_device *dev, u8 bearer_id, u16 seq, u8 mux_id, u8 type) rmnet_map_tx_qmap_cmd(skb); } static int dfc_bearer_flow_ctl(struct net_device *dev, int dfc_bearer_flow_ctl(struct net_device *dev, struct rmnet_bearer_map *bearer, struct qos_info *qos) { Loading Loading @@ -928,6 +1078,10 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, if (itm->rat_switch) return 0; /* If TX is OFF but we received grant, ignore it */ if (itm->tx_off && fc_info->num_bytes > 0) return 0; if ((itm->grant_size == 0 && fc_info->num_bytes > 0) || (itm->grant_size > 0 && fc_info->num_bytes == 0)) action = true; Loading @@ -951,7 +1105,7 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, static void dfc_do_burst_flow_control(struct dfc_qmi_data *dfc, struct dfc_svc_ind *svc_ind) { struct dfc_flow_status_ind_msg_v01 *ind = &svc_ind->dfc_info; struct dfc_flow_status_ind_msg_v01 *ind = &svc_ind->d.dfc_info; struct net_device *dev; struct qos_info *qos; struct dfc_flow_status_info_type_v01 *flow_status; Loading Loading @@ -1015,6 +1169,71 @@ static void dfc_do_burst_flow_control(struct dfc_qmi_data *dfc, rcu_read_unlock(); } static void dfc_update_tx_link_status(struct net_device *dev, struct qos_info *qos, u8 tx_status, struct dfc_bearer_info_type_v01 *binfo) { struct rmnet_bearer_map *itm = NULL; itm = qmi_rmnet_get_bearer_map(qos, binfo->bearer_id); if (!itm) return; if (itm->grant_size && !tx_status) { itm->grant_size = 0; itm->tcp_bidir = false; dfc_bearer_flow_ctl(dev, itm, qos); } else if (itm->grant_size == 0 && tx_status && !itm->rat_switch) { itm->grant_size = DEFAULT_GRANT; itm->grant_thresh = DEFAULT_GRANT; itm->seq = 0; itm->ack_req = 0; dfc_bearer_flow_ctl(dev, itm, qos); } itm->tx_off = !tx_status; } static void dfc_handle_tx_link_status_ind(struct dfc_qmi_data *dfc, struct dfc_svc_ind *svc_ind) { struct dfc_tx_link_status_ind_msg_v01 *ind = &svc_ind->d.tx_status; struct net_device *dev; struct qos_info *qos; struct dfc_bearer_info_type_v01 *bearer_info; int i; rcu_read_lock(); for (i = 0; i < ind->bearer_info_len; i++) { bearer_info = &ind->bearer_info[i]; trace_dfc_tx_link_status_ind(dfc->index, i, ind->tx_status, bearer_info->mux_id, bearer_info->bearer_id); dev = rmnet_get_rmnet_dev(dfc->rmnet_port, bearer_info->mux_id); if (!dev) goto clean_out; qos = (struct qos_info *)rmnet_get_qos_pt(dev); if (!qos) continue; spin_lock_bh(&qos->qos_lock); dfc_update_tx_link_status( dev, qos, ind->tx_status, bearer_info); spin_unlock_bh(&qos->qos_lock); } clean_out: rcu_read_unlock(); } static void dfc_qmi_ind_work(struct work_struct *work) { struct dfc_qmi_data *dfc = container_of(work, struct dfc_qmi_data, Loading @@ -1035,12 +1254,18 @@ static void dfc_qmi_ind_work(struct work_struct *work) list_del(&svc_ind->list); spin_unlock_irqrestore(&dfc->qmi_ind_lock, flags); if (svc_ind) { if (!dfc->restart_state) if (!svc_ind) break; if (!dfc->restart_state) { if (svc_ind->msg_id == QMI_DFC_FLOW_STATUS_IND_V01) dfc_do_burst_flow_control(dfc, svc_ind); kfree(svc_ind); else if (svc_ind->msg_id == QMI_DFC_TX_LINK_STATUS_IND_V01) dfc_handle_tx_link_status_ind(dfc, svc_ind); } } while (svc_ind != NULL); kfree(svc_ind); } while (1); local_bh_enable(); Loading Loading @@ -1071,7 +1296,44 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, if (!svc_ind) return; memcpy(&svc_ind->dfc_info, ind_msg, sizeof(*ind_msg)); svc_ind->msg_id = QMI_DFC_FLOW_STATUS_IND_V01; memcpy(&svc_ind->d.dfc_info, ind_msg, sizeof(*ind_msg)); spin_lock_irqsave(&dfc->qmi_ind_lock, flags); list_add_tail(&svc_ind->list, &dfc->qmi_ind_q); spin_unlock_irqrestore(&dfc->qmi_ind_lock, flags); queue_work(dfc->dfc_wq, &dfc->qmi_ind_work); } } static void dfc_tx_link_status_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *data) { struct dfc_qmi_data *dfc = container_of(qmi, struct dfc_qmi_data, handle); struct dfc_tx_link_status_ind_msg_v01 *ind_msg; struct dfc_svc_ind *svc_ind; unsigned long flags; if (qmi != &dfc->handle) return; ind_msg = (struct dfc_tx_link_status_ind_msg_v01 *)data; if (ind_msg->bearer_info_valid) { if (ind_msg->bearer_info_len > DFC_MAX_BEARERS_V01) { pr_err("%s() Invalid bearer info len: %d\n", __func__, ind_msg->bearer_info_len); return; } svc_ind = kzalloc(sizeof(struct dfc_svc_ind), GFP_ATOMIC); if (!svc_ind) return; svc_ind->msg_id = QMI_DFC_TX_LINK_STATUS_IND_V01; memcpy(&svc_ind->d.tx_status, ind_msg, sizeof(*ind_msg)); spin_lock_irqsave(&dfc->qmi_ind_lock, flags); list_add_tail(&svc_ind->list, &dfc->qmi_ind_q); Loading Loading @@ -1156,9 +1418,16 @@ static struct qmi_msg_handler qmi_indication_handler[] = { .type = QMI_INDICATION, .msg_id = QMI_DFC_FLOW_STATUS_IND_V01, .ei = dfc_flow_status_ind_v01_ei, .decoded_size = QMI_DFC_FLOW_STATUS_IND_V01_MAX_MSG_LEN, .decoded_size = sizeof(struct dfc_flow_status_ind_msg_v01), .fn = dfc_clnt_ind_cb, }, { .type = QMI_INDICATION, .msg_id = QMI_DFC_TX_LINK_STATUS_IND_V01, .ei = dfc_tx_link_status_ind_v01_ei, .decoded_size = sizeof(struct dfc_tx_link_status_ind_msg_v01), .fn = dfc_tx_link_status_ind_cb, }, {}, }; Loading Loading @@ -1307,9 +1576,9 @@ void dfc_qmi_query_flow(void *dfc_data) resp->flow_status_len > DFC_MAX_BEARERS_V01) goto done; svc_ind->dfc_info.flow_status_valid = resp->flow_status_valid; svc_ind->dfc_info.flow_status_len = resp->flow_status_len; memcpy(&svc_ind->dfc_info.flow_status, resp->flow_status, svc_ind->d.dfc_info.flow_status_valid = resp->flow_status_valid; svc_ind->d.dfc_info.flow_status_len = resp->flow_status_len; memcpy(&svc_ind->d.dfc_info.flow_status, resp->flow_status, sizeof(resp->flow_status[0]) * resp->flow_status_len); dfc_do_burst_flow_control(data, svc_ind); Loading drivers/soc/qcom/qmi_rmnet.c +6 −7 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; bool do_wake = false; bool do_wake; qos = (struct qos_info *)rmnet_get_qos_pt(dev); if (!qos) Loading @@ -584,19 +584,18 @@ 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) { if (!bearer->grant_size) do_wake = true; if (bearer->tx_off) continue; do_wake = !bearer->grant_size; bearer->grant_size = DEFAULT_GRANT; bearer->grant_thresh = DEFAULT_GRANT; bearer->seq = 0; bearer->ack_req = 0; bearer->tcp_bidir = false; bearer->rat_switch = false; } if (do_wake) { netif_tx_wake_all_queues(dev); trace_dfc_qmi_tc(dev->name, 0xFF, 0, DEFAULT_GRANT, 0, 0, 1); if (do_wake) dfc_bearer_flow_ctl(dev, bearer, qos); } spin_unlock_bh(&qos->qos_lock); Loading drivers/soc/qcom/qmi_rmnet_i.h +13 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ struct rmnet_bearer_map { u16 last_seq; bool tcp_bidir; bool rat_switch; bool tx_off; }; struct svc_info { Loading Loading @@ -113,6 +114,10 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, int qmi_rmnet_flow_control(struct net_device *dev, u32 tcm_handle, int enable); void dfc_qmi_query_flow(void *dfc_data); int dfc_bearer_flow_ctl(struct net_device *dev, struct rmnet_bearer_map *bearer, struct qos_info *qos); #else static inline struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, Loading Loading @@ -148,6 +153,14 @@ static inline void dfc_qmi_query_flow(void *dfc_data) { } static inline int dfc_bearer_flow_ctl(struct net_device *dev, struct rmnet_bearer_map *bearer, struct qos_info *qos) { return 0; } #endif #ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE Loading include/trace/events/dfc.h +27 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,33 @@ TRACE_EVENT(dfc_qmap_cmd, __entry->type, __entry->tran) ); TRACE_EVENT(dfc_tx_link_status_ind, TP_PROTO(int src, int idx, u8 status, u8 mux_id, u8 bearer_id), TP_ARGS(src, idx, status, mux_id, bearer_id), TP_STRUCT__entry( __field(int, src) __field(int, idx) __field(u8, status) __field(u8, mid) __field(u8, bid) ), TP_fast_assign( __entry->src = src; __entry->idx = idx; __entry->status = status; __entry->mid = mux_id; __entry->bid = bearer_id; ), TP_printk("src=%d [%d]: status=%u mux_id=%u bearer_id=%u", __entry->src, __entry->idx, __entry->status, __entry->mid, __entry->bid) ); #endif /* _TRACE_DFC_H */ /* This part must be outside protection */ Loading Loading
drivers/soc/qcom/dfc_qmi.c +285 −16 Original line number Diff line number Diff line Loading @@ -77,11 +77,11 @@ static void dfc_svc_init(struct work_struct *work); #define QMI_DFC_INDICATION_REGISTER_REQ_V01 0x0001 #define QMI_DFC_INDICATION_REGISTER_RESP_V01 0x0001 #define QMI_DFC_INDICATION_REGISTER_REQ_V01_MAX_MSG_LEN 4 #define QMI_DFC_INDICATION_REGISTER_REQ_V01_MAX_MSG_LEN 8 #define QMI_DFC_INDICATION_REGISTER_RESP_V01_MAX_MSG_LEN 7 #define QMI_DFC_FLOW_STATUS_IND_V01 0x0022 #define QMI_DFC_FLOW_STATUS_IND_V01_MAX_MSG_LEN 540 #define QMI_DFC_TX_LINK_STATUS_IND_V01 0x0024 #define QMI_DFC_GET_FLOW_STATUS_REQ_V01 0x0023 #define QMI_DFC_GET_FLOW_STATUS_RESP_V01 0x0023 Loading @@ -100,6 +100,8 @@ struct dfc_bind_client_resp_msg_v01 { struct dfc_indication_register_req_msg_v01 { u8 report_flow_status_valid; u8 report_flow_status; u8 report_tx_link_status_valid; u8 report_tx_link_status; }; struct dfc_indication_register_resp_msg_v01 { Loading Loading @@ -311,6 +313,20 @@ struct dfc_flow_status_ind_msg_v01 { struct dfc_ancillary_info_type_v01 ancillary_info[DFC_MAX_BEARERS_V01]; }; struct dfc_bearer_info_type_v01 { u8 subs_id; u8 mux_id; u8 bearer_id; enum dfc_ip_type_enum_v01 ip_type; }; struct dfc_tx_link_status_ind_msg_v01 { u8 tx_status; u8 bearer_info_valid; u8 bearer_info_len; struct dfc_bearer_info_type_v01 bearer_info[DFC_MAX_BEARERS_V01]; }; struct dfc_get_flow_status_req_msg_v01 { u8 bearer_id_list_valid; u8 bearer_id_list_len; Loading @@ -326,7 +342,11 @@ struct dfc_get_flow_status_resp_msg_v01 { struct dfc_svc_ind { struct list_head list; u16 msg_id; union { struct dfc_flow_status_ind_msg_v01 dfc_info; struct dfc_tx_link_status_ind_msg_v01 tx_status; } d; }; static struct qmi_elem_info dfc_bind_client_req_msg_v01_ei[] = { Loading Loading @@ -398,6 +418,28 @@ static struct qmi_elem_info dfc_indication_register_req_msg_v01_ei[] = { report_flow_status), .ei_array = NULL, }, { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct dfc_indication_register_req_msg_v01, report_tx_link_status_valid), .ei_array = NULL, }, { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x11, .offset = offsetof(struct dfc_indication_register_req_msg_v01, report_tx_link_status), .ei_array = NULL, }, { .data_type = QMI_EOTI, .array_type = NO_ARRAY, Loading Loading @@ -616,6 +658,111 @@ static struct qmi_elem_info dfc_get_flow_status_resp_msg_v01_ei[] = { }, }; static struct qmi_elem_info dfc_bearer_info_type_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct dfc_bearer_info_type_v01, subs_id), .ei_array = NULL, }, { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct dfc_bearer_info_type_v01, mux_id), .ei_array = NULL, }, { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct dfc_bearer_info_type_v01, bearer_id), .ei_array = NULL, }, { .data_type = QMI_SIGNED_4_BYTE_ENUM, .elem_len = 1, .elem_size = sizeof(enum dfc_ip_type_enum_v01), .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, .offset = offsetof(struct dfc_bearer_info_type_v01, ip_type), .ei_array = NULL, }, { .data_type = QMI_EOTI, .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, }, }; static struct qmi_elem_info dfc_tx_link_status_ind_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct dfc_tx_link_status_ind_msg_v01, tx_status), .ei_array = NULL, }, { .data_type = QMI_OPT_FLAG, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct dfc_tx_link_status_ind_msg_v01, bearer_info_valid), .ei_array = NULL, }, { .data_type = QMI_DATA_LEN, .elem_len = 1, .elem_size = sizeof(u8), .array_type = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct dfc_tx_link_status_ind_msg_v01, bearer_info_len), .ei_array = NULL, }, { .data_type = QMI_STRUCT, .elem_len = DFC_MAX_BEARERS_V01, .elem_size = sizeof(struct dfc_bearer_info_type_v01), .array_type = VAR_LEN_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct dfc_tx_link_status_ind_msg_v01, bearer_info), .ei_array = dfc_bearer_info_type_v01_ei, }, { .data_type = QMI_EOTI, .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, }, }; static int dfc_bind_client_req(struct qmi_handle *dfc_handle, struct sockaddr_qrtr *ssctl, struct svc_info *svc) Loading Loading @@ -702,6 +849,9 @@ dfc_indication_register_req(struct qmi_handle *dfc_handle, req->report_flow_status_valid = 1; req->report_flow_status = reg; req->report_tx_link_status_valid = 1; req->report_tx_link_status = reg; ret = qmi_send_request(dfc_handle, ssctl, &txn, QMI_DFC_INDICATION_REGISTER_REQ_V01, QMI_DFC_INDICATION_REGISTER_REQ_V01_MAX_MSG_LEN, Loading Loading @@ -834,7 +984,7 @@ dfc_send_ack(struct net_device *dev, u8 bearer_id, u16 seq, u8 mux_id, u8 type) rmnet_map_tx_qmap_cmd(skb); } static int dfc_bearer_flow_ctl(struct net_device *dev, int dfc_bearer_flow_ctl(struct net_device *dev, struct rmnet_bearer_map *bearer, struct qos_info *qos) { Loading Loading @@ -928,6 +1078,10 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, if (itm->rat_switch) return 0; /* If TX is OFF but we received grant, ignore it */ if (itm->tx_off && fc_info->num_bytes > 0) return 0; if ((itm->grant_size == 0 && fc_info->num_bytes > 0) || (itm->grant_size > 0 && fc_info->num_bytes == 0)) action = true; Loading @@ -951,7 +1105,7 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, static void dfc_do_burst_flow_control(struct dfc_qmi_data *dfc, struct dfc_svc_ind *svc_ind) { struct dfc_flow_status_ind_msg_v01 *ind = &svc_ind->dfc_info; struct dfc_flow_status_ind_msg_v01 *ind = &svc_ind->d.dfc_info; struct net_device *dev; struct qos_info *qos; struct dfc_flow_status_info_type_v01 *flow_status; Loading Loading @@ -1015,6 +1169,71 @@ static void dfc_do_burst_flow_control(struct dfc_qmi_data *dfc, rcu_read_unlock(); } static void dfc_update_tx_link_status(struct net_device *dev, struct qos_info *qos, u8 tx_status, struct dfc_bearer_info_type_v01 *binfo) { struct rmnet_bearer_map *itm = NULL; itm = qmi_rmnet_get_bearer_map(qos, binfo->bearer_id); if (!itm) return; if (itm->grant_size && !tx_status) { itm->grant_size = 0; itm->tcp_bidir = false; dfc_bearer_flow_ctl(dev, itm, qos); } else if (itm->grant_size == 0 && tx_status && !itm->rat_switch) { itm->grant_size = DEFAULT_GRANT; itm->grant_thresh = DEFAULT_GRANT; itm->seq = 0; itm->ack_req = 0; dfc_bearer_flow_ctl(dev, itm, qos); } itm->tx_off = !tx_status; } static void dfc_handle_tx_link_status_ind(struct dfc_qmi_data *dfc, struct dfc_svc_ind *svc_ind) { struct dfc_tx_link_status_ind_msg_v01 *ind = &svc_ind->d.tx_status; struct net_device *dev; struct qos_info *qos; struct dfc_bearer_info_type_v01 *bearer_info; int i; rcu_read_lock(); for (i = 0; i < ind->bearer_info_len; i++) { bearer_info = &ind->bearer_info[i]; trace_dfc_tx_link_status_ind(dfc->index, i, ind->tx_status, bearer_info->mux_id, bearer_info->bearer_id); dev = rmnet_get_rmnet_dev(dfc->rmnet_port, bearer_info->mux_id); if (!dev) goto clean_out; qos = (struct qos_info *)rmnet_get_qos_pt(dev); if (!qos) continue; spin_lock_bh(&qos->qos_lock); dfc_update_tx_link_status( dev, qos, ind->tx_status, bearer_info); spin_unlock_bh(&qos->qos_lock); } clean_out: rcu_read_unlock(); } static void dfc_qmi_ind_work(struct work_struct *work) { struct dfc_qmi_data *dfc = container_of(work, struct dfc_qmi_data, Loading @@ -1035,12 +1254,18 @@ static void dfc_qmi_ind_work(struct work_struct *work) list_del(&svc_ind->list); spin_unlock_irqrestore(&dfc->qmi_ind_lock, flags); if (svc_ind) { if (!dfc->restart_state) if (!svc_ind) break; if (!dfc->restart_state) { if (svc_ind->msg_id == QMI_DFC_FLOW_STATUS_IND_V01) dfc_do_burst_flow_control(dfc, svc_ind); kfree(svc_ind); else if (svc_ind->msg_id == QMI_DFC_TX_LINK_STATUS_IND_V01) dfc_handle_tx_link_status_ind(dfc, svc_ind); } } while (svc_ind != NULL); kfree(svc_ind); } while (1); local_bh_enable(); Loading Loading @@ -1071,7 +1296,44 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, if (!svc_ind) return; memcpy(&svc_ind->dfc_info, ind_msg, sizeof(*ind_msg)); svc_ind->msg_id = QMI_DFC_FLOW_STATUS_IND_V01; memcpy(&svc_ind->d.dfc_info, ind_msg, sizeof(*ind_msg)); spin_lock_irqsave(&dfc->qmi_ind_lock, flags); list_add_tail(&svc_ind->list, &dfc->qmi_ind_q); spin_unlock_irqrestore(&dfc->qmi_ind_lock, flags); queue_work(dfc->dfc_wq, &dfc->qmi_ind_work); } } static void dfc_tx_link_status_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *data) { struct dfc_qmi_data *dfc = container_of(qmi, struct dfc_qmi_data, handle); struct dfc_tx_link_status_ind_msg_v01 *ind_msg; struct dfc_svc_ind *svc_ind; unsigned long flags; if (qmi != &dfc->handle) return; ind_msg = (struct dfc_tx_link_status_ind_msg_v01 *)data; if (ind_msg->bearer_info_valid) { if (ind_msg->bearer_info_len > DFC_MAX_BEARERS_V01) { pr_err("%s() Invalid bearer info len: %d\n", __func__, ind_msg->bearer_info_len); return; } svc_ind = kzalloc(sizeof(struct dfc_svc_ind), GFP_ATOMIC); if (!svc_ind) return; svc_ind->msg_id = QMI_DFC_TX_LINK_STATUS_IND_V01; memcpy(&svc_ind->d.tx_status, ind_msg, sizeof(*ind_msg)); spin_lock_irqsave(&dfc->qmi_ind_lock, flags); list_add_tail(&svc_ind->list, &dfc->qmi_ind_q); Loading Loading @@ -1156,9 +1418,16 @@ static struct qmi_msg_handler qmi_indication_handler[] = { .type = QMI_INDICATION, .msg_id = QMI_DFC_FLOW_STATUS_IND_V01, .ei = dfc_flow_status_ind_v01_ei, .decoded_size = QMI_DFC_FLOW_STATUS_IND_V01_MAX_MSG_LEN, .decoded_size = sizeof(struct dfc_flow_status_ind_msg_v01), .fn = dfc_clnt_ind_cb, }, { .type = QMI_INDICATION, .msg_id = QMI_DFC_TX_LINK_STATUS_IND_V01, .ei = dfc_tx_link_status_ind_v01_ei, .decoded_size = sizeof(struct dfc_tx_link_status_ind_msg_v01), .fn = dfc_tx_link_status_ind_cb, }, {}, }; Loading Loading @@ -1307,9 +1576,9 @@ void dfc_qmi_query_flow(void *dfc_data) resp->flow_status_len > DFC_MAX_BEARERS_V01) goto done; svc_ind->dfc_info.flow_status_valid = resp->flow_status_valid; svc_ind->dfc_info.flow_status_len = resp->flow_status_len; memcpy(&svc_ind->dfc_info.flow_status, resp->flow_status, svc_ind->d.dfc_info.flow_status_valid = resp->flow_status_valid; svc_ind->d.dfc_info.flow_status_len = resp->flow_status_len; memcpy(&svc_ind->d.dfc_info.flow_status, resp->flow_status, sizeof(resp->flow_status[0]) * resp->flow_status_len); dfc_do_burst_flow_control(data, svc_ind); Loading
drivers/soc/qcom/qmi_rmnet.c +6 −7 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; bool do_wake = false; bool do_wake; qos = (struct qos_info *)rmnet_get_qos_pt(dev); if (!qos) Loading @@ -584,19 +584,18 @@ 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) { if (!bearer->grant_size) do_wake = true; if (bearer->tx_off) continue; do_wake = !bearer->grant_size; bearer->grant_size = DEFAULT_GRANT; bearer->grant_thresh = DEFAULT_GRANT; bearer->seq = 0; bearer->ack_req = 0; bearer->tcp_bidir = false; bearer->rat_switch = false; } if (do_wake) { netif_tx_wake_all_queues(dev); trace_dfc_qmi_tc(dev->name, 0xFF, 0, DEFAULT_GRANT, 0, 0, 1); if (do_wake) dfc_bearer_flow_ctl(dev, bearer, qos); } spin_unlock_bh(&qos->qos_lock); Loading
drivers/soc/qcom/qmi_rmnet_i.h +13 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ struct rmnet_bearer_map { u16 last_seq; bool tcp_bidir; bool rat_switch; bool tx_off; }; struct svc_info { Loading Loading @@ -113,6 +114,10 @@ void dfc_qmi_burst_check(struct net_device *dev, struct qos_info *qos, int qmi_rmnet_flow_control(struct net_device *dev, u32 tcm_handle, int enable); void dfc_qmi_query_flow(void *dfc_data); int dfc_bearer_flow_ctl(struct net_device *dev, struct rmnet_bearer_map *bearer, struct qos_info *qos); #else static inline struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, Loading Loading @@ -148,6 +153,14 @@ static inline void dfc_qmi_query_flow(void *dfc_data) { } static inline int dfc_bearer_flow_ctl(struct net_device *dev, struct rmnet_bearer_map *bearer, struct qos_info *qos) { return 0; } #endif #ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE Loading
include/trace/events/dfc.h +27 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,33 @@ TRACE_EVENT(dfc_qmap_cmd, __entry->type, __entry->tran) ); TRACE_EVENT(dfc_tx_link_status_ind, TP_PROTO(int src, int idx, u8 status, u8 mux_id, u8 bearer_id), TP_ARGS(src, idx, status, mux_id, bearer_id), TP_STRUCT__entry( __field(int, src) __field(int, idx) __field(u8, status) __field(u8, mid) __field(u8, bid) ), TP_fast_assign( __entry->src = src; __entry->idx = idx; __entry->status = status; __entry->mid = mux_id; __entry->bid = bearer_id; ), TP_printk("src=%d [%d]: status=%u mux_id=%u bearer_id=%u", __entry->src, __entry->idx, __entry->status, __entry->mid, __entry->bid) ); #endif /* _TRACE_DFC_H */ /* This part must be outside protection */ Loading