1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
3 * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved.
9 net_dim_get_rx_moderation(u8 cq_period_mode
, int ix
)
11 struct dim_cq_moder cq_moder
= rx_profile
[cq_period_mode
][ix
];
13 cq_moder
.cq_period_mode
= cq_period_mode
;
16 EXPORT_SYMBOL(net_dim_get_rx_moderation
);
19 net_dim_get_def_rx_moderation(u8 cq_period_mode
)
21 u8 profile_ix
= cq_period_mode
== DIM_CQ_PERIOD_MODE_START_FROM_CQE
?
22 NET_DIM_DEF_PROFILE_CQE
: NET_DIM_DEF_PROFILE_EQE
;
24 return net_dim_get_rx_moderation(cq_period_mode
, profile_ix
);
26 EXPORT_SYMBOL(net_dim_get_def_rx_moderation
);
29 net_dim_get_tx_moderation(u8 cq_period_mode
, int ix
)
31 struct dim_cq_moder cq_moder
= tx_profile
[cq_period_mode
][ix
];
33 cq_moder
.cq_period_mode
= cq_period_mode
;
36 EXPORT_SYMBOL(net_dim_get_tx_moderation
);
39 net_dim_get_def_tx_moderation(u8 cq_period_mode
)
41 u8 profile_ix
= cq_period_mode
== DIM_CQ_PERIOD_MODE_START_FROM_CQE
?
42 NET_DIM_DEF_PROFILE_CQE
: NET_DIM_DEF_PROFILE_EQE
;
44 return net_dim_get_tx_moderation(cq_period_mode
, profile_ix
);
46 EXPORT_SYMBOL(net_dim_get_def_tx_moderation
);
48 static int net_dim_step(struct dim
*dim
)
50 if (dim
->tired
== (NET_DIM_PARAMS_NUM_PROFILES
* 2))
53 switch (dim
->tune_state
) {
54 case DIM_PARKING_ON_TOP
:
55 case DIM_PARKING_TIRED
:
58 if (dim
->profile_ix
== (NET_DIM_PARAMS_NUM_PROFILES
- 1))
64 if (dim
->profile_ix
== 0)
75 static void net_dim_exit_parking(struct dim
*dim
)
77 dim
->tune_state
= dim
->profile_ix
? DIM_GOING_LEFT
: DIM_GOING_RIGHT
;
81 static int net_dim_stats_compare(struct dim_stats
*curr
,
82 struct dim_stats
*prev
)
85 return curr
->bpms
? DIM_STATS_BETTER
: DIM_STATS_SAME
;
87 if (IS_SIGNIFICANT_DIFF(curr
->bpms
, prev
->bpms
))
88 return (curr
->bpms
> prev
->bpms
) ? DIM_STATS_BETTER
:
92 return curr
->ppms
? DIM_STATS_BETTER
:
95 if (IS_SIGNIFICANT_DIFF(curr
->ppms
, prev
->ppms
))
96 return (curr
->ppms
> prev
->ppms
) ? DIM_STATS_BETTER
:
100 return DIM_STATS_SAME
;
102 if (IS_SIGNIFICANT_DIFF(curr
->epms
, prev
->epms
))
103 return (curr
->epms
< prev
->epms
) ? DIM_STATS_BETTER
:
106 return DIM_STATS_SAME
;
109 static bool net_dim_decision(struct dim_stats
*curr_stats
, struct dim
*dim
)
111 int prev_state
= dim
->tune_state
;
112 int prev_ix
= dim
->profile_ix
;
116 switch (dim
->tune_state
) {
117 case DIM_PARKING_ON_TOP
:
118 stats_res
= net_dim_stats_compare(curr_stats
,
120 if (stats_res
!= DIM_STATS_SAME
)
121 net_dim_exit_parking(dim
);
124 case DIM_PARKING_TIRED
:
127 net_dim_exit_parking(dim
);
130 case DIM_GOING_RIGHT
:
132 stats_res
= net_dim_stats_compare(curr_stats
,
134 if (stats_res
!= DIM_STATS_BETTER
)
137 if (dim_on_top(dim
)) {
138 dim_park_on_top(dim
);
142 step_res
= net_dim_step(dim
);
145 dim_park_on_top(dim
);
155 if (prev_state
!= DIM_PARKING_ON_TOP
||
156 dim
->tune_state
!= DIM_PARKING_ON_TOP
)
157 dim
->prev_stats
= *curr_stats
;
159 return dim
->profile_ix
!= prev_ix
;
162 void net_dim(struct dim
*dim
, struct dim_sample end_sample
)
164 struct dim_stats curr_stats
;
167 switch (dim
->state
) {
168 case DIM_MEASURE_IN_PROGRESS
:
169 nevents
= BIT_GAP(BITS_PER_TYPE(u16
),
170 end_sample
.event_ctr
,
171 dim
->start_sample
.event_ctr
);
172 if (nevents
< DIM_NEVENTS
)
174 dim_calc_stats(&dim
->start_sample
, &end_sample
, &curr_stats
);
175 if (net_dim_decision(&curr_stats
, dim
)) {
176 dim
->state
= DIM_APPLY_NEW_PROFILE
;
177 schedule_work(&dim
->work
);
181 case DIM_START_MEASURE
:
182 dim_update_sample(end_sample
.event_ctr
, end_sample
.pkt_ctr
,
183 end_sample
.byte_ctr
, &dim
->start_sample
);
184 dim
->state
= DIM_MEASURE_IN_PROGRESS
;
186 case DIM_APPLY_NEW_PROFILE
:
190 EXPORT_SYMBOL(net_dim
);