/* Copyright (c) 2018-2020 The Linux Foundation. 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 * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * RMNET Data Smart Hash solution * */ #include #include "rmnet_shs_wq.h" #ifndef _RMNET_SHS_H_ #define _RMNET_SHS_H_ #include "rmnet_shs_freq.h" #include <../drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h> #include <../drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h> #include <../drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h> #include <../drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h> #include <../drivers/net/ethernet/qualcomm/rmnet/rmnet_trace.h> #include <../include/soc/qcom/qmi_rmnet.h> #define RMNET_SHS_HT rmnet_shs_ht #define RMNET_SHS_HT_SIZE 9 #define RMNET_SHS_MAX_SKB_INACTIVE_TSEC 30 #define MAX_SILVER_CORES 4 #define MAX_CPUS 8 #define PERF_MASK 0xF0 /* RPS mask change's Default core for orphaned CPU flows */ #define MAIN_CORE 0 #define UPDATE_MASK 0xFF #define MAX_FLOWS 700 /* Different max inactivity based on # of flows */ #define FLOW_LIMIT1 70 #define INACTIVE_TSEC1 10 #define FLOW_LIMIT2 140 #define INACTIVE_TSEC2 2 //#define RMNET_SHS_MAX_UDP_SILVER_CORE_DATA_RATE 1073741824 //1.0Gbps //#define RMNET_SHS_MAX_UDP_SILVER_CORE_DATA_RATE 320787200 //320 Mbps //#define RMNET_SHS_MAX_UDP_GOLD_CORE_DATA_RATE 3650722201 //3.4 Gbps //#define RMNET_SHS_UDP_PPS_SILVER_CORE_UPPER_THRESH 90000 //#define RMNET_SHS_TCP_PPS_SILVER_CORE_UPPER_THRESH 90000 #define SHS_TRACE_ERR(...) \ do { if (rmnet_shs_debug) trace_rmnet_shs_err(__VA_ARGS__); } while (0) #define SHS_TRACE_HIGH(...) \ do { if (rmnet_shs_debug) trace_rmnet_shs_high(__VA_ARGS__); } while (0) #define SHS_TRACE_LOW(...) \ do { if (rmnet_shs_debug) trace_rmnet_shs_low(__VA_ARGS__); } while (0) #define RMNET_SHS_MAX_SILVER_CORE_BURST_CAPACITY 204800 #define RMNET_SHS_TCP_COALESCING_RATIO 23 //Heuristic #define RMNET_SHS_UDP_PPS_LPWR_CPU_UTHRESH 80000 #define RMNET_SHS_TCP_PPS_LPWR_CPU_UTHRESH (80000*RMNET_SHS_TCP_COALESCING_RATIO) #define RMNET_SHS_UDP_PPS_PERF_CPU_UTHRESH 210000 #define RMNET_SHS_TCP_PPS_PERF_CPU_UTHRESH (210000*RMNET_SHS_TCP_COALESCING_RATIO) //50% of MAX SILVER THRESHOLD #define RMNET_SHS_UDP_PPS_LPWR_CPU_LTHRESH 0 #define RMNET_SHS_UDP_PPS_PERF_CPU_LTHRESH 40000 #define RMNET_SHS_TCP_PPS_PERF_CPU_LTHRESH (40000*RMNET_SHS_TCP_COALESCING_RATIO) #define RMNET_SHS_UDP_PPS_HEADROOM 20000 #define RMNET_SHS_GOLD_BALANCING_THRESH (RMNET_SHS_UDP_PPS_PERF_CPU_UTHRESH / 2) struct core_flush_s { struct hrtimer core_timer; struct work_struct work; struct timespec coretime; int coresum; u8 core; }; struct rmnet_shs_cfg_s { struct hrtimer hrtimer_shs; struct rmnet_map_dl_ind dl_mrk_ind_cb; struct qmi_rmnet_ps_ind rmnet_idl_ind_cb; struct rmnet_port *port; struct core_flush_s core_flush[MAX_CPUS]; u64 core_skbs[MAX_CPUS]; long num_bytes_parked; long num_pkts_parked; u32 is_reg_dl_mrk_ind; u16 num_flows; u8 is_pkt_parked; u8 is_timer_init; u8 force_flush_state; u8 rmnet_shs_init_complete; u8 dl_ind_state; u8 map_mask; u8 map_len; }; struct rmnet_shs_skb_list { struct sk_buff *head; struct sk_buff *tail; u64 num_parked_bytes; u32 num_parked_skbs; u32 skb_load; }; struct rmnet_shs_skbn_s { struct list_head node_id; /*list head for per cpu flow table*/ struct net_device *dev; struct rmnet_shs_wq_hstat_s *hstats; /*stats meta data*/ struct rmnet_shs_skb_list skb_list; /*list to park packets*/ struct hlist_node list; /*list head for hash table*/ u64 num_skb; /* num skbs received*/ u64 num_skb_bytes; /* num bytes received*/ u32 queue_head; /* n/w stack CPU pkt processing queue head */ u32 hash; /*incoming hash*/ u16 map_index; /* rps map index assigned*/ u16 map_cpu; /* rps cpu for this flow*/ u16 skb_tport_proto; /* Transport protocol associated with this flow*/ u8 is_shs_enabled; /*Is SHS enabled for this flow*/ }; enum rmnet_shs_tmr_force_flush_state_e { RMNET_SHS_FLUSH_OFF, RMNET_SHS_FLUSH_ON, RMNET_SHS_FLUSH_DONE }; enum rmnet_shs_switch_reason_e { RMNET_SHS_SWITCH_INSTANT_RATE, RMNET_SHS_SWITCH_WQ_RATE, RMNET_SHS_OOO_PACKET_SWITCH, RMNET_SHS_OOO_PACKET_TOTAL, RMNET_SHS_SWITCH_PACKET_BURST, RMNET_SHS_SWITCH_CORE_BACKLOG, RMNET_SHS_SWITCH_MAX_REASON }; enum rmnet_shs_dl_ind_state { RMNET_SHS_HDR_PENDING, RMNET_SHS_END_PENDING, RMNET_SHS_IND_COMPLETE, RMNET_SHS_DL_IND_MAX_STATE }; enum rmnet_shs_flush_reason_e { RMNET_SHS_FLUSH_PKT_LIMIT, RMNET_SHS_FLUSH_BYTE_LIMIT, RMNET_SHS_FLUSH_TIMER_EXPIRY, RMNET_SHS_FLUSH_RX_DL_TRAILER, RMNET_SHS_FLUSH_INV_DL_IND, RMNET_SHS_FLUSH_WQ_FB_FLUSH, RMNET_SHS_FLUSH_WQ_CORE_FLUSH, RMNET_SHS_FLUSH_PSH_PKT_FLUSH, RMNET_SHS_FLUSH_MAX_REASON }; struct flow_buff { struct sk_buff *skb; struct flow_buff *next; }; struct rmnet_shs_flush_work { struct work_struct work; struct rmnet_port *port; }; struct rmnet_shs_cpu_node_s { struct list_head node_list_id; u32 qhead; u32 qtail; u32 qdiff; u32 parkedlen; u32 seg; u8 prio; u8 wqprio; }; enum rmnet_shs_trace_func { RMNET_SHS_MODULE, RMNET_SHS_CPU_NODE, RMNET_SHS_SKB_STAMPING, RMNET_SHS_SKB_CAN_GRO, RMNET_SHS_DELIVER_SKB, RMNET_SHS_CORE_CFG, RMNET_SHS_HASH_MAP, RMNET_SHS_ASSIGN, RMNET_SHS_FLUSH, RMNET_SHS_DL_MRK, }; enum rmnet_shs_flush_context { RMNET_RX_CTXT, RMNET_WQ_CTXT, RMNET_MAX_CTXT }; /* Trace events and functions */ enum rmnet_shs_trace_evt { RMNET_SHS_MODULE_INIT, RMNET_SHS_MODULE_INIT_WQ, RMNET_SHS_MODULE_GOING_DOWN, RMNET_SHS_MODULE_EXIT, RMNET_SHS_CPU_NODE_FUNC_START, RMNET_SHS_CPU_NODE_FUNC_ADD, RMNET_SHS_CPU_NODE_FUNC_MOVE, RMNET_SHS_CPU_NODE_FUNC_REMOVE, RMNET_SHS_CPU_NODE_FUNC_END, RMNET_SHS_SKB_STAMPING_START, RMNET_SHS_SKB_STAMPING_END, RMNET_SHS_SKB_CAN_GRO_START, RMNET_SHS_SKB_CAN_GRO_END, RMNET_SHS_DELIVER_SKB_START, RMNET_SHS_DELIVER_SKB_END, RMNET_SHS_CORE_CFG_START, RMNET_SHS_CORE_CFG_NUM_LO_CORES, RMNET_SHS_CORE_CFG_NUM_HI_CORES, RMNET_SHS_CORE_CFG_CHK_HI_CPU, RMNET_SHS_CORE_CFG_CHK_LO_CPU, RMNET_SHS_CORE_CFG_GET_QHEAD, RMNET_SHS_CORE_CFG_GET_QTAIL, RMNET_SHS_CORE_CFG_GET_CPU_PROC_PARAMS, RMNET_SHS_CORE_CFG_END, RMNET_SHS_HASH_MAP_START, RMNET_SHS_HASH_MAP_IDX_TO_STAMP, RMNET_SHS_HASH_MAP_FORM_HASH, RMNET_SHS_HASH_MAP_END, RMNET_SHS_ASSIGN_START, RMNET_SHS_ASSIGN_GET_NEW_FLOW_CPU, RMNET_SHS_ASSIGN_MATCH_FLOW_NODE_START, RMNET_SHS_ASSIGN_MATCH_FLOW_COMPLETE, RMNET_SHS_ASSIGN_PARK_PKT_COMPLETE, RMNET_SHS_ASSIGN_PARK_TMR_START, RMNET_SHS_ASSIGN_PARK_TMR_CANCEL, RMNET_SHS_ASSIGN_MASK_CHNG, RMNET_SHS_ASSIGN_CRIT_ERROR_NO_MSK_SET, RMNET_SHS_ASSIGN_CRIT_ERROR_NO_SHS_REQD, RMNET_SHS_ASSIGN_END, RMNET_SHS_FLUSH_START, RMNET_SHS_FLUSH_PARK_TMR_EXPIRY, RMNET_SHS_FLUSH_PARK_TMR_RESTART, RMNET_SHS_FLUSH_DELAY_WQ_TRIGGER, RMNET_SHS_FLUSH_DELAY_WQ_START, RMNET_SHS_FLUSH_DELAY_WQ_END, RMNET_SHS_FLUSH_FORCE_TRIGGER, RMNET_SHS_FLUSH_BYTE_LIMIT_TRIGGER, RMNET_SHS_FLUSH_PKT_LIMIT_TRIGGER, RMNET_SHS_FLUSH_DL_MRK_TRLR_HDLR_START, RMNET_SHS_FLUSH_DL_MRK_TRLR_HDLR_END, RMNET_SHS_FLUSH_CHK_AND_FLUSH_NODE_START, RMNET_SHS_FLUSH_NODE_START, RMNET_SHS_FLUSH_CHK_NODE_CAN_FLUSH, RMNET_SHS_FLUSH_NODE_CORE_SWITCH, RMNET_SHS_FLUSH_NODE_END, RMNET_SHS_FLUSH_CHK_AND_FLUSH_NODE_END, RMNET_SHS_FLUSH_END, RMNET_SHS_DL_MRK_START, RMNET_SHS_DL_MRK_HDR_HDLR_START, RMNET_SHS_DL_MRK_HDR_HDLR_END, RMNET_SHS_DL_MRK_TRLR_START, RMNET_SHS_DL_MRK_TRLR_HDLR_END, RMNET_SHS_DL_MRK_TRLR_END, RMNET_SHS_DL_MRK_END, }; extern struct rmnet_shs_flush_work shs_delayed_work; extern spinlock_t rmnet_shs_ht_splock; extern struct hlist_head RMNET_SHS_HT[1 << (RMNET_SHS_HT_SIZE)]; /* rmnet based functions that we rely on*/ extern void rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port); extern int (*rmnet_shs_skb_entry)(struct sk_buff *skb, struct rmnet_port *port); int rmnet_shs_is_lpwr_cpu(u16 cpu); void rmnet_shs_cancel_table(void); void rmnet_shs_rx_wq_init(void); unsigned int rmnet_shs_rx_wq_exit(void); int rmnet_shs_get_mask_len(u8 mask); int rmnet_shs_chk_and_flush_node(struct rmnet_shs_skbn_s *node, u8 force_flush, u8 ctxt); void rmnet_shs_dl_hdr_handler_v2(struct rmnet_map_dl_ind_hdr *dlhdr, struct rmnet_map_control_command_header *qcmd); void rmnet_shs_dl_trl_handler_v2(struct rmnet_map_dl_ind_trl *dltrl, struct rmnet_map_control_command_header *qcmd); void rmnet_shs_dl_hdr_handler(struct rmnet_map_dl_ind_hdr *dlhdr); void rmnet_shs_dl_trl_handler(struct rmnet_map_dl_ind_trl *dltrl); void rmnet_shs_assign(struct sk_buff *skb, struct rmnet_port *port); void rmnet_shs_flush_table(u8 is_force_flush, u8 ctxt); void rmnet_shs_cpu_node_remove(struct rmnet_shs_skbn_s *node); void rmnet_shs_init(struct net_device *dev, struct net_device *vnd); void rmnet_shs_exit(unsigned int cpu_switch); void rmnet_shs_ps_on_hdlr(void *port); void rmnet_shs_ps_off_hdlr(void *port); void rmnet_shs_update_cpu_proc_q_all_cpus(void); void rmnet_shs_clear_node(struct rmnet_shs_skbn_s *node, u8 ctxt); u32 rmnet_shs_get_cpu_qhead(u8 cpu_num); #endif /* _RMNET_SHS_H_ */