|
@@ -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);
|