From 59eb3e5550a8b4bd61d9bb95f659699bbf56090d Mon Sep 17 00:00:00 2001 From: Vladimir Sokolovsky Date: Tue, 17 Jul 2018 13:42:51 -0500 Subject: [PATCH] Added macros and headers required by MLX4/5 drivers on RHEL7.5 Signed-off-by: Vladimir Sokolovsky --- config/rdma.m4 | 375 ++++++++++++++++++++++++++++++++++- include/linux/bpf.h | 36 ++++ include/linux/compat-2.6.h | 1 + include/linux/compat-4.17.h | 23 +++ include/linux/dcbnl.h | 65 ++++++ include/linux/net_dim.h | 380 ++++++++++++++++++++++++++++++++++++ include/linux/netdevice.h | 20 +- 7 files changed, 897 insertions(+), 3 deletions(-) create mode 100644 include/linux/bpf.h create mode 100644 include/linux/compat-4.17.h create mode 100644 include/linux/dcbnl.h create mode 100644 include/linux/net_dim.h diff --git a/config/rdma.m4 b/config/rdma.m4 index 2773ecb..6469093 100644 --- a/config/rdma.m4 +++ b/config/rdma.m4 @@ -3180,6 +3180,23 @@ AC_DEFUN([LINUX_CONFIG_COMPAT], AC_MSG_RESULT(no) ]) + AC_MSG_CHECKING([if struct ifla_vf_stats has rx_dropped]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct ifla_vf_stats stat = { + .rx_dropped = 0, + }; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IFLA_VF_STATS_RX_DROPPED, 1, + [struct ifla_vf_stats has rx_dropped]) + ],[ + AC_MSG_RESULT(no) + ]) + AC_MSG_CHECKING([if struct net_device_ops has ndo_set_vf_guid]) LB_LINUX_TRY_COMPILE([ #include @@ -3246,6 +3263,23 @@ AC_DEFUN([LINUX_CONFIG_COMPAT], AC_MSG_RESULT(no) ]) + AC_MSG_CHECKING([if struct xdp_buff has rxq]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct xdp_buff x = { + .rxq = NULL, + }; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_XDP_BUFF_RXQ, 1, + [struct xdp_buff has rxq]) + ],[ + AC_MSG_RESULT(no) + ]) + AC_MSG_CHECKING([if firmware.h has request_firmware_direct]) LB_LINUX_TRY_COMPILE([ #include @@ -3515,6 +3549,23 @@ AC_DEFUN([LINUX_CONFIG_COMPAT], AC_MSG_RESULT(no) ]) + AC_MSG_CHECKING([if if_link.h has IFLA_VF_IB_NODE_PORT_GUID]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + int type = IFLA_VF_IB_NODE_GUID; + + type = IFLA_VF_IB_PORT_GUID; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IFLA_VF_IB_NODE_PORT_GUID, 1, + [trust is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + AC_MSG_CHECKING([if skbuff.h skb_shared_info has UNION tx_flags]) LB_LINUX_TRY_COMPILE([ #include @@ -3666,6 +3717,21 @@ AC_DEFUN([LINUX_CONFIG_COMPAT], AC_MSG_RESULT(no) ]) + AC_MSG_CHECKING([if net/tc_act/tc_mirred.h has tcf_mirred_dev]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + tcf_mirred_dev(NULL); + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_TCF_MIRRED_DEV, 1, + [tcf_mirred_dev is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + AC_MSG_CHECKING([if enum tc_fl_command has TC_CLSFLOWER_STATS]) LB_LINUX_TRY_COMPILE([ #include @@ -4475,7 +4541,24 @@ AC_DEFUN([LINUX_CONFIG_COMPAT], AC_MSG_RESULT(no) ]) - AC_MSG_CHECKING([if mm has register_netdevice_notifier_rh]) + AC_MSG_CHECKING([if netdevice.h has struct netdev_notifier_info]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct netdev_notifier_info x = { + .dev = NULL, + }; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NETDEV_NOTIFIER_INFO, 1, + [struct netdev_notifier_info is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if netdevice.h has register_netdevice_notifier_rh]) LB_LINUX_TRY_COMPILE([ #include ],[ @@ -4567,6 +4650,23 @@ AC_DEFUN([LINUX_CONFIG_COMPAT], AC_MSG_RESULT(no) ]) + AC_MSG_CHECKING([if struct net_device_ops has ndo_change_mtu_rh74]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct net_device_ops netdev_ops = { + .ndo_change_mtu_rh74 = NULL, + }; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NDO_CHANGE_MTU_RH74, 1, + [ndo_change_mtu_rh74 is defined in net_device_ops]) + ],[ + AC_MSG_RESULT(no) + ]) + AC_MSG_CHECKING([if struct net_device_ops_extended has ndo_set_vf_vlan]) LB_LINUX_TRY_COMPILE([ #include @@ -5936,6 +6036,279 @@ AC_DEFUN([LINUX_CONFIG_COMPAT], ],[ AC_MSG_RESULT(no) ]) + + AC_MSG_CHECKING([if skbuff.h has build_skb]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + build_skb(NULL, 0); + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BUILD_SKB, 1, + [build_skb is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if include/net/devlink.h exists]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_DEVLINK_H, 1, + [include/net/devlink.h exists]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if net_device_ops_extended has ndo_get_phys_port_id]) + LB_LINUX_TRY_COMPILE([ + #include + + int get_phys_port_name(struct net_device *dev, + char *name, size_t len) + { + return 0; + } + ],[ + struct net_device_ops_extended netdev_ops; + + netdev_ops.ndo_get_phys_port_name = get_phys_port_name; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NDO_GET_PHYS_PORT_NAME_EXTENDED, 1, + [ is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if struct net_device_ops ndo_vlan_rx_add_vid has 2 parameters and returns int]) + LB_LINUX_TRY_COMPILE([ + #include + + int vlan_rx_add_vid(struct net_device *dev, u16 vid) + { + return 0; + } + ],[ + struct net_device_ops netdev_ops = { + .ndo_vlan_rx_add_vid = vlan_rx_add_vid, + }; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NDO_RX_ADD_VID_HAS_2_PARAMS_RET_INT, 1, + [ndo_vlan_rx_add_vid has 2 parameters and returns int]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if netdev_extended has wanted_features]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct net_device *dev = NULL; + + netdev_extended(dev)->wanted_features = 0; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NETDEV_EXTENDED_WANTED_FEATURES, 1, + [ is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if netdevice.h has IFF_UNICAST_FLT]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + int x = IFF_UNICAST_FLT; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NETDEV_IFF_UNICAST_FLT, 1, + [IFF_UNICAST_FLT is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if struct net_device has wanted_features]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct net_device dev; + dev.wanted_features = 0; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NETDEV_WANTED_FEATURES, 1, + [wanted_features is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if dcbnl.h has struct ieee_pfc]) + LB_LINUX_TRY_COMPILE([ + #include + #include + ],[ + struct ieee_pfc x; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_STRUCT_IEEE_PFC, 1, + [ieee_pfc is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if struct tc_to_netdev has egress_dev]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct tc_to_netdev x = { + .egress_dev = false, + }; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_TC_TO_NETDEV_EGRESS_DEV, 1, + [struct tc_to_netdev has egress_dev]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if struct tc_to_netdev has tc]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct tc_to_netdev x; + x.tc = 0; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_TC_TO_NETDEV_TC, 1, + [struct tc_to_netdev has tc]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if linux/bpf_trace has trace_xdp_exception]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + trace_xdp_exception(NULL, NULL, 0); + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_TRACE_XDP_EXCEPTION, 1, + [trace_xdp_exception is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if filter.h has struct xdp_buff]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct xdp_buff d = { + .data = NULL, + .data_end = NULL, + }; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_XDP_BUFF, 1, + [xdp is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if filter.h struct xdp_buff has data_hard_start]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct xdp_buff d = { + .data_hard_start = NULL, + }; + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_XDP_BUFF_DATA_HARD_START, 1, + [xdp_buff data_hard_start is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if filter.h has xdp_set_data_meta_invalid]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + struct xdp_buff d; + xdp_set_data_meta_invalid(&d); + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_XDP_SET_DATA_META_INVALID, 1, + [xdp_set_data_meta_invalid is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if linux/bpf.h has bpf_prog_sub]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + bpf_prog_sub(NULL, 0); + + return 0; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BPF_PROG_SUB, 1, + [bpf_prog_sub is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + AC_MSG_CHECKING([if netdevice.h has enum netdev_lag_tx_type]) + LB_LINUX_TRY_COMPILE([ + #include + ],[ + enum netdev_lag_tx_type x; + x = 0; + + return x; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LAG_TX_TYPE, 1, + [enum netdev_lag_tx_type is defined]) + ],[ + AC_MSG_RESULT(no) + ]) + + LB_CHECK_SYMBOL_EXPORT([bpf_prog_inc], + [kernel/bpf/syscall.c], + [AC_DEFINE(HAVE_BPF_PROG_INC_EXPORTED, 1, + [bpf_prog_inc is exported by the kernel])], + []) ]) # # COMPAT_CONFIG_HEADERS diff --git a/include/linux/bpf.h b/include/linux/bpf.h new file mode 100644 index 0000000..b90db74 --- /dev/null +++ b/include/linux/bpf.h @@ -0,0 +1,36 @@ +#ifndef _COMPAT_LINUX_BPF_H +#define _COMPAT_LINUX_BPF_H + +#include "../../compat/config.h" + +#ifdef HAVE_LINUX_BPF_H +#include_next + +#ifndef HAVE_BPF_PROG_INC_EXPORTED +#define bpf_prog_inc LINUX_BACKPORT(bpf_prog_inc) +static inline struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) +{ + return bpf_prog_add(prog, 1); +} +#endif + +#ifndef HAVE_BPF_PROG_SUB +#include +static inline void bpf_prog_sub(struct bpf_prog *prog, int i) +{ + /* Only to be used for undoing previous bpf_prog_add() in some + * error path. We still know that another entity in our call + * path holds a reference to the program, thus atomic_sub() can + * be safely used in such cases! + */ + WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0); +} +#endif + +#endif /* HAVE_LINUX_BPF_H */ + +#ifndef XDP_PACKET_HEADROOM +#define XDP_PACKET_HEADROOM 256 +#endif + +#endif /* _COMPAT_LINUX_BPF_H */ diff --git a/include/linux/compat-2.6.h b/include/linux/compat-2.6.h index 028597a..a31f860 100644 --- a/include/linux/compat-2.6.h +++ b/include/linux/compat-2.6.h @@ -55,6 +55,7 @@ void backport_dependency_symbol(void); #include #include #include +#include #endif /* CONFIG_COMPAT_RDMA */ #endif /* LINUX_26_COMPAT_H */ diff --git a/include/linux/compat-4.17.h b/include/linux/compat-4.17.h new file mode 100644 index 0000000..63d4fd5 --- /dev/null +++ b/include/linux/compat-4.17.h @@ -0,0 +1,23 @@ +#ifndef LINUX_4_17_COMPAT_H +#define LINUX_4_17_COMPAT_H + +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)) + +#ifndef PFC_STORM_PREVENTION_AUTO +#define PFC_STORM_PREVENTION_AUTO 0xffff +#endif + +#ifndef PFC_STORM_PREVENTION_DISABLE +#define PFC_STORM_PREVENTION_DISABLE 0 +#endif + +#include +#ifndef ETHTOOL_PFC_PREVENTION_TOUT +#define ETHTOOL_PFC_PREVENTION_TOUT (ETHTOOL_TX_COPYBREAK + 1) +#endif + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)) */ + +#endif /* LINUX_4_17_COMPAT_H */ diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h new file mode 100644 index 0000000..987cbb6 --- /dev/null +++ b/include/linux/dcbnl.h @@ -0,0 +1,65 @@ +#ifndef LINUX_DCBNL_H +#define LINUX_DCBNL_H + +#include "../../compat/config.h" + +#include_next + +#ifndef HAVE_IEEE_GETQCN + +#ifndef HAVE_STRUCT_IEEE_QCN +enum dcbnl_cndd_states { + DCB_CNDD_RESET = 0, + DCB_CNDD_EDGE, + DCB_CNDD_INTERIOR, + DCB_CNDD_INTERIOR_READY, +}; + +struct ieee_qcn { + __u8 rpg_enable[IEEE_8021QAZ_MAX_TCS]; + __u32 rppp_max_rps[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_time_reset[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_byte_reset[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_threshold[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_max_rate[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_ai_rate[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_hai_rate[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_gd[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_min_dec_fac[IEEE_8021QAZ_MAX_TCS]; + __u32 rpg_min_rate[IEEE_8021QAZ_MAX_TCS]; + __u32 cndd_state_machine[IEEE_8021QAZ_MAX_TCS]; +}; +#endif /* HAVE_STRUCT_IEEE_QCN */ + +/* RH7.3 backported this struct, but it does not have + * all needed feilds as below + * */ +#define ieee_qcn_stats mlnx_ofed_ieee_qcn_stats +struct ieee_qcn_stats { + __u64 rppp_rp_centiseconds[IEEE_8021QAZ_MAX_TCS]; + __u32 rppp_created_rps[IEEE_8021QAZ_MAX_TCS]; + __u32 ignored_cnm[IEEE_8021QAZ_MAX_TCS]; + __u32 estimated_total_rate[IEEE_8021QAZ_MAX_TCS]; + __u32 cnms_handled_successfully[IEEE_8021QAZ_MAX_TCS]; + __u32 min_total_limiters_rate[IEEE_8021QAZ_MAX_TCS]; + __u32 max_total_limiters_rate[IEEE_8021QAZ_MAX_TCS]; +}; + +#endif + +#ifndef IEEE_8021QAZ_APP_SEL_DSCP +#define IEEE_8021QAZ_APP_SEL_DSCP 5 +#endif + +#ifndef HAVE_STRUCT_IEEE_PFC +struct ieee_pfc { + __u8 pfc_cap; + __u8 pfc_en; + __u8 mbc; + __u16 delay; + __u64 requests[IEEE_8021QAZ_MAX_TCS]; + __u64 indications[IEEE_8021QAZ_MAX_TCS]; +}; +#endif + +#endif /* LINUX_DCBNL_H */ diff --git a/include/linux/net_dim.h b/include/linux/net_dim.h new file mode 100644 index 0000000..29ed8fd --- /dev/null +++ b/include/linux/net_dim.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2016, Mellanox Technologies. All rights reserved. + * Copyright (c) 2017-2018, Broadcom Limited. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef NET_DIM_H +#define NET_DIM_H + +#include + +struct net_dim_cq_moder { + u16 usec; + u16 pkts; + u8 cq_period_mode; +}; + +struct net_dim_sample { + ktime_t time; + u32 pkt_ctr; + u32 byte_ctr; + u16 event_ctr; +}; + +struct net_dim_stats { + int ppms; /* packets per msec */ + int bpms; /* bytes per msec */ + int epms; /* events per msec */ +}; + +struct net_dim { /* Adaptive Moderation */ + u8 state; + struct net_dim_stats prev_stats; + struct net_dim_sample start_sample; + struct work_struct work; + u8 profile_ix; + u8 mode; + u8 tune_state; + u8 steps_right; + u8 steps_left; + u8 tired; +}; + +enum { + NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0x0, + NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE = 0x1, + NET_DIM_CQ_PERIOD_NUM_MODES +}; + +/* Adaptive moderation logic */ +enum { + NET_DIM_START_MEASURE, + NET_DIM_MEASURE_IN_PROGRESS, + NET_DIM_APPLY_NEW_PROFILE, +}; + +enum { + NET_DIM_PARKING_ON_TOP, + NET_DIM_PARKING_TIRED, + NET_DIM_GOING_RIGHT, + NET_DIM_GOING_LEFT, +}; + +enum { + NET_DIM_STATS_WORSE, + NET_DIM_STATS_SAME, + NET_DIM_STATS_BETTER, +}; + +enum { + NET_DIM_STEPPED, + NET_DIM_TOO_TIRED, + NET_DIM_ON_EDGE, +}; + +#define NET_DIM_PARAMS_NUM_PROFILES 5 +/* Adaptive moderation profiles */ +#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256 +#define NET_DIM_DEF_PROFILE_CQE 1 +#define NET_DIM_DEF_PROFILE_EQE 1 + +/* All profiles sizes must be NET_PARAMS_DIM_NUM_PROFILES */ +#define NET_DIM_EQE_PROFILES { \ + {1, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \ + {8, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \ + {64, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \ + {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \ + {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \ +} + +#define NET_DIM_CQE_PROFILES { \ + {2, 256}, \ + {8, 128}, \ + {16, 64}, \ + {32, 64}, \ + {64, 64} \ +} + +static const struct net_dim_cq_moder +profile[NET_DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = { + NET_DIM_EQE_PROFILES, + NET_DIM_CQE_PROFILES, +}; + +static inline struct net_dim_cq_moder net_dim_get_profile(u8 cq_period_mode, + int ix) +{ + struct net_dim_cq_moder cq_moder; + + cq_moder = profile[cq_period_mode][ix]; + cq_moder.cq_period_mode = cq_period_mode; + return cq_moder; +} + +static inline struct net_dim_cq_moder net_dim_get_def_profile(u8 rx_cq_period_mode) +{ + int default_profile_ix; + + if (rx_cq_period_mode == NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE) + default_profile_ix = NET_DIM_DEF_PROFILE_CQE; + else /* NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE */ + default_profile_ix = NET_DIM_DEF_PROFILE_EQE; + + return net_dim_get_profile(rx_cq_period_mode, default_profile_ix); +} + +static inline bool net_dim_on_top(struct net_dim *dim) +{ + switch (dim->tune_state) { + case NET_DIM_PARKING_ON_TOP: + case NET_DIM_PARKING_TIRED: + return true; + case NET_DIM_GOING_RIGHT: + return (dim->steps_left > 1) && (dim->steps_right == 1); + default: /* NET_DIM_GOING_LEFT */ + return (dim->steps_right > 1) && (dim->steps_left == 1); + } +} + +static inline void net_dim_turn(struct net_dim *dim) +{ + switch (dim->tune_state) { + case NET_DIM_PARKING_ON_TOP: + case NET_DIM_PARKING_TIRED: + break; + case NET_DIM_GOING_RIGHT: + dim->tune_state = NET_DIM_GOING_LEFT; + dim->steps_left = 0; + break; + case NET_DIM_GOING_LEFT: + dim->tune_state = NET_DIM_GOING_RIGHT; + dim->steps_right = 0; + break; + } +} + +static inline int net_dim_step(struct net_dim *dim) +{ + if (dim->tired == (NET_DIM_PARAMS_NUM_PROFILES * 2)) + return NET_DIM_TOO_TIRED; + + switch (dim->tune_state) { + case NET_DIM_PARKING_ON_TOP: + case NET_DIM_PARKING_TIRED: + break; + case NET_DIM_GOING_RIGHT: + if (dim->profile_ix == (NET_DIM_PARAMS_NUM_PROFILES - 1)) + return NET_DIM_ON_EDGE; + dim->profile_ix++; + dim->steps_right++; + break; + case NET_DIM_GOING_LEFT: + if (dim->profile_ix == 0) + return NET_DIM_ON_EDGE; + dim->profile_ix--; + dim->steps_left++; + break; + } + + dim->tired++; + return NET_DIM_STEPPED; +} + +static inline void net_dim_park_on_top(struct net_dim *dim) +{ + dim->steps_right = 0; + dim->steps_left = 0; + dim->tired = 0; + dim->tune_state = NET_DIM_PARKING_ON_TOP; +} + +static inline void net_dim_park_tired(struct net_dim *dim) +{ + dim->steps_right = 0; + dim->steps_left = 0; + dim->tune_state = NET_DIM_PARKING_TIRED; +} + +static inline void net_dim_exit_parking(struct net_dim *dim) +{ + dim->tune_state = dim->profile_ix ? NET_DIM_GOING_LEFT : + NET_DIM_GOING_RIGHT; + net_dim_step(dim); +} + +#define IS_SIGNIFICANT_DIFF(val, ref) \ + (((100UL * abs((val) - (ref))) / (ref)) > 10) /* more than 10% difference */ + +static inline int net_dim_stats_compare(struct net_dim_stats *curr, + struct net_dim_stats *prev) +{ + if (!prev->bpms) + return curr->bpms ? NET_DIM_STATS_BETTER : + NET_DIM_STATS_SAME; + + if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms)) + return (curr->bpms > prev->bpms) ? NET_DIM_STATS_BETTER : + NET_DIM_STATS_WORSE; + + if (!prev->ppms) + return curr->ppms ? NET_DIM_STATS_BETTER : + NET_DIM_STATS_SAME; + + if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms)) + return (curr->ppms > prev->ppms) ? NET_DIM_STATS_BETTER : + NET_DIM_STATS_WORSE; + + if (!prev->epms) + return NET_DIM_STATS_SAME; + + if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms)) + return (curr->epms < prev->epms) ? NET_DIM_STATS_BETTER : + NET_DIM_STATS_WORSE; + + return NET_DIM_STATS_SAME; +} + +static inline bool net_dim_decision(struct net_dim_stats *curr_stats, + struct net_dim *dim) +{ + int prev_state = dim->tune_state; + int prev_ix = dim->profile_ix; + int stats_res; + int step_res; + + switch (dim->tune_state) { + case NET_DIM_PARKING_ON_TOP: + stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats); + if (stats_res != NET_DIM_STATS_SAME) + net_dim_exit_parking(dim); + break; + + case NET_DIM_PARKING_TIRED: + dim->tired--; + if (!dim->tired) + net_dim_exit_parking(dim); + break; + + case NET_DIM_GOING_RIGHT: + case NET_DIM_GOING_LEFT: + stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats); + if (stats_res != NET_DIM_STATS_BETTER) + net_dim_turn(dim); + + if (net_dim_on_top(dim)) { + net_dim_park_on_top(dim); + break; + } + + step_res = net_dim_step(dim); + switch (step_res) { + case NET_DIM_ON_EDGE: + net_dim_park_on_top(dim); + break; + case NET_DIM_TOO_TIRED: + net_dim_park_tired(dim); + break; + } + + break; + } + + if ((prev_state != NET_DIM_PARKING_ON_TOP) || + (dim->tune_state != NET_DIM_PARKING_ON_TOP)) + dim->prev_stats = *curr_stats; + + return dim->profile_ix != prev_ix; +} + +static inline void net_dim_sample(u16 event_ctr, + u64 packets, + u64 bytes, + struct net_dim_sample *s) +{ + s->time = ktime_get(); + s->pkt_ctr = packets; + s->byte_ctr = bytes; + s->event_ctr = event_ctr; +} + +#define NET_DIM_NEVENTS 64 +#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) +#define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) & (BIT_ULL(bits) - 1)) + +static inline void net_dim_calc_stats(struct net_dim_sample *start, + struct net_dim_sample *end, + struct net_dim_stats *curr_stats) +{ + /* u32 holds up to 71 minutes, should be enough */ + u32 delta_us = ktime_us_delta(end->time, start->time); + u32 npkts = BIT_GAP(BITS_PER_TYPE(u32), end->pkt_ctr, start->pkt_ctr); + u32 nbytes = BIT_GAP(BITS_PER_TYPE(u32), end->byte_ctr, + start->byte_ctr); + + if (!delta_us) + return; + + curr_stats->ppms = DIV_ROUND_UP(npkts * USEC_PER_MSEC, delta_us); + curr_stats->bpms = DIV_ROUND_UP(nbytes * USEC_PER_MSEC, delta_us); + curr_stats->epms = DIV_ROUND_UP(NET_DIM_NEVENTS * USEC_PER_MSEC, + delta_us); +} + +static inline void net_dim(struct net_dim *dim, + struct net_dim_sample end_sample) +{ + struct net_dim_stats curr_stats; + u16 nevents; + + switch (dim->state) { + case NET_DIM_MEASURE_IN_PROGRESS: + nevents = BIT_GAP(BITS_PER_TYPE(u16), + end_sample.event_ctr, + dim->start_sample.event_ctr); + if (nevents < NET_DIM_NEVENTS) + break; + net_dim_calc_stats(&dim->start_sample, &end_sample, + &curr_stats); + if (net_dim_decision(&curr_stats, dim)) { + dim->state = NET_DIM_APPLY_NEW_PROFILE; + schedule_work(&dim->work); + break; + } + /* fall through */ + case NET_DIM_START_MEASURE: + dim->state = NET_DIM_MEASURE_IN_PROGRESS; + break; + case NET_DIM_APPLY_NEW_PROFILE: + break; + } +} + +#endif /* NET_DIM_H */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 6332329..4de00eb 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -16,6 +16,21 @@ #define ndo_bpf ndo_xdp #endif +static inline const char *netdev_reg_state(const struct net_device *dev) +{ + switch (dev->reg_state) { + case NETREG_UNINITIALIZED: return " (uninitialized)"; + case NETREG_REGISTERED: return ""; + case NETREG_UNREGISTERING: return " (unregistering)"; + case NETREG_UNREGISTERED: return " (unregistered)"; + case NETREG_RELEASED: return " (released)"; + case NETREG_DUMMY: return " (dummy)"; + } + + WARN_ONCE(1, "%s: unknown reg_state %d\n", dev->name, dev->reg_state); + return " (unknown)"; +} + #ifndef HAVE_TC_SETUP_QDISC_MQPRIO #define TC_SETUP_QDISC_MQPRIO TC_SETUP_MQPRIO @@ -47,9 +62,10 @@ do { \ netdev_level_once(KERN_INFO, dev, fmt, ##__VA_ARGS__) -#define netdev_WARN_ONCE(dev, condition, format, arg...) \ - WARN_ONCE(1, "netdevice: %s%s\n" format, netdev_name(dev) \ +#define netdev_WARN_ONCE(dev, format, args...) \ + WARN_ONCE(1, "netdevice: %s%s: " format, netdev_name(dev), \ netdev_reg_state(dev), ##args) + #endif /* netdev_WARN_ONCE */ #endif -- 2.41.0