Przeglądaj źródła

core: Handle Pending byte marker

When a pending byte marker is received,
rmnet_core will place a vote to raise
clocks for a predefined period of time.
After that period of time rmnet_core
removes that vote.

Change-Id: I53b434664a518b686d59ffa5ba4c08eee067abde
Signed-off-by: Conner Huff <[email protected]>
Conner Huff 2 lat temu
rodzic
commit
07ba798610
5 zmienionych plików z 187 dodań i 2 usunięć
  1. 4 1
      core/rmnet_config.h
  2. 36 0
      core/rmnet_descriptor.c
  3. 31 1
      core/rmnet_map.h
  4. 115 0
      core/rmnet_map_command.c
  5. 1 0
      core/rmnet_vnd.c

+ 4 - 1
core/rmnet_config.h

@@ -1,5 +1,5 @@
 /* Copyright (c) 2013-2014, 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -76,6 +76,7 @@ struct rmnet_port_priv_stats {
 	u64 dl_chain_stat[7];
 	u64 dl_frag_stat_1;
 	u64 dl_frag_stat[5];
+	u64 pb_marker_count;
 };
 
 struct rmnet_egress_agg_params {
@@ -136,6 +137,8 @@ struct rmnet_port {
 	struct list_head dl_list;
 	struct rmnet_port_priv_stats stats;
 	int dl_marker_flush;
+	/* Pending Byte Marker */
+	struct list_head pb_list;
 	/* Port Config for shs */
 	struct rmnet_shs_clnt_s shs_cfg;
 	struct rmnet_shs_clnt_s phy_shs_cfg;

+ 36 - 0
core/rmnet_descriptor.c

@@ -35,6 +35,9 @@
 #define RMNET_DL_IND_TRL_SIZE (sizeof(struct rmnet_map_dl_ind_trl) + \
 			       sizeof(struct rmnet_map_header) + \
 			       sizeof(struct rmnet_map_control_command_header))
+#define RMNET_PB_IND_HDR_SIZE (sizeof(struct rmnet_map_pb_ind_hdr) + \
+			       sizeof(struct rmnet_map_header) + \
+			       sizeof(struct rmnet_map_control_command_header))
 
 #define rmnet_descriptor_for_each_frag(p, desc) \
 	list_for_each_entry(p, &desc->frags, list)
@@ -444,6 +447,36 @@ static void rmnet_frag_send_ack(struct rmnet_map_header *qmap,
 	netif_tx_unlock(dev);
 }
 
+static void
+rmnet_frag_process_pb_ind(struct rmnet_frag_descriptor *frag_desc,
+			  struct rmnet_map_control_command_header *cmd,
+			  struct rmnet_port *port,
+			  u16 cmd_len)
+{
+	struct rmnet_map_pb_ind_hdr *pbhdr, __pbhdr;
+	u32 offset = sizeof(struct rmnet_map_header);
+	u32 data_format;
+	bool is_dl_mark_v2;
+
+	if (cmd_len + offset < RMNET_PB_IND_HDR_SIZE)
+		return;
+
+	data_format = port->data_format;
+	is_dl_mark_v2 = data_format & RMNET_INGRESS_FORMAT_DL_MARKER_V2;
+	pbhdr = rmnet_frag_header_ptr(frag_desc, offset + sizeof(*cmd),
+				      sizeof(*pbhdr), &__pbhdr);
+	if (!pbhdr)
+		return;
+
+	port->stats.pb_marker_count++;
+
+	/* If a target is taking frag path, we can assume DL marker v2 is in
+	 * play
+	 */
+	if (is_dl_mark_v2)
+		rmnet_map_pb_ind_notify(port, pbhdr);
+}
+
 static void
 rmnet_frag_process_flow_start(struct rmnet_frag_descriptor *frag_desc,
 			      struct rmnet_map_control_command_header *cmd,
@@ -570,6 +603,9 @@ int rmnet_frag_flow_command(struct rmnet_frag_descriptor *frag_desc,
 		rmnet_frag_process_flow_end(frag_desc, cmd, port, pkt_len);
 		break;
 
+	case RMNET_MAP_COMMAND_PB_BYTES:
+		rmnet_frag_process_pb_ind(frag_desc, cmd, port, pkt_len);
+		break;
 	default:
 		return 1;
 	}

+ 31 - 1
core/rmnet_map.h

@@ -1,5 +1,5 @@
 /* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -40,6 +40,7 @@ enum rmnet_map_commands {
 	RMNET_MAP_COMMAND_FLOW_ENABLE,
 	RMNET_MAP_COMMAND_FLOW_START = 7,
 	RMNET_MAP_COMMAND_FLOW_END = 8,
+	RMNET_MAP_COMMAND_PB_BYTES = 29,
 	/* These should always be the last 2 elements */
 	RMNET_MAP_COMMAND_UNKNOWN,
 	RMNET_MAP_COMMAND_ENUM_LENGTH
@@ -165,6 +166,29 @@ struct rmnet_map_flow_info_be {
 	u32 pkts;
 } __aligned(1);
 
+struct rmnet_map_pb_ind_hdr {
+	union {
+		struct {
+			u32 seq_num;
+			u32 start_end_seq_num;
+			u32 row_bytes_pending;
+			u32 fc_bytes_pending;
+		} le __aligned(1);
+		struct {
+			u32 seq_num;
+			u32 start_end_seq_num;
+			u32 row_bytes_pending;
+			u32 fc_bytes_pending;
+		} be __aligned(1);
+	} __aligned(1);
+} __aligned(1);
+
+struct rmnet_map_pb_ind {
+	u8 priority;
+	void (*pb_ind_handler)(struct rmnet_map_pb_ind_hdr *pbhdr);
+	struct list_head list;
+};
+
 struct rmnet_map_dl_ind_hdr {
 	union {
 		struct {
@@ -285,6 +309,8 @@ void rmnet_map_dl_hdr_notify_v2(struct rmnet_port *port,
 void rmnet_map_dl_trl_notify_v2(struct rmnet_port *port,
 				struct rmnet_map_dl_ind_trl *dltrl,
 				struct rmnet_map_control_command_header *qcmd);
+void rmnet_map_pb_ind_notify(struct rmnet_port *port,
+			     struct rmnet_map_pb_ind_hdr *pbhdr);
 int rmnet_map_flow_command(struct sk_buff *skb,
 			   struct rmnet_port *port,
 			   bool rmnet_perf);
@@ -293,6 +319,10 @@ int rmnet_map_dl_ind_register(struct rmnet_port *port,
 			      struct rmnet_map_dl_ind *dl_ind);
 int rmnet_map_dl_ind_deregister(struct rmnet_port *port,
 				struct rmnet_map_dl_ind *dl_ind);
+int rmnet_map_pb_ind_register(struct rmnet_port *port,
+			      struct rmnet_map_pb_ind *pb_ind);
+int rmnet_map_pb_ind_deregister(struct rmnet_port *port,
+				struct rmnet_map_pb_ind *pb_ind);
 void rmnet_map_cmd_exit(struct rmnet_port *port);
 void rmnet_map_tx_qmap_cmd(struct sk_buff *qmap_skb, u8 ch, bool flush);
 void rmnet_map_send_agg_skb(struct rmnet_aggregation_state *state);

+ 115 - 0
core/rmnet_map_command.c

@@ -1,4 +1,5 @@
 /* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -27,6 +28,10 @@
 			       sizeof(struct rmnet_map_header) + \
 			       sizeof(struct rmnet_map_control_command_header))
 
+#define RMNET_PB_IND_HDR_SIZE (sizeof(struct rmnet_map_pb_ind_hdr) + \
+			       sizeof(struct rmnet_map_header) + \
+			       sizeof(struct rmnet_map_control_command_header))
+
 static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
 				    struct rmnet_port *port,
 				    int enable)
@@ -118,6 +123,49 @@ rmnet_map_dl_trl_notify_v2(struct rmnet_port *port,
 		tmp->dl_trl_handler_v2(dltrl, qcmd);
 }
 
+void rmnet_map_pb_ind_notify(struct rmnet_port *port,
+			     struct rmnet_map_pb_ind_hdr *pbhdr)
+{
+	struct rmnet_map_pb_ind *tmp;
+
+	list_for_each_entry(tmp, &port->pb_list, list)
+		tmp->pb_ind_handler(pbhdr);
+}
+
+static void rmnet_map_process_pb_ind(struct sk_buff *skb,
+				     struct rmnet_port *port,
+				     bool rmnet_perf)
+{
+	struct rmnet_map_pb_ind_hdr *pbhdr;
+	u32 data_format;
+	bool is_dl_mark_v2;
+
+	if (skb->len < RMNET_PB_IND_HDR_SIZE)
+		return;
+
+	data_format = port->data_format;
+	is_dl_mark_v2 = data_format & RMNET_INGRESS_FORMAT_DL_MARKER_V2;
+	if (is_dl_mark_v2) {
+		pskb_pull(skb, sizeof(struct rmnet_map_header) +
+				  sizeof(struct rmnet_map_control_command_header));
+	}
+
+	pbhdr = (struct rmnet_map_pb_ind_hdr *)rmnet_map_data_ptr(skb);
+	port->stats.pb_marker_count++;
+
+	if (is_dl_mark_v2)
+		rmnet_map_pb_ind_notify(port, pbhdr);
+
+	if (rmnet_perf) {
+		unsigned int pull_size;
+
+		pull_size = sizeof(struct rmnet_map_pb_ind_hdr);
+		if (data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4)
+			pull_size += sizeof(struct rmnet_map_dl_csum_trailer);
+		pskb_pull(skb, pull_size);
+	}
+}
+
 static void rmnet_map_process_flow_start(struct sk_buff *skb,
 					 struct rmnet_port *port,
 					 bool rmnet_perf)
@@ -262,6 +310,10 @@ int rmnet_map_flow_command(struct sk_buff *skb, struct rmnet_port *port,
 		rmnet_map_process_flow_end(skb, port, rmnet_perf);
 		break;
 
+	case RMNET_MAP_COMMAND_PB_BYTES:
+		rmnet_map_process_pb_ind(skb, port, rmnet_perf);
+		break;
+
 	default:
 		return 1;
 	}
@@ -280,11 +332,15 @@ void rmnet_map_cmd_exit(struct rmnet_port *port)
 
 	list_for_each_entry_safe(tmp, idx, &port->dl_list, list)
 		list_del_rcu(&tmp->list);
+
+	list_for_each_entry_safe(tmp, idx, &port->pb_list, list)
+		list_del_rcu(&tmp->list);
 }
 
 void rmnet_map_cmd_init(struct rmnet_port *port)
 {
 	INIT_LIST_HEAD(&port->dl_list);
+	INIT_LIST_HEAD(&port->pb_list);
 }
 
 int rmnet_map_dl_ind_register(struct rmnet_port *port,
@@ -346,3 +402,62 @@ done:
 	return 0;
 }
 EXPORT_SYMBOL(rmnet_map_dl_ind_deregister);
+
+int rmnet_map_pb_ind_register(struct rmnet_port *port,
+			      struct rmnet_map_pb_ind *pb_ind)
+{
+	struct rmnet_map_pb_ind *pb_ind_iterator;
+	bool empty_ind_list = true;
+
+	if (!port || !pb_ind || !pb_ind->pb_ind_handler)
+		return -EINVAL;
+
+	list_for_each_entry_rcu(pb_ind_iterator, &port->pb_list, list) {
+		empty_ind_list = false;
+		if (pb_ind_iterator->priority < pb_ind->priority) {
+			if (pb_ind_iterator->list.next) {
+				if (pb_ind->priority
+				    < list_entry_rcu(pb_ind_iterator->list.next,
+				    typeof(*pb_ind_iterator), list)->priority) {
+					list_add_rcu(&pb_ind->list,
+						     &pb_ind_iterator->list);
+					break;
+				}
+			} else {
+				list_add_rcu(&pb_ind->list,
+					     &pb_ind_iterator->list);
+				break;
+			}
+		} else {
+			list_add_tail_rcu(&pb_ind->list,
+					  &pb_ind_iterator->list);
+			break;
+		}
+	}
+
+	if (empty_ind_list)
+		list_add_rcu(&pb_ind->list, &port->pb_list);
+
+	return 0;
+}
+EXPORT_SYMBOL(rmnet_map_pb_ind_register);
+
+int rmnet_map_pb_ind_deregister(struct rmnet_port *port,
+				struct rmnet_map_pb_ind *pb_ind)
+{
+	struct rmnet_map_pb_ind *tmp;
+
+	if (!port || !pb_ind)
+		return -EINVAL;
+
+	list_for_each_entry(tmp, &port->pb_list, list) {
+		if (tmp == pb_ind) {
+			list_del_rcu(&pb_ind->list);
+			goto done;
+		}
+	}
+
+done:
+	return 0;
+}
+EXPORT_SYMBOL(rmnet_map_pb_ind_deregister);

+ 1 - 0
core/rmnet_vnd.c

@@ -574,6 +574,7 @@ static const char rmnet_port_gstrings_stats[][ETH_GSTRING_LEN] = {
 	"DL chaining frags [8-11]",
 	"DL chaining frags [12-15]",
 	"DL chaining frags = 16",
+	"PB Byte Marker Count",
 };
 
 static const char rmnet_ll_gstrings_stats[][ETH_GSTRING_LEN] = {