1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
3 * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved.
10 * There are different set of profiles for each CQ period mode.
11 * There are different set of profiles for RX/TX CQs.
12 * Each profile size must be of NET_DIM_PARAMS_NUM_PROFILES
14 #define NET_DIM_PARAMS_NUM_PROFILES 5
15 #define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
16 #define NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE 128
17 #define NET_DIM_DEF_PROFILE_CQE 1
18 #define NET_DIM_DEF_PROFILE_EQE 1
20 #define NET_DIM_RX_EQE_PROFILES { \
21 {1, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
22 {8, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
23 {64, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
24 {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
25 {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
28 #define NET_DIM_RX_CQE_PROFILES { \
36 #define NET_DIM_TX_EQE_PROFILES { \
37 {1, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
38 {8, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
39 {32, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
40 {64, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}, \
41 {128, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE} \
44 #define NET_DIM_TX_CQE_PROFILES { \
52 static const struct dim_cq_moder
53 rx_profile
[DIM_CQ_PERIOD_NUM_MODES
][NET_DIM_PARAMS_NUM_PROFILES
] = {
54 NET_DIM_RX_EQE_PROFILES
,
55 NET_DIM_RX_CQE_PROFILES
,
58 static const struct dim_cq_moder
59 tx_profile
[DIM_CQ_PERIOD_NUM_MODES
][NET_DIM_PARAMS_NUM_PROFILES
] = {
60 NET_DIM_TX_EQE_PROFILES
,
61 NET_DIM_TX_CQE_PROFILES
,
65 net_dim_get_rx_moderation(u8 cq_period_mode
, int ix
)
67 struct dim_cq_moder cq_moder
= rx_profile
[cq_period_mode
][ix
];
69 cq_moder
.cq_period_mode
= cq_period_mode
;
72 EXPORT_SYMBOL(net_dim_get_rx_moderation
);
75 net_dim_get_def_rx_moderation(u8 cq_period_mode
)
77 u8 profile_ix
= cq_period_mode
== DIM_CQ_PERIOD_MODE_START_FROM_CQE
?
78 NET_DIM_DEF_PROFILE_CQE
: NET_DIM_DEF_PROFILE_EQE
;
80 return net_dim_get_rx_moderation(cq_period_mode
, profile_ix
);
82 EXPORT_SYMBOL(net_dim_get_def_rx_moderation
);
85 net_dim_get_tx_moderation(u8 cq_period_mode
, int ix
)
87 struct dim_cq_moder cq_moder
= tx_profile
[cq_period_mode
][ix
];
89 cq_moder
.cq_period_mode
= cq_period_mode
;
92 EXPORT_SYMBOL(net_dim_get_tx_moderation
);
95 net_dim_get_def_tx_moderation(u8 cq_period_mode
)
97 u8 profile_ix
= cq_period_mode
== DIM_CQ_PERIOD_MODE_START_FROM_CQE
?
98 NET_DIM_DEF_PROFILE_CQE
: NET_DIM_DEF_PROFILE_EQE
;
100 return net_dim_get_tx_moderation(cq_period_mode
, profile_ix
);
102 EXPORT_SYMBOL(net_dim_get_def_tx_moderation
);
104 static int net_dim_step(struct dim
*dim
)
106 if (dim
->tired
== (NET_DIM_PARAMS_NUM_PROFILES
* 2))
107 return DIM_TOO_TIRED
;
109 switch (dim
->tune_state
) {
110 case DIM_PARKING_ON_TOP
:
111 case DIM_PARKING_TIRED
:
113 case DIM_GOING_RIGHT
:
114 if (dim
->profile_ix
== (NET_DIM_PARAMS_NUM_PROFILES
- 1))
120 if (dim
->profile_ix
== 0)
131 static void net_dim_exit_parking(struct dim
*dim
)
133 dim
->tune_state
= dim
->profile_ix
? DIM_GOING_LEFT
: DIM_GOING_RIGHT
;
137 static int net_dim_stats_compare(struct dim_stats
*curr
,
138 struct dim_stats
*prev
)
141 return curr
->bpms
? DIM_STATS_BETTER
: DIM_STATS_SAME
;
143 if (IS_SIGNIFICANT_DIFF(curr
->bpms
, prev
->bpms
))
144 return (curr
->bpms
> prev
->bpms
) ? DIM_STATS_BETTER
:
148 return curr
->ppms
? DIM_STATS_BETTER
:
151 if (IS_SIGNIFICANT_DIFF(curr
->ppms
, prev
->ppms
))
152 return (curr
->ppms
> prev
->ppms
) ? DIM_STATS_BETTER
:
156 return DIM_STATS_SAME
;
158 if (IS_SIGNIFICANT_DIFF(curr
->epms
, prev
->epms
))
159 return (curr
->epms
< prev
->epms
) ? DIM_STATS_BETTER
:
162 return DIM_STATS_SAME
;
165 static bool net_dim_decision(struct dim_stats
*curr_stats
, struct dim
*dim
)
167 int prev_state
= dim
->tune_state
;
168 int prev_ix
= dim
->profile_ix
;
172 switch (dim
->tune_state
) {
173 case DIM_PARKING_ON_TOP
:
174 stats_res
= net_dim_stats_compare(curr_stats
,
176 if (stats_res
!= DIM_STATS_SAME
)
177 net_dim_exit_parking(dim
);
180 case DIM_PARKING_TIRED
:
183 net_dim_exit_parking(dim
);
186 case DIM_GOING_RIGHT
:
188 stats_res
= net_dim_stats_compare(curr_stats
,
190 if (stats_res
!= DIM_STATS_BETTER
)
193 if (dim_on_top(dim
)) {
194 dim_park_on_top(dim
);
198 step_res
= net_dim_step(dim
);
201 dim_park_on_top(dim
);
211 if (prev_state
!= DIM_PARKING_ON_TOP
||
212 dim
->tune_state
!= DIM_PARKING_ON_TOP
)
213 dim
->prev_stats
= *curr_stats
;
215 return dim
->profile_ix
!= prev_ix
;
218 void net_dim(struct dim
*dim
, struct dim_sample end_sample
)
220 struct dim_stats curr_stats
;
223 switch (dim
->state
) {
224 case DIM_MEASURE_IN_PROGRESS
:
225 nevents
= BIT_GAP(BITS_PER_TYPE(u16
),
226 end_sample
.event_ctr
,
227 dim
->start_sample
.event_ctr
);
228 if (nevents
< DIM_NEVENTS
)
230 dim_calc_stats(&dim
->start_sample
, &end_sample
, &curr_stats
);
231 if (net_dim_decision(&curr_stats
, dim
)) {
232 dim
->state
= DIM_APPLY_NEW_PROFILE
;
233 schedule_work(&dim
->work
);
237 case DIM_START_MEASURE
:
238 dim_update_sample(end_sample
.event_ctr
, end_sample
.pkt_ctr
,
239 end_sample
.byte_ctr
, &dim
->start_sample
);
240 dim
->state
= DIM_MEASURE_IN_PROGRESS
;
242 case DIM_APPLY_NEW_PROFILE
:
246 EXPORT_SYMBOL(net_dim
);