linux/dim: Rename externally exposed macros
[muen/linux.git] / include / linux / net_dim.h
1 /*
2  * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
3  * Copyright (c) 2017-2018, Broadcom Limited. All rights reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses.  You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * OpenIB.org BSD license below:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      - Redistributions of source code must retain the above
16  *        copyright notice, this list of conditions and the following
17  *        disclaimer.
18  *
19  *      - Redistributions in binary form must reproduce the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer in the documentation and/or other materials
22  *        provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33
34 #ifndef NET_DIM_H
35 #define NET_DIM_H
36
37 #include <linux/module.h>
38 #include <linux/dim.h>
39
40 #define NET_DIM_PARAMS_NUM_PROFILES 5
41 /* Netdev dynamic interrupt moderation profiles */
42 #define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
43 #define NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE 128
44 #define NET_DIM_DEF_PROFILE_CQE 1
45 #define NET_DIM_DEF_PROFILE_EQE 1
46
47 /* All profiles sizes must be NET_PARAMS_DIM_NUM_PROFILES */
48 #define NET_DIM_RX_EQE_PROFILES { \
49         {1,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
50         {8,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
51         {64,  NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
52         {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
53         {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
54 }
55
56 #define NET_DIM_RX_CQE_PROFILES { \
57         {2,  256},             \
58         {8,  128},             \
59         {16, 64},              \
60         {32, 64},              \
61         {64, 64}               \
62 }
63
64 #define NET_DIM_TX_EQE_PROFILES { \
65         {1,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
66         {8,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
67         {32,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
68         {64,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
69         {128, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}   \
70 }
71
72 #define NET_DIM_TX_CQE_PROFILES { \
73         {5,  128},  \
74         {8,  64},  \
75         {16, 32},  \
76         {32, 32},  \
77         {64, 32}   \
78 }
79
80 static const struct net_dim_cq_moder
81 rx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
82         NET_DIM_RX_EQE_PROFILES,
83         NET_DIM_RX_CQE_PROFILES,
84 };
85
86 static const struct net_dim_cq_moder
87 tx_profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
88         NET_DIM_TX_EQE_PROFILES,
89         NET_DIM_TX_CQE_PROFILES,
90 };
91
92 static inline struct net_dim_cq_moder
93 net_dim_get_rx_moderation(u8 cq_period_mode, int ix)
94 {
95         struct net_dim_cq_moder cq_moder = rx_profile[cq_period_mode][ix];
96
97         cq_moder.cq_period_mode = cq_period_mode;
98         return cq_moder;
99 }
100
101 static inline struct net_dim_cq_moder
102 net_dim_get_def_rx_moderation(u8 cq_period_mode)
103 {
104         u8 profile_ix = cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
105                         NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
106
107         return net_dim_get_rx_moderation(cq_period_mode, profile_ix);
108 }
109
110 static inline struct net_dim_cq_moder
111 net_dim_get_tx_moderation(u8 cq_period_mode, int ix)
112 {
113         struct net_dim_cq_moder cq_moder = tx_profile[cq_period_mode][ix];
114
115         cq_moder.cq_period_mode = cq_period_mode;
116         return cq_moder;
117 }
118
119 static inline struct net_dim_cq_moder
120 net_dim_get_def_tx_moderation(u8 cq_period_mode)
121 {
122         u8 profile_ix = cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
123                         NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
124
125         return net_dim_get_tx_moderation(cq_period_mode, profile_ix);
126 }
127
128 static inline int net_dim_step(struct net_dim *dim)
129 {
130         if (dim->tired == (NET_DIM_PARAMS_NUM_PROFILES * 2))
131                 return DIM_TOO_TIRED;
132
133         switch (dim->tune_state) {
134         case DIM_PARKING_ON_TOP:
135         case DIM_PARKING_TIRED:
136                 break;
137         case DIM_GOING_RIGHT:
138                 if (dim->profile_ix == (NET_DIM_PARAMS_NUM_PROFILES - 1))
139                         return DIM_ON_EDGE;
140                 dim->profile_ix++;
141                 dim->steps_right++;
142                 break;
143         case DIM_GOING_LEFT:
144                 if (dim->profile_ix == 0)
145                         return DIM_ON_EDGE;
146                 dim->profile_ix--;
147                 dim->steps_left++;
148                 break;
149         }
150
151         dim->tired++;
152         return DIM_STEPPED;
153 }
154
155 static inline void net_dim_exit_parking(struct net_dim *dim)
156 {
157         dim->tune_state = dim->profile_ix ? DIM_GOING_LEFT :
158                                           DIM_GOING_RIGHT;
159         net_dim_step(dim);
160 }
161
162 static inline int net_dim_stats_compare(struct dim_stats *curr,
163                                         struct dim_stats *prev)
164 {
165         if (!prev->bpms)
166                 return curr->bpms ? DIM_STATS_BETTER :
167                                     DIM_STATS_SAME;
168
169         if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
170                 return (curr->bpms > prev->bpms) ? DIM_STATS_BETTER :
171                                                    DIM_STATS_WORSE;
172
173         if (!prev->ppms)
174                 return curr->ppms ? DIM_STATS_BETTER :
175                                     DIM_STATS_SAME;
176
177         if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
178                 return (curr->ppms > prev->ppms) ? DIM_STATS_BETTER :
179                                                    DIM_STATS_WORSE;
180
181         if (!prev->epms)
182                 return DIM_STATS_SAME;
183
184         if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
185                 return (curr->epms < prev->epms) ? DIM_STATS_BETTER :
186                                                    DIM_STATS_WORSE;
187
188         return DIM_STATS_SAME;
189 }
190
191 static inline bool net_dim_decision(struct dim_stats *curr_stats,
192                                     struct net_dim *dim)
193 {
194         int prev_state = dim->tune_state;
195         int prev_ix = dim->profile_ix;
196         int stats_res;
197         int step_res;
198
199         switch (dim->tune_state) {
200         case DIM_PARKING_ON_TOP:
201                 stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
202                 if (stats_res != DIM_STATS_SAME)
203                         net_dim_exit_parking(dim);
204                 break;
205
206         case DIM_PARKING_TIRED:
207                 dim->tired--;
208                 if (!dim->tired)
209                         net_dim_exit_parking(dim);
210                 break;
211
212         case DIM_GOING_RIGHT:
213         case DIM_GOING_LEFT:
214                 stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
215                 if (stats_res != DIM_STATS_BETTER)
216                         dim_turn(dim);
217
218                 if (dim_on_top(dim)) {
219                         dim_park_on_top(dim);
220                         break;
221                 }
222
223                 step_res = net_dim_step(dim);
224                 switch (step_res) {
225                 case DIM_ON_EDGE:
226                         dim_park_on_top(dim);
227                         break;
228                 case DIM_TOO_TIRED:
229                         dim_park_tired(dim);
230                         break;
231                 }
232
233                 break;
234         }
235
236         if (prev_state != DIM_PARKING_ON_TOP ||
237             dim->tune_state != DIM_PARKING_ON_TOP)
238                 dim->prev_stats = *curr_stats;
239
240         return dim->profile_ix != prev_ix;
241 }
242
243 static inline void net_dim(struct net_dim *dim,
244                            struct net_dim_sample end_sample)
245 {
246         struct dim_stats curr_stats;
247         u16 nevents;
248
249         switch (dim->state) {
250         case DIM_MEASURE_IN_PROGRESS:
251                 nevents = BIT_GAP(BITS_PER_TYPE(u16),
252                                   end_sample.event_ctr,
253                                   dim->start_sample.event_ctr);
254                 if (nevents < DIM_NEVENTS)
255                         break;
256                 dim_calc_stats(&dim->start_sample, &end_sample, &curr_stats);
257                 if (net_dim_decision(&curr_stats, dim)) {
258                         dim->state = DIM_APPLY_NEW_PROFILE;
259                         schedule_work(&dim->work);
260                         break;
261                 }
262                 /* fall through */
263         case DIM_START_MEASURE:
264                 net_dim_sample(end_sample.event_ctr, end_sample.pkt_ctr, end_sample.byte_ctr,
265                                &dim->start_sample);
266                 dim->state = DIM_MEASURE_IN_PROGRESS;
267                 break;
268         case DIM_APPLY_NEW_PROFILE:
269                 break;
270         }
271 }
272
273 #endif /* NET_DIM_H */