xref: /openbmc/linux/kernel/irq/timings.c (revision 290fdc4b)
152a65ff5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0
2f3f59fbcSThomas Gleixner // Copyright (C) 2016, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
36aed82deSDaniel Lezcano #define pr_fmt(fmt) "irq_timings: " fmt
4f3f59fbcSThomas Gleixner 
5e1c92149SDaniel Lezcano #include <linux/kernel.h>
6b2d3d61aSDaniel Lezcano #include <linux/percpu.h>
7e1c92149SDaniel Lezcano #include <linux/slab.h>
8b2d3d61aSDaniel Lezcano #include <linux/static_key.h>
96aed82deSDaniel Lezcano #include <linux/init.h>
10b2d3d61aSDaniel Lezcano #include <linux/interrupt.h>
11e1c92149SDaniel Lezcano #include <linux/idr.h>
12b2d3d61aSDaniel Lezcano #include <linux/irq.h>
13bbba0e7cSDaniel Lezcano #include <linux/math64.h>
14bbba0e7cSDaniel Lezcano #include <linux/log2.h>
15e1c92149SDaniel Lezcano 
16e1c92149SDaniel Lezcano #include <trace/events/irq.h>
17b2d3d61aSDaniel Lezcano 
18b2d3d61aSDaniel Lezcano #include "internals.h"
19b2d3d61aSDaniel Lezcano 
20b2d3d61aSDaniel Lezcano DEFINE_STATIC_KEY_FALSE(irq_timing_enabled);
21b2d3d61aSDaniel Lezcano 
22b2d3d61aSDaniel Lezcano DEFINE_PER_CPU(struct irq_timings, irq_timings);
23b2d3d61aSDaniel Lezcano 
24e1c92149SDaniel Lezcano static DEFINE_IDR(irqt_stats);
25e1c92149SDaniel Lezcano 
irq_timings_enable(void)26b2d3d61aSDaniel Lezcano void irq_timings_enable(void)
27b2d3d61aSDaniel Lezcano {
28b2d3d61aSDaniel Lezcano 	static_branch_enable(&irq_timing_enabled);
29b2d3d61aSDaniel Lezcano }
30b2d3d61aSDaniel Lezcano 
irq_timings_disable(void)31b2d3d61aSDaniel Lezcano void irq_timings_disable(void)
32b2d3d61aSDaniel Lezcano {
33b2d3d61aSDaniel Lezcano 	static_branch_disable(&irq_timing_enabled);
34b2d3d61aSDaniel Lezcano }
35e1c92149SDaniel Lezcano 
36bbba0e7cSDaniel Lezcano /*
37bbba0e7cSDaniel Lezcano  * The main goal of this algorithm is to predict the next interrupt
38bbba0e7cSDaniel Lezcano  * occurrence on the current CPU.
39bbba0e7cSDaniel Lezcano  *
40bbba0e7cSDaniel Lezcano  * Currently, the interrupt timings are stored in a circular array
41bbba0e7cSDaniel Lezcano  * buffer every time there is an interrupt, as a tuple: the interrupt
42bbba0e7cSDaniel Lezcano  * number and the associated timestamp when the event occurred <irq,
43bbba0e7cSDaniel Lezcano  * timestamp>.
44bbba0e7cSDaniel Lezcano  *
45bbba0e7cSDaniel Lezcano  * For every interrupt occurring in a short period of time, we can
46bbba0e7cSDaniel Lezcano  * measure the elapsed time between the occurrences for the same
47bbba0e7cSDaniel Lezcano  * interrupt and we end up with a suite of intervals. The experience
48bbba0e7cSDaniel Lezcano  * showed the interrupts are often coming following a periodic
49bbba0e7cSDaniel Lezcano  * pattern.
50bbba0e7cSDaniel Lezcano  *
51bbba0e7cSDaniel Lezcano  * The objective of the algorithm is to find out this periodic pattern
52bbba0e7cSDaniel Lezcano  * in a fastest way and use its period to predict the next irq event.
53bbba0e7cSDaniel Lezcano  *
54bbba0e7cSDaniel Lezcano  * When the next interrupt event is requested, we are in the situation
55bbba0e7cSDaniel Lezcano  * where the interrupts are disabled and the circular buffer
56bbba0e7cSDaniel Lezcano  * containing the timings is filled with the events which happened
57bbba0e7cSDaniel Lezcano  * after the previous next-interrupt-event request.
58bbba0e7cSDaniel Lezcano  *
59bbba0e7cSDaniel Lezcano  * At this point, we read the circular buffer and we fill the irq
60bbba0e7cSDaniel Lezcano  * related statistics structure. After this step, the circular array
61bbba0e7cSDaniel Lezcano  * containing the timings is empty because all the values are
62bbba0e7cSDaniel Lezcano  * dispatched in their corresponding buffers.
63bbba0e7cSDaniel Lezcano  *
64bbba0e7cSDaniel Lezcano  * Now for each interrupt, we can predict the next event by using the
65bbba0e7cSDaniel Lezcano  * suffix array, log interval and exponential moving average
66bbba0e7cSDaniel Lezcano  *
67bbba0e7cSDaniel Lezcano  * 1. Suffix array
68bbba0e7cSDaniel Lezcano  *
69bbba0e7cSDaniel Lezcano  * Suffix array is an array of all the suffixes of a string. It is
70bbba0e7cSDaniel Lezcano  * widely used as a data structure for compression, text search, ...
71bbba0e7cSDaniel Lezcano  * For instance for the word 'banana', the suffixes will be: 'banana'
72bbba0e7cSDaniel Lezcano  * 'anana' 'nana' 'ana' 'na' 'a'
73bbba0e7cSDaniel Lezcano  *
74bbba0e7cSDaniel Lezcano  * Usually, the suffix array is sorted but for our purpose it is
75bbba0e7cSDaniel Lezcano  * not necessary and won't provide any improvement in the context of
76bbba0e7cSDaniel Lezcano  * the solved problem where we clearly define the boundaries of the
77bbba0e7cSDaniel Lezcano  * search by a max period and min period.
78bbba0e7cSDaniel Lezcano  *
79bbba0e7cSDaniel Lezcano  * The suffix array will build a suite of intervals of different
80bbba0e7cSDaniel Lezcano  * length and will look for the repetition of each suite. If the suite
81bbba0e7cSDaniel Lezcano  * is repeating then we have the period because it is the length of
82bbba0e7cSDaniel Lezcano  * the suite whatever its position in the buffer.
83bbba0e7cSDaniel Lezcano  *
84bbba0e7cSDaniel Lezcano  * 2. Log interval
85bbba0e7cSDaniel Lezcano  *
86bbba0e7cSDaniel Lezcano  * We saw the irq timings allow to compute the interval of the
875c982c58SKrzysztof Kozlowski  * occurrences for a specific interrupt. We can reasonably assume the
88bbba0e7cSDaniel Lezcano  * longer is the interval, the higher is the error for the next event
89bbba0e7cSDaniel Lezcano  * and we can consider storing those interval values into an array
90bbba0e7cSDaniel Lezcano  * where each slot in the array correspond to an interval at the power
91bbba0e7cSDaniel Lezcano  * of 2 of the index. For example, index 12 will contain values
92bbba0e7cSDaniel Lezcano  * between 2^11 and 2^12.
93bbba0e7cSDaniel Lezcano  *
94bbba0e7cSDaniel Lezcano  * At the end we have an array of values where at each index defines a
95bbba0e7cSDaniel Lezcano  * [2^index - 1, 2 ^ index] interval values allowing to store a large
96bbba0e7cSDaniel Lezcano  * number of values inside a small array.
97bbba0e7cSDaniel Lezcano  *
98bbba0e7cSDaniel Lezcano  * For example, if we have the value 1123, then we store it at
99bbba0e7cSDaniel Lezcano  * ilog2(1123) = 10 index value.
100bbba0e7cSDaniel Lezcano  *
101bbba0e7cSDaniel Lezcano  * Storing those value at the specific index is done by computing an
102bbba0e7cSDaniel Lezcano  * exponential moving average for this specific slot. For instance,
103bbba0e7cSDaniel Lezcano  * for values 1800, 1123, 1453, ... fall under the same slot (10) and
104bbba0e7cSDaniel Lezcano  * the exponential moving average is computed every time a new value
105bbba0e7cSDaniel Lezcano  * is stored at this slot.
106bbba0e7cSDaniel Lezcano  *
107bbba0e7cSDaniel Lezcano  * 3. Exponential Moving Average
108bbba0e7cSDaniel Lezcano  *
109bbba0e7cSDaniel Lezcano  * The EMA is largely used to track a signal for stocks or as a low
110bbba0e7cSDaniel Lezcano  * pass filter. The magic of the formula, is it is very simple and the
111bbba0e7cSDaniel Lezcano  * reactivity of the average can be tuned with the factors called
112bbba0e7cSDaniel Lezcano  * alpha.
113bbba0e7cSDaniel Lezcano  *
114bbba0e7cSDaniel Lezcano  * The higher the alphas are, the faster the average respond to the
115bbba0e7cSDaniel Lezcano  * signal change. In our case, if a slot in the array is a big
116bbba0e7cSDaniel Lezcano  * interval, we can have numbers with a big difference between
117bbba0e7cSDaniel Lezcano  * them. The impact of those differences in the average computation
118bbba0e7cSDaniel Lezcano  * can be tuned by changing the alpha value.
119bbba0e7cSDaniel Lezcano  *
120bbba0e7cSDaniel Lezcano  *
121bbba0e7cSDaniel Lezcano  *  -- The algorithm --
122bbba0e7cSDaniel Lezcano  *
123bbba0e7cSDaniel Lezcano  * We saw the different processing above, now let's see how they are
124bbba0e7cSDaniel Lezcano  * used together.
125bbba0e7cSDaniel Lezcano  *
126bbba0e7cSDaniel Lezcano  * For each interrupt:
127bbba0e7cSDaniel Lezcano  *	For each interval:
128bbba0e7cSDaniel Lezcano  *		Compute the index = ilog2(interval)
129bbba0e7cSDaniel Lezcano  *		Compute a new_ema(buffer[index], interval)
130bbba0e7cSDaniel Lezcano  *		Store the index in a circular buffer
131bbba0e7cSDaniel Lezcano  *
132bbba0e7cSDaniel Lezcano  *	Compute the suffix array of the indexes
133bbba0e7cSDaniel Lezcano  *
134bbba0e7cSDaniel Lezcano  *	For each suffix:
135bbba0e7cSDaniel Lezcano  *		If the suffix is reverse-found 3 times
136bbba0e7cSDaniel Lezcano  *			Return suffix
137bbba0e7cSDaniel Lezcano  *
138bbba0e7cSDaniel Lezcano  *	Return Not found
139bbba0e7cSDaniel Lezcano  *
140bbba0e7cSDaniel Lezcano  * However we can not have endless suffix array to be build, it won't
141bbba0e7cSDaniel Lezcano  * make sense and it will add an extra overhead, so we can restrict
142bbba0e7cSDaniel Lezcano  * this to a maximum suffix length of 5 and a minimum suffix length of
143bbba0e7cSDaniel Lezcano  * 2. The experience showed 5 is the majority of the maximum pattern
144bbba0e7cSDaniel Lezcano  * period found for different devices.
145bbba0e7cSDaniel Lezcano  *
146bbba0e7cSDaniel Lezcano  * The result is a pattern finding less than 1us for an interrupt.
147bbba0e7cSDaniel Lezcano  *
148bbba0e7cSDaniel Lezcano  * Example based on real values:
149bbba0e7cSDaniel Lezcano  *
150bbba0e7cSDaniel Lezcano  * Example 1 : MMC write/read interrupt interval:
151bbba0e7cSDaniel Lezcano  *
152bbba0e7cSDaniel Lezcano  *	223947, 1240, 1384, 1386, 1386,
153bbba0e7cSDaniel Lezcano  *	217416, 1236, 1384, 1386, 1387,
154bbba0e7cSDaniel Lezcano  *	214719, 1241, 1386, 1387, 1384,
155bbba0e7cSDaniel Lezcano  *	213696, 1234, 1384, 1386, 1388,
156bbba0e7cSDaniel Lezcano  *	219904, 1240, 1385, 1389, 1385,
157bbba0e7cSDaniel Lezcano  *	212240, 1240, 1386, 1386, 1386,
158bbba0e7cSDaniel Lezcano  *	214415, 1236, 1384, 1386, 1387,
159bbba0e7cSDaniel Lezcano  *	214276, 1234, 1384, 1388, ?
160bbba0e7cSDaniel Lezcano  *
161bbba0e7cSDaniel Lezcano  * For each element, apply ilog2(value)
162bbba0e7cSDaniel Lezcano  *
163bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
164bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
165bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
166bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
167bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
168bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
169bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
170bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, ?
171bbba0e7cSDaniel Lezcano  *
172bbba0e7cSDaniel Lezcano  * Max period of 5, we take the last (max_period * 3) 15 elements as
173bbba0e7cSDaniel Lezcano  * we can be confident if the pattern repeats itself three times it is
174bbba0e7cSDaniel Lezcano  * a repeating pattern.
175bbba0e7cSDaniel Lezcano  *
176bbba0e7cSDaniel Lezcano  *	             8,
177bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
178bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, 8,
179bbba0e7cSDaniel Lezcano  *	15, 8, 8, 8, ?
180bbba0e7cSDaniel Lezcano  *
181bbba0e7cSDaniel Lezcano  * Suffixes are:
182bbba0e7cSDaniel Lezcano  *
183bbba0e7cSDaniel Lezcano  *  1) 8, 15, 8, 8, 8  <- max period
184bbba0e7cSDaniel Lezcano  *  2) 8, 15, 8, 8
185bbba0e7cSDaniel Lezcano  *  3) 8, 15, 8
186bbba0e7cSDaniel Lezcano  *  4) 8, 15           <- min period
187bbba0e7cSDaniel Lezcano  *
188bbba0e7cSDaniel Lezcano  * From there we search the repeating pattern for each suffix.
189bbba0e7cSDaniel Lezcano  *
190bbba0e7cSDaniel Lezcano  * buffer: 8, 15, 8, 8, 8, 8, 15, 8, 8, 8, 8, 15, 8, 8, 8
191bbba0e7cSDaniel Lezcano  *         |   |  |  |  |  |   |  |  |  |  |   |  |  |  |
192bbba0e7cSDaniel Lezcano  *         8, 15, 8, 8, 8  |   |  |  |  |  |   |  |  |  |
193bbba0e7cSDaniel Lezcano  *                         8, 15, 8, 8, 8  |   |  |  |  |
194bbba0e7cSDaniel Lezcano  *                                         8, 15, 8, 8, 8
195bbba0e7cSDaniel Lezcano  *
196bbba0e7cSDaniel Lezcano  * When moving the suffix, we found exactly 3 matches.
197bbba0e7cSDaniel Lezcano  *
198bbba0e7cSDaniel Lezcano  * The first suffix with period 5 is repeating.
199bbba0e7cSDaniel Lezcano  *
200bbba0e7cSDaniel Lezcano  * The next event is (3 * max_period) % suffix_period
201bbba0e7cSDaniel Lezcano  *
202bbba0e7cSDaniel Lezcano  * In this example, the result 0, so the next event is suffix[0] => 8
203bbba0e7cSDaniel Lezcano  *
204bbba0e7cSDaniel Lezcano  * However, 8 is the index in the array of exponential moving average
205bbba0e7cSDaniel Lezcano  * which was calculated on the fly when storing the values, so the
206bbba0e7cSDaniel Lezcano  * interval is ema[8] = 1366
207bbba0e7cSDaniel Lezcano  *
208bbba0e7cSDaniel Lezcano  *
209bbba0e7cSDaniel Lezcano  * Example 2:
210bbba0e7cSDaniel Lezcano  *
211bbba0e7cSDaniel Lezcano  *	4, 3, 5, 100,
212bbba0e7cSDaniel Lezcano  *	3, 3, 5, 117,
213bbba0e7cSDaniel Lezcano  *	4, 4, 5, 112,
214bbba0e7cSDaniel Lezcano  *	4, 3, 4, 110,
215bbba0e7cSDaniel Lezcano  *	3, 5, 3, 117,
216bbba0e7cSDaniel Lezcano  *	4, 4, 5, 112,
217bbba0e7cSDaniel Lezcano  *	4, 3, 4, 110,
218bbba0e7cSDaniel Lezcano  *	3, 4, 5, 112,
219bbba0e7cSDaniel Lezcano  *	4, 3, 4, 110
220bbba0e7cSDaniel Lezcano  *
221bbba0e7cSDaniel Lezcano  * ilog2
222bbba0e7cSDaniel Lezcano  *
223bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
224bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
225bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
226bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
227bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
228bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
229bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
230bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
231bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4
232bbba0e7cSDaniel Lezcano  *
233bbba0e7cSDaniel Lezcano  * Max period 5:
234bbba0e7cSDaniel Lezcano  *	   0, 0, 4,
235bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
236bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4,
237bbba0e7cSDaniel Lezcano  *	0, 0, 0, 4
238bbba0e7cSDaniel Lezcano  *
239bbba0e7cSDaniel Lezcano  * Suffixes:
240bbba0e7cSDaniel Lezcano  *
241bbba0e7cSDaniel Lezcano  *  1) 0, 0, 4, 0, 0
242bbba0e7cSDaniel Lezcano  *  2) 0, 0, 4, 0
243bbba0e7cSDaniel Lezcano  *  3) 0, 0, 4
244bbba0e7cSDaniel Lezcano  *  4) 0, 0
245bbba0e7cSDaniel Lezcano  *
246bbba0e7cSDaniel Lezcano  * buffer: 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4
247bbba0e7cSDaniel Lezcano  *         |  |  |  |  |  |  X
248bbba0e7cSDaniel Lezcano  *         0, 0, 4, 0, 0, |  X
249bbba0e7cSDaniel Lezcano  *                        0, 0
250bbba0e7cSDaniel Lezcano  *
251bbba0e7cSDaniel Lezcano  * buffer: 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4
252bbba0e7cSDaniel Lezcano  *         |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
253bbba0e7cSDaniel Lezcano  *         0, 0, 4, 0, |  |  |  |  |  |  |  |  |  |  |
254bbba0e7cSDaniel Lezcano  *                     0, 0, 4, 0, |  |  |  |  |  |  |
255bbba0e7cSDaniel Lezcano  *                                 0, 0, 4, 0, |  |  |
256bbba0e7cSDaniel Lezcano  *                                             0  0  4
257bbba0e7cSDaniel Lezcano  *
258bbba0e7cSDaniel Lezcano  * Pattern is found 3 times, the remaining is 1 which results from
259bbba0e7cSDaniel Lezcano  * (max_period * 3) % suffix_period. This value is the index in the
260bbba0e7cSDaniel Lezcano  * suffix arrays. The suffix array for a period 4 has the value 4
261bbba0e7cSDaniel Lezcano  * at index 1.
262bbba0e7cSDaniel Lezcano  */
263bbba0e7cSDaniel Lezcano #define EMA_ALPHA_VAL		64
264bbba0e7cSDaniel Lezcano #define EMA_ALPHA_SHIFT		7
265bbba0e7cSDaniel Lezcano 
2663c2e79f4SDaniel Lezcano #define PREDICTION_PERIOD_MIN	3
267bbba0e7cSDaniel Lezcano #define PREDICTION_PERIOD_MAX	5
268bbba0e7cSDaniel Lezcano #define PREDICTION_FACTOR	4
269bbba0e7cSDaniel Lezcano #define PREDICTION_MAX		10 /* 2 ^ PREDICTION_MAX useconds */
270bbba0e7cSDaniel Lezcano #define PREDICTION_BUFFER_SIZE	16 /* slots for EMAs, hardly more than 16 */
271bbba0e7cSDaniel Lezcano 
2722840eef0SDaniel Lezcano /*
2732840eef0SDaniel Lezcano  * Number of elements in the circular buffer: If it happens it was
2742840eef0SDaniel Lezcano  * flushed before, then the number of elements could be smaller than
2752840eef0SDaniel Lezcano  * IRQ_TIMINGS_SIZE, so the count is used, otherwise the array size is
2762840eef0SDaniel Lezcano  * used as we wrapped. The index begins from zero when we did not
2772840eef0SDaniel Lezcano  * wrap. That could be done in a nicer way with the proper circular
2782840eef0SDaniel Lezcano  * array structure type but with the cost of extra computation in the
2792840eef0SDaniel Lezcano  * interrupt handler hot path. We choose efficiency.
2802840eef0SDaniel Lezcano  */
2812840eef0SDaniel Lezcano #define for_each_irqts(i, irqts)					\
2822840eef0SDaniel Lezcano 	for (i = irqts->count < IRQ_TIMINGS_SIZE ?			\
2832840eef0SDaniel Lezcano 		     0 : irqts->count & IRQ_TIMINGS_MASK,		\
2842840eef0SDaniel Lezcano 		     irqts->count = min(IRQ_TIMINGS_SIZE,		\
2852840eef0SDaniel Lezcano 					irqts->count);			\
2862840eef0SDaniel Lezcano 	     irqts->count > 0; irqts->count--,				\
2872840eef0SDaniel Lezcano 		     i = (i + 1) & IRQ_TIMINGS_MASK)
2882840eef0SDaniel Lezcano 
289bbba0e7cSDaniel Lezcano struct irqt_stat {
290bbba0e7cSDaniel Lezcano 	u64	last_ts;
291bbba0e7cSDaniel Lezcano 	u64	ema_time[PREDICTION_BUFFER_SIZE];
292bbba0e7cSDaniel Lezcano 	int	timings[IRQ_TIMINGS_SIZE];
293bbba0e7cSDaniel Lezcano 	int	circ_timings[IRQ_TIMINGS_SIZE];
294bbba0e7cSDaniel Lezcano 	int	count;
295bbba0e7cSDaniel Lezcano };
296bbba0e7cSDaniel Lezcano 
297bbba0e7cSDaniel Lezcano /*
298bbba0e7cSDaniel Lezcano  * Exponential moving average computation
299bbba0e7cSDaniel Lezcano  */
irq_timings_ema_new(u64 value,u64 ema_old)300bbba0e7cSDaniel Lezcano static u64 irq_timings_ema_new(u64 value, u64 ema_old)
301bbba0e7cSDaniel Lezcano {
302bbba0e7cSDaniel Lezcano 	s64 diff;
303bbba0e7cSDaniel Lezcano 
304bbba0e7cSDaniel Lezcano 	if (unlikely(!ema_old))
305bbba0e7cSDaniel Lezcano 		return value;
306bbba0e7cSDaniel Lezcano 
307bbba0e7cSDaniel Lezcano 	diff = (value - ema_old) * EMA_ALPHA_VAL;
308bbba0e7cSDaniel Lezcano 	/*
309bbba0e7cSDaniel Lezcano 	 * We can use a s64 type variable to be added with the u64
310bbba0e7cSDaniel Lezcano 	 * ema_old variable as this one will never have its topmost
311bbba0e7cSDaniel Lezcano 	 * bit set, it will be always smaller than 2^63 nanosec
312bbba0e7cSDaniel Lezcano 	 * interrupt interval (292 years).
313bbba0e7cSDaniel Lezcano 	 */
314bbba0e7cSDaniel Lezcano 	return ema_old + (diff >> EMA_ALPHA_SHIFT);
315bbba0e7cSDaniel Lezcano }
316bbba0e7cSDaniel Lezcano 
irq_timings_next_event_index(int * buffer,size_t len,int period_max)317bbba0e7cSDaniel Lezcano static int irq_timings_next_event_index(int *buffer, size_t len, int period_max)
318bbba0e7cSDaniel Lezcano {
319619c1baaSDaniel Lezcano 	int period;
320619c1baaSDaniel Lezcano 
321619c1baaSDaniel Lezcano 	/*
322619c1baaSDaniel Lezcano 	 * Move the beginning pointer to the end minus the max period x 3.
323619c1baaSDaniel Lezcano 	 * We are at the point we can begin searching the pattern
324619c1baaSDaniel Lezcano 	 */
325619c1baaSDaniel Lezcano 	buffer = &buffer[len - (period_max * 3)];
326619c1baaSDaniel Lezcano 
327619c1baaSDaniel Lezcano 	/* Adjust the length to the maximum allowed period x 3 */
328619c1baaSDaniel Lezcano 	len = period_max * 3;
329bbba0e7cSDaniel Lezcano 
330bbba0e7cSDaniel Lezcano 	/*
331bbba0e7cSDaniel Lezcano 	 * The buffer contains the suite of intervals, in a ilog2
332bbba0e7cSDaniel Lezcano 	 * basis, we are looking for a repetition. We point the
333bbba0e7cSDaniel Lezcano 	 * beginning of the search three times the length of the
334bbba0e7cSDaniel Lezcano 	 * period beginning at the end of the buffer. We do that for
335bbba0e7cSDaniel Lezcano 	 * each suffix.
336bbba0e7cSDaniel Lezcano 	 */
337619c1baaSDaniel Lezcano 	for (period = period_max; period >= PREDICTION_PERIOD_MIN; period--) {
338bbba0e7cSDaniel Lezcano 
339619c1baaSDaniel Lezcano 		/*
340619c1baaSDaniel Lezcano 		 * The first comparison always succeed because the
341619c1baaSDaniel Lezcano 		 * suffix is deduced from the first n-period bytes of
342619c1baaSDaniel Lezcano 		 * the buffer and we compare the initial suffix with
343619c1baaSDaniel Lezcano 		 * itself, so we can skip the first iteration.
344619c1baaSDaniel Lezcano 		 */
345619c1baaSDaniel Lezcano 		int idx = period;
346619c1baaSDaniel Lezcano 		size_t size = period;
347bbba0e7cSDaniel Lezcano 
348bbba0e7cSDaniel Lezcano 		/*
349bbba0e7cSDaniel Lezcano 		 * We look if the suite with period 'i' repeat
350bbba0e7cSDaniel Lezcano 		 * itself. If it is truncated at the end, as it
351bbba0e7cSDaniel Lezcano 		 * repeats we can use the period to find out the next
352619c1baaSDaniel Lezcano 		 * element with the modulo.
353bbba0e7cSDaniel Lezcano 		 */
354619c1baaSDaniel Lezcano 		while (!memcmp(buffer, &buffer[idx], size * sizeof(int))) {
355619c1baaSDaniel Lezcano 
356619c1baaSDaniel Lezcano 			/*
357619c1baaSDaniel Lezcano 			 * Move the index in a period basis
358619c1baaSDaniel Lezcano 			 */
359619c1baaSDaniel Lezcano 			idx += size;
360619c1baaSDaniel Lezcano 
361619c1baaSDaniel Lezcano 			/*
362619c1baaSDaniel Lezcano 			 * If this condition is reached, all previous
363619c1baaSDaniel Lezcano 			 * memcmp were successful, so the period is
364619c1baaSDaniel Lezcano 			 * found.
365619c1baaSDaniel Lezcano 			 */
366619c1baaSDaniel Lezcano 			if (idx == len)
367619c1baaSDaniel Lezcano 				return buffer[len % period];
368619c1baaSDaniel Lezcano 
369619c1baaSDaniel Lezcano 			/*
370619c1baaSDaniel Lezcano 			 * If the remaining elements to compare are
371619c1baaSDaniel Lezcano 			 * smaller than the period, readjust the size
372619c1baaSDaniel Lezcano 			 * of the comparison for the last iteration.
373619c1baaSDaniel Lezcano 			 */
374619c1baaSDaniel Lezcano 			if (len - idx < period)
375619c1baaSDaniel Lezcano 				size = len - idx;
376bbba0e7cSDaniel Lezcano 		}
377bbba0e7cSDaniel Lezcano 	}
378bbba0e7cSDaniel Lezcano 
379bbba0e7cSDaniel Lezcano 	return -1;
380bbba0e7cSDaniel Lezcano }
381bbba0e7cSDaniel Lezcano 
__irq_timings_next_event(struct irqt_stat * irqs,int irq,u64 now)382bbba0e7cSDaniel Lezcano static u64 __irq_timings_next_event(struct irqt_stat *irqs, int irq, u64 now)
383bbba0e7cSDaniel Lezcano {
384bbba0e7cSDaniel Lezcano 	int index, i, period_max, count, start, min = INT_MAX;
385bbba0e7cSDaniel Lezcano 
386bbba0e7cSDaniel Lezcano 	if ((now - irqs->last_ts) >= NSEC_PER_SEC) {
387bbba0e7cSDaniel Lezcano 		irqs->count = irqs->last_ts = 0;
388bbba0e7cSDaniel Lezcano 		return U64_MAX;
389bbba0e7cSDaniel Lezcano 	}
390bbba0e7cSDaniel Lezcano 
391bbba0e7cSDaniel Lezcano 	/*
392bbba0e7cSDaniel Lezcano 	 * As we want to find three times the repetition, we need a
393bbba0e7cSDaniel Lezcano 	 * number of intervals greater or equal to three times the
394bbba0e7cSDaniel Lezcano 	 * maximum period, otherwise we truncate the max period.
395bbba0e7cSDaniel Lezcano 	 */
396bbba0e7cSDaniel Lezcano 	period_max = irqs->count > (3 * PREDICTION_PERIOD_MAX) ?
397bbba0e7cSDaniel Lezcano 		PREDICTION_PERIOD_MAX : irqs->count / 3;
398bbba0e7cSDaniel Lezcano 
399bbba0e7cSDaniel Lezcano 	/*
400bbba0e7cSDaniel Lezcano 	 * If we don't have enough irq timings for this prediction,
401bbba0e7cSDaniel Lezcano 	 * just bail out.
402bbba0e7cSDaniel Lezcano 	 */
403bbba0e7cSDaniel Lezcano 	if (period_max <= PREDICTION_PERIOD_MIN)
404bbba0e7cSDaniel Lezcano 		return U64_MAX;
405bbba0e7cSDaniel Lezcano 
406bbba0e7cSDaniel Lezcano 	/*
407bbba0e7cSDaniel Lezcano 	 * 'count' will depends if the circular buffer wrapped or not
408bbba0e7cSDaniel Lezcano 	 */
409bbba0e7cSDaniel Lezcano 	count = irqs->count < IRQ_TIMINGS_SIZE ?
410bbba0e7cSDaniel Lezcano 		irqs->count : IRQ_TIMINGS_SIZE;
411bbba0e7cSDaniel Lezcano 
412bbba0e7cSDaniel Lezcano 	start = irqs->count < IRQ_TIMINGS_SIZE ?
413bbba0e7cSDaniel Lezcano 		0 : (irqs->count & IRQ_TIMINGS_MASK);
414bbba0e7cSDaniel Lezcano 
415bbba0e7cSDaniel Lezcano 	/*
416bbba0e7cSDaniel Lezcano 	 * Copy the content of the circular buffer into another buffer
417bbba0e7cSDaniel Lezcano 	 * in order to linearize the buffer instead of dealing with
418bbba0e7cSDaniel Lezcano 	 * wrapping indexes and shifted array which will be prone to
4195c982c58SKrzysztof Kozlowski 	 * error and extremely difficult to debug.
420bbba0e7cSDaniel Lezcano 	 */
421bbba0e7cSDaniel Lezcano 	for (i = 0; i < count; i++) {
422bbba0e7cSDaniel Lezcano 		int index = (start + i) & IRQ_TIMINGS_MASK;
423bbba0e7cSDaniel Lezcano 
424bbba0e7cSDaniel Lezcano 		irqs->timings[i] = irqs->circ_timings[index];
425bbba0e7cSDaniel Lezcano 		min = min_t(int, irqs->timings[i], min);
426bbba0e7cSDaniel Lezcano 	}
427bbba0e7cSDaniel Lezcano 
428bbba0e7cSDaniel Lezcano 	index = irq_timings_next_event_index(irqs->timings, count, period_max);
429bbba0e7cSDaniel Lezcano 	if (index < 0)
430bbba0e7cSDaniel Lezcano 		return irqs->last_ts + irqs->ema_time[min];
431bbba0e7cSDaniel Lezcano 
432bbba0e7cSDaniel Lezcano 	return irqs->last_ts + irqs->ema_time[index];
433bbba0e7cSDaniel Lezcano }
434bbba0e7cSDaniel Lezcano 
irq_timings_interval_index(u64 interval)43523aa3b9aSDaniel Lezcano static __always_inline int irq_timings_interval_index(u64 interval)
43623aa3b9aSDaniel Lezcano {
43723aa3b9aSDaniel Lezcano 	/*
43823aa3b9aSDaniel Lezcano 	 * The PREDICTION_FACTOR increase the interval size for the
43923aa3b9aSDaniel Lezcano 	 * array of exponential average.
44023aa3b9aSDaniel Lezcano 	 */
44123aa3b9aSDaniel Lezcano 	u64 interval_us = (interval >> 10) / PREDICTION_FACTOR;
44223aa3b9aSDaniel Lezcano 
44323aa3b9aSDaniel Lezcano 	return likely(interval_us) ? ilog2(interval_us) : 0;
44423aa3b9aSDaniel Lezcano }
44523aa3b9aSDaniel Lezcano 
__irq_timings_store(int irq,struct irqt_stat * irqs,u64 interval)44623aa3b9aSDaniel Lezcano static __always_inline void __irq_timings_store(int irq, struct irqt_stat *irqs,
44723aa3b9aSDaniel Lezcano 						u64 interval)
44823aa3b9aSDaniel Lezcano {
44923aa3b9aSDaniel Lezcano 	int index;
45023aa3b9aSDaniel Lezcano 
45123aa3b9aSDaniel Lezcano 	/*
45223aa3b9aSDaniel Lezcano 	 * Get the index in the ema table for this interrupt.
45323aa3b9aSDaniel Lezcano 	 */
45423aa3b9aSDaniel Lezcano 	index = irq_timings_interval_index(interval);
45523aa3b9aSDaniel Lezcano 
45623aa3b9aSDaniel Lezcano 	if (index > PREDICTION_BUFFER_SIZE - 1) {
45723aa3b9aSDaniel Lezcano 		irqs->count = 0;
45823aa3b9aSDaniel Lezcano 		return;
45923aa3b9aSDaniel Lezcano 	}
46023aa3b9aSDaniel Lezcano 
46123aa3b9aSDaniel Lezcano 	/*
46223aa3b9aSDaniel Lezcano 	 * Store the index as an element of the pattern in another
46323aa3b9aSDaniel Lezcano 	 * circular array.
46423aa3b9aSDaniel Lezcano 	 */
46523aa3b9aSDaniel Lezcano 	irqs->circ_timings[irqs->count & IRQ_TIMINGS_MASK] = index;
46623aa3b9aSDaniel Lezcano 
46723aa3b9aSDaniel Lezcano 	irqs->ema_time[index] = irq_timings_ema_new(interval,
468bbba0e7cSDaniel Lezcano 						    irqs->ema_time[index]);
469bbba0e7cSDaniel Lezcano 
470bbba0e7cSDaniel Lezcano 	irqs->count++;
471bbba0e7cSDaniel Lezcano }
472bbba0e7cSDaniel Lezcano 
irq_timings_store(int irq,struct irqt_stat * irqs,u64 ts)473bbba0e7cSDaniel Lezcano static inline void irq_timings_store(int irq, struct irqt_stat *irqs, u64 ts)
474bbba0e7cSDaniel Lezcano {
475bbba0e7cSDaniel Lezcano 	u64 old_ts = irqs->last_ts;
476bbba0e7cSDaniel Lezcano 	u64 interval;
477bbba0e7cSDaniel Lezcano 
478bbba0e7cSDaniel Lezcano 	/*
479bbba0e7cSDaniel Lezcano 	 * The timestamps are absolute time values, we need to compute
480bbba0e7cSDaniel Lezcano 	 * the timing interval between two interrupts.
481bbba0e7cSDaniel Lezcano 	 */
482bbba0e7cSDaniel Lezcano 	irqs->last_ts = ts;
483bbba0e7cSDaniel Lezcano 
484bbba0e7cSDaniel Lezcano 	/*
485bbba0e7cSDaniel Lezcano 	 * The interval type is u64 in order to deal with the same
486bbba0e7cSDaniel Lezcano 	 * type in our computation, that prevent mindfuck issues with
487bbba0e7cSDaniel Lezcano 	 * overflow, sign and division.
488a359f757SIngo Molnar 	 */
489bbba0e7cSDaniel Lezcano 	interval = ts - old_ts;
490bbba0e7cSDaniel Lezcano 
491bbba0e7cSDaniel Lezcano 	/*
492bbba0e7cSDaniel Lezcano 	 * The interrupt triggered more than one second apart, that
493bbba0e7cSDaniel Lezcano 	 * ends the sequence as predictable for our purpose. In this
494bbba0e7cSDaniel Lezcano 	 * case, assume we have the beginning of a sequence and the
495bbba0e7cSDaniel Lezcano 	 * timestamp is the first value. As it is impossible to
496bbba0e7cSDaniel Lezcano 	 * predict anything at this point, return.
497bbba0e7cSDaniel Lezcano 	 *
498bbba0e7cSDaniel Lezcano 	 * Note the first timestamp of the sequence will always fall
499bbba0e7cSDaniel Lezcano 	 * in this test because the old_ts is zero. That is what we
500bbba0e7cSDaniel Lezcano 	 * want as we need another timestamp to compute an interval.
501bbba0e7cSDaniel Lezcano 	 */
50223aa3b9aSDaniel Lezcano 	if (interval >= NSEC_PER_SEC) {
503bbba0e7cSDaniel Lezcano 		irqs->count = 0;
504bbba0e7cSDaniel Lezcano 		return;
505e1c92149SDaniel Lezcano 	}
506e1c92149SDaniel Lezcano 
507e1c92149SDaniel Lezcano 	__irq_timings_store(irq, irqs, interval);
508e1c92149SDaniel Lezcano }
509e1c92149SDaniel Lezcano 
510e1c92149SDaniel Lezcano /**
511e1c92149SDaniel Lezcano  * irq_timings_next_event - Return when the next event is supposed to arrive
512e1c92149SDaniel Lezcano  *
513e1c92149SDaniel Lezcano  * During the last busy cycle, the number of interrupts is incremented
514e1c92149SDaniel Lezcano  * and stored in the irq_timings structure. This information is
515e1c92149SDaniel Lezcano  * necessary to:
516e1c92149SDaniel Lezcano  *
5175c982c58SKrzysztof Kozlowski  * - know if the index in the table wrapped up:
518e1c92149SDaniel Lezcano  *
519e1c92149SDaniel Lezcano  *      If more than the array size interrupts happened during the
520e1c92149SDaniel Lezcano  *      last busy/idle cycle, the index wrapped up and we have to
521e1c92149SDaniel Lezcano  *      begin with the next element in the array which is the last one
522e1c92149SDaniel Lezcano  *      in the sequence, otherwise it is at the index 0.
523e1c92149SDaniel Lezcano  *
524e1c92149SDaniel Lezcano  * - have an indication of the interrupts activity on this CPU
525e1c92149SDaniel Lezcano  *   (eg. irq/sec)
526e1c92149SDaniel Lezcano  *
527e1c92149SDaniel Lezcano  * The values are 'consumed' after inserting in the statistical model,
528e1c92149SDaniel Lezcano  * thus the count is reinitialized.
529e1c92149SDaniel Lezcano  *
530e1c92149SDaniel Lezcano  * The array of values **must** be browsed in the time direction, the
531e1c92149SDaniel Lezcano  * timestamp must increase between an element and the next one.
532e1c92149SDaniel Lezcano  *
533bbba0e7cSDaniel Lezcano  * Returns a nanosec time based estimation of the earliest interrupt,
534bbba0e7cSDaniel Lezcano  * U64_MAX otherwise.
535bbba0e7cSDaniel Lezcano  */
irq_timings_next_event(u64 now)536bbba0e7cSDaniel Lezcano u64 irq_timings_next_event(u64 now)
537bbba0e7cSDaniel Lezcano {
538bbba0e7cSDaniel Lezcano 	struct irq_timings *irqts = this_cpu_ptr(&irq_timings);
539e1c92149SDaniel Lezcano 	struct irqt_stat *irqs;
540e1c92149SDaniel Lezcano 	struct irqt_stat __percpu *s;
541e1c92149SDaniel Lezcano 	u64 ts, next_evt = U64_MAX;
542e1c92149SDaniel Lezcano 	int i, irq = 0;
543e1c92149SDaniel Lezcano 
544a934d4d1SFrederic Weisbecker 	/*
545e1c92149SDaniel Lezcano 	 * This function must be called with the local irq disabled in
546bbba0e7cSDaniel Lezcano 	 * order to prevent the timings circular buffer to be updated
547bbba0e7cSDaniel Lezcano 	 * while we are reading it.
548bbba0e7cSDaniel Lezcano 	 */
549bbba0e7cSDaniel Lezcano 	lockdep_assert_irqs_disabled();
550bbba0e7cSDaniel Lezcano 
551bbba0e7cSDaniel Lezcano 	if (!irqts->count)
552bbba0e7cSDaniel Lezcano 		return next_evt;
553bbba0e7cSDaniel Lezcano 
554bbba0e7cSDaniel Lezcano 	/*
555bbba0e7cSDaniel Lezcano 	 * Number of elements in the circular buffer: If it happens it
556bbba0e7cSDaniel Lezcano 	 * was flushed before, then the number of elements could be
557bbba0e7cSDaniel Lezcano 	 * smaller than IRQ_TIMINGS_SIZE, so the count is used,
558bbba0e7cSDaniel Lezcano 	 * otherwise the array size is used as we wrapped. The index
559bbba0e7cSDaniel Lezcano 	 * begins from zero when we did not wrap. That could be done
560bbba0e7cSDaniel Lezcano 	 * in a nicer way with the proper circular array structure
561bbba0e7cSDaniel Lezcano 	 * type but with the cost of extra computation in the
562bbba0e7cSDaniel Lezcano 	 * interrupt handler hot path. We choose efficiency.
5632840eef0SDaniel Lezcano 	 *
564bbba0e7cSDaniel Lezcano 	 * Inject measured irq/timestamp to the pattern prediction
565bbba0e7cSDaniel Lezcano 	 * model while decrementing the counter because we consume the
566bbba0e7cSDaniel Lezcano 	 * data from our circular buffer.
567bbba0e7cSDaniel Lezcano 	 */
568bbba0e7cSDaniel Lezcano 	for_each_irqts(i, irqts) {
569bbba0e7cSDaniel Lezcano 		irq = irq_timing_decode(irqts->values[i], &ts);
570bbba0e7cSDaniel Lezcano 		s = idr_find(&irqt_stats, irq);
571bbba0e7cSDaniel Lezcano 		if (s)
572bbba0e7cSDaniel Lezcano 			irq_timings_store(irq, this_cpu_ptr(s), ts);
573bbba0e7cSDaniel Lezcano 	}
574bbba0e7cSDaniel Lezcano 
575bbba0e7cSDaniel Lezcano 	/*
576bbba0e7cSDaniel Lezcano 	 * Look in the list of interrupts' statistics, the earliest
577bbba0e7cSDaniel Lezcano 	 * next event.
578bbba0e7cSDaniel Lezcano 	 */
579bbba0e7cSDaniel Lezcano 	idr_for_each_entry(&irqt_stats, s, i) {
580bbba0e7cSDaniel Lezcano 
581bbba0e7cSDaniel Lezcano 		irqs = this_cpu_ptr(s);
582bbba0e7cSDaniel Lezcano 
583bbba0e7cSDaniel Lezcano 		ts = __irq_timings_next_event(irqs, i, now);
584bbba0e7cSDaniel Lezcano 		if (ts <= now)
585bbba0e7cSDaniel Lezcano 			return now;
586bbba0e7cSDaniel Lezcano 
587e1c92149SDaniel Lezcano 		if (ts < next_evt)
588e1c92149SDaniel Lezcano 			next_evt = ts;
589e1c92149SDaniel Lezcano 	}
590e1c92149SDaniel Lezcano 
591e1c92149SDaniel Lezcano 	return next_evt;
592e1c92149SDaniel Lezcano }
593e1c92149SDaniel Lezcano 
irq_timings_free(int irq)594e1c92149SDaniel Lezcano void irq_timings_free(int irq)
595e1c92149SDaniel Lezcano {
596e1c92149SDaniel Lezcano 	struct irqt_stat __percpu *s;
597e1c92149SDaniel Lezcano 
598e1c92149SDaniel Lezcano 	s = idr_find(&irqt_stats, irq);
599e1c92149SDaniel Lezcano 	if (s) {
600e1c92149SDaniel Lezcano 		free_percpu(s);
601e1c92149SDaniel Lezcano 		idr_remove(&irqt_stats, irq);
602e1c92149SDaniel Lezcano 	}
603e1c92149SDaniel Lezcano }
604e1c92149SDaniel Lezcano 
irq_timings_alloc(int irq)605e1c92149SDaniel Lezcano int irq_timings_alloc(int irq)
606e1c92149SDaniel Lezcano {
6077b7b8a2cSRandy Dunlap 	struct irqt_stat __percpu *s;
608e1c92149SDaniel Lezcano 	int id;
609e1c92149SDaniel Lezcano 
610e1c92149SDaniel Lezcano 	/*
611e1c92149SDaniel Lezcano 	 * Some platforms can have the same private interrupt per cpu,
612e1c92149SDaniel Lezcano 	 * so this function may be called several times with the
613e1c92149SDaniel Lezcano 	 * same interrupt number. Just bail out in case the per cpu
614e1c92149SDaniel Lezcano 	 * stat structure is already allocated.
615e1c92149SDaniel Lezcano 	 */
616e1c92149SDaniel Lezcano 	s = idr_find(&irqt_stats, irq);
617e1c92149SDaniel Lezcano 	if (s)
618e1c92149SDaniel Lezcano 		return 0;
619e1c92149SDaniel Lezcano 
620e1c92149SDaniel Lezcano 	s = alloc_percpu(*s);
621e1c92149SDaniel Lezcano 	if (!s)
622e1c92149SDaniel Lezcano 		return -ENOMEM;
623e1c92149SDaniel Lezcano 
624e1c92149SDaniel Lezcano 	idr_preload(GFP_KERNEL);
625e1c92149SDaniel Lezcano 	id = idr_alloc(&irqt_stats, s, irq, irq + 1, GFP_NOWAIT);
626e1c92149SDaniel Lezcano 	idr_preload_end();
627e1c92149SDaniel Lezcano 
628e1c92149SDaniel Lezcano 	if (id < 0) {
629e1c92149SDaniel Lezcano 		free_percpu(s);
6306aed82deSDaniel Lezcano 		return id;
6316aed82deSDaniel Lezcano 	}
632f52da98dSDaniel Lezcano 
633f52da98dSDaniel Lezcano 	return 0;
634f52da98dSDaniel Lezcano }
635f52da98dSDaniel Lezcano 
636f52da98dSDaniel Lezcano #ifdef CONFIG_TEST_IRQ_TIMINGS
637f52da98dSDaniel Lezcano struct timings_intervals {
638f52da98dSDaniel Lezcano 	u64 *intervals;
639f52da98dSDaniel Lezcano 	size_t count;
640f52da98dSDaniel Lezcano };
641f52da98dSDaniel Lezcano 
642f52da98dSDaniel Lezcano /*
643f52da98dSDaniel Lezcano  * Intervals are given in nanosecond base
644f52da98dSDaniel Lezcano  */
645f52da98dSDaniel Lezcano static u64 intervals0[] __initdata = {
646f52da98dSDaniel Lezcano 	10000, 50000, 200000, 500000,
647f52da98dSDaniel Lezcano 	10000, 50000, 200000, 500000,
648f52da98dSDaniel Lezcano 	10000, 50000, 200000, 500000,
649f52da98dSDaniel Lezcano 	10000, 50000, 200000, 500000,
650f52da98dSDaniel Lezcano 	10000, 50000, 200000, 500000,
651f52da98dSDaniel Lezcano 	10000, 50000, 200000, 500000,
652f52da98dSDaniel Lezcano 	10000, 50000, 200000, 500000,
653f52da98dSDaniel Lezcano 	10000, 50000, 200000, 500000,
654f52da98dSDaniel Lezcano 	10000, 50000, 200000,
655f52da98dSDaniel Lezcano };
656f52da98dSDaniel Lezcano 
657f52da98dSDaniel Lezcano static u64 intervals1[] __initdata = {
658f52da98dSDaniel Lezcano 	223947000, 1240000, 1384000, 1386000, 1386000,
659f52da98dSDaniel Lezcano 	217416000, 1236000, 1384000, 1386000, 1387000,
660f52da98dSDaniel Lezcano 	214719000, 1241000, 1386000, 1387000, 1384000,
661f52da98dSDaniel Lezcano 	213696000, 1234000, 1384000, 1386000, 1388000,
662f52da98dSDaniel Lezcano 	219904000, 1240000, 1385000, 1389000, 1385000,
663f52da98dSDaniel Lezcano 	212240000, 1240000, 1386000, 1386000, 1386000,
664f52da98dSDaniel Lezcano 	214415000, 1236000, 1384000, 1386000, 1387000,
665f52da98dSDaniel Lezcano 	214276000, 1234000,
666f52da98dSDaniel Lezcano };
667f52da98dSDaniel Lezcano 
668f52da98dSDaniel Lezcano static u64 intervals2[] __initdata = {
669f52da98dSDaniel Lezcano 	4000, 3000, 5000, 100000,
670f52da98dSDaniel Lezcano 	3000, 3000, 5000, 117000,
671f52da98dSDaniel Lezcano 	4000, 4000, 5000, 112000,
672f52da98dSDaniel Lezcano 	4000, 3000, 4000, 110000,
673f52da98dSDaniel Lezcano 	3000, 5000, 3000, 117000,
674f52da98dSDaniel Lezcano 	4000, 4000, 5000, 112000,
675f52da98dSDaniel Lezcano 	4000, 3000, 4000, 110000,
676f52da98dSDaniel Lezcano 	3000, 4000, 5000, 112000,
677f52da98dSDaniel Lezcano 	4000,
678f52da98dSDaniel Lezcano };
679f52da98dSDaniel Lezcano 
680f52da98dSDaniel Lezcano static u64 intervals3[] __initdata = {
681f52da98dSDaniel Lezcano 	1385000, 212240000, 1240000,
682f52da98dSDaniel Lezcano 	1386000, 214415000, 1236000,
683f52da98dSDaniel Lezcano 	1384000, 214276000, 1234000,
684f52da98dSDaniel Lezcano 	1386000, 214415000, 1236000,
685f52da98dSDaniel Lezcano 	1385000, 212240000, 1240000,
686f52da98dSDaniel Lezcano 	1386000, 214415000, 1236000,
687f52da98dSDaniel Lezcano 	1384000, 214276000, 1234000,
688f52da98dSDaniel Lezcano 	1386000, 214415000, 1236000,
689f52da98dSDaniel Lezcano 	1385000, 212240000, 1240000,
690f52da98dSDaniel Lezcano };
691f52da98dSDaniel Lezcano 
692f52da98dSDaniel Lezcano static u64 intervals4[] __initdata = {
693f52da98dSDaniel Lezcano 	10000, 50000, 10000, 50000,
694f52da98dSDaniel Lezcano 	10000, 50000, 10000, 50000,
695f52da98dSDaniel Lezcano 	10000, 50000, 10000, 50000,
696f52da98dSDaniel Lezcano 	10000, 50000, 10000, 50000,
697f52da98dSDaniel Lezcano 	10000, 50000, 10000, 50000,
698f52da98dSDaniel Lezcano 	10000, 50000, 10000, 50000,
699f52da98dSDaniel Lezcano 	10000, 50000, 10000, 50000,
700f52da98dSDaniel Lezcano 	10000, 50000, 10000, 50000,
701f52da98dSDaniel Lezcano 	10000,
702f52da98dSDaniel Lezcano };
703f52da98dSDaniel Lezcano 
704f52da98dSDaniel Lezcano static struct timings_intervals tis[] __initdata = {
705f52da98dSDaniel Lezcano 	{ intervals0, ARRAY_SIZE(intervals0) },
706f52da98dSDaniel Lezcano 	{ intervals1, ARRAY_SIZE(intervals1) },
707699785f5SDaniel Lezcano 	{ intervals2, ARRAY_SIZE(intervals2) },
708699785f5SDaniel Lezcano 	{ intervals3, ARRAY_SIZE(intervals3) },
709699785f5SDaniel Lezcano 	{ intervals4, ARRAY_SIZE(intervals4) },
710699785f5SDaniel Lezcano };
711699785f5SDaniel Lezcano 
irq_timings_test_next_index(struct timings_intervals * ti)712699785f5SDaniel Lezcano static int __init irq_timings_test_next_index(struct timings_intervals *ti)
713699785f5SDaniel Lezcano {
714699785f5SDaniel Lezcano 	int _buffer[IRQ_TIMINGS_SIZE];
715699785f5SDaniel Lezcano 	int buffer[IRQ_TIMINGS_SIZE];
716699785f5SDaniel Lezcano 	int index, start, i, count, period_max;
717699785f5SDaniel Lezcano 
718699785f5SDaniel Lezcano 	count = ti->count - 1;
719699785f5SDaniel Lezcano 
720699785f5SDaniel Lezcano 	period_max = count > (3 * PREDICTION_PERIOD_MAX) ?
721699785f5SDaniel Lezcano 		PREDICTION_PERIOD_MAX : count / 3;
722699785f5SDaniel Lezcano 
723699785f5SDaniel Lezcano 	/*
724699785f5SDaniel Lezcano 	 * Inject all values except the last one which will be used
725699785f5SDaniel Lezcano 	 * to compare with the next index result.
726699785f5SDaniel Lezcano 	 */
727699785f5SDaniel Lezcano 	pr_debug("index suite: ");
728699785f5SDaniel Lezcano 
729699785f5SDaniel Lezcano 	for (i = 0; i < count; i++) {
730699785f5SDaniel Lezcano 		index = irq_timings_interval_index(ti->intervals[i]);
731699785f5SDaniel Lezcano 		_buffer[i & IRQ_TIMINGS_MASK] = index;
732699785f5SDaniel Lezcano 		pr_cont("%d ", index);
733699785f5SDaniel Lezcano 	}
734699785f5SDaniel Lezcano 
735699785f5SDaniel Lezcano 	start = count < IRQ_TIMINGS_SIZE ? 0 :
736699785f5SDaniel Lezcano 		count & IRQ_TIMINGS_MASK;
737699785f5SDaniel Lezcano 
738699785f5SDaniel Lezcano 	count = min_t(int, count, IRQ_TIMINGS_SIZE);
739699785f5SDaniel Lezcano 
740699785f5SDaniel Lezcano 	for (i = 0; i < count; i++) {
741699785f5SDaniel Lezcano 		int index = (start + i) & IRQ_TIMINGS_MASK;
742699785f5SDaniel Lezcano 		buffer[i] = _buffer[index];
743699785f5SDaniel Lezcano 	}
744699785f5SDaniel Lezcano 
745699785f5SDaniel Lezcano 	index = irq_timings_next_event_index(buffer, count, period_max);
746699785f5SDaniel Lezcano 	i = irq_timings_interval_index(ti->intervals[ti->count - 1]);
747699785f5SDaniel Lezcano 
748699785f5SDaniel Lezcano 	if (index != i) {
749699785f5SDaniel Lezcano 		pr_err("Expected (%d) and computed (%d) next indexes differ\n",
750699785f5SDaniel Lezcano 		       i, index);
751699785f5SDaniel Lezcano 		return -EINVAL;
752699785f5SDaniel Lezcano 	}
753699785f5SDaniel Lezcano 
754699785f5SDaniel Lezcano 	return 0;
755699785f5SDaniel Lezcano }
756699785f5SDaniel Lezcano 
irq_timings_next_index_selftest(void)757699785f5SDaniel Lezcano static int __init irq_timings_next_index_selftest(void)
758699785f5SDaniel Lezcano {
759699785f5SDaniel Lezcano 	int i, ret;
760699785f5SDaniel Lezcano 
761699785f5SDaniel Lezcano 	for (i = 0; i < ARRAY_SIZE(tis); i++) {
762699785f5SDaniel Lezcano 
763699785f5SDaniel Lezcano 		pr_info("---> Injecting intervals number #%d (count=%zd)\n",
764699785f5SDaniel Lezcano 			i, tis[i].count);
765699785f5SDaniel Lezcano 
766699785f5SDaniel Lezcano 		ret = irq_timings_test_next_index(&tis[i]);
767699785f5SDaniel Lezcano 		if (ret)
768699785f5SDaniel Lezcano 			break;
769f52da98dSDaniel Lezcano 	}
770f52da98dSDaniel Lezcano 
771f52da98dSDaniel Lezcano 	return ret;
772f52da98dSDaniel Lezcano }
773f52da98dSDaniel Lezcano 
irq_timings_test_irqs(struct timings_intervals * ti)774f52da98dSDaniel Lezcano static int __init irq_timings_test_irqs(struct timings_intervals *ti)
775f52da98dSDaniel Lezcano {
776f52da98dSDaniel Lezcano 	struct irqt_stat __percpu *s;
777f52da98dSDaniel Lezcano 	struct irqt_stat *irqs;
778f52da98dSDaniel Lezcano 	int i, index, ret, irq = 0xACE5;
779f52da98dSDaniel Lezcano 
780f52da98dSDaniel Lezcano 	ret = irq_timings_alloc(irq);
781f52da98dSDaniel Lezcano 	if (ret) {
782f52da98dSDaniel Lezcano 		pr_err("Failed to allocate irq timings\n");
783f52da98dSDaniel Lezcano 		return ret;
784f52da98dSDaniel Lezcano 	}
785f52da98dSDaniel Lezcano 
786f52da98dSDaniel Lezcano 	s = idr_find(&irqt_stats, irq);
787f52da98dSDaniel Lezcano 	if (!s) {
788f52da98dSDaniel Lezcano 		ret = -EIDRM;
789f52da98dSDaniel Lezcano 		goto out;
790f52da98dSDaniel Lezcano 	}
791f52da98dSDaniel Lezcano 
792f52da98dSDaniel Lezcano 	irqs = this_cpu_ptr(s);
793f52da98dSDaniel Lezcano 
794f52da98dSDaniel Lezcano 	for (i = 0; i < ti->count; i++) {
795f52da98dSDaniel Lezcano 
796f52da98dSDaniel Lezcano 		index = irq_timings_interval_index(ti->intervals[i]);
797*290fdc4bSZhen Lei 		pr_debug("%d: interval=%llu ema_index=%d\n",
798f52da98dSDaniel Lezcano 			 i, ti->intervals[i], index);
799f52da98dSDaniel Lezcano 
800f52da98dSDaniel Lezcano 		__irq_timings_store(irq, irqs, ti->intervals[i]);
801f52da98dSDaniel Lezcano 		if (irqs->circ_timings[i & IRQ_TIMINGS_MASK] != index) {
802f52da98dSDaniel Lezcano 			ret = -EBADSLT;
803f52da98dSDaniel Lezcano 			pr_err("Failed to store in the circular buffer\n");
804*290fdc4bSZhen Lei 			goto out;
805f52da98dSDaniel Lezcano 		}
806f52da98dSDaniel Lezcano 	}
807f52da98dSDaniel Lezcano 
808f52da98dSDaniel Lezcano 	if (irqs->count != ti->count) {
809f52da98dSDaniel Lezcano 		ret = -ERANGE;
810f52da98dSDaniel Lezcano 		pr_err("Count differs\n");
811f52da98dSDaniel Lezcano 		goto out;
812f52da98dSDaniel Lezcano 	}
813f52da98dSDaniel Lezcano 
814f52da98dSDaniel Lezcano 	ret = 0;
815f52da98dSDaniel Lezcano out:
816f52da98dSDaniel Lezcano 	irq_timings_free(irq);
817f52da98dSDaniel Lezcano 
818f52da98dSDaniel Lezcano 	return ret;
819f52da98dSDaniel Lezcano }
820f52da98dSDaniel Lezcano 
irq_timings_irqs_selftest(void)821f52da98dSDaniel Lezcano static int __init irq_timings_irqs_selftest(void)
822f52da98dSDaniel Lezcano {
823f52da98dSDaniel Lezcano 	int i, ret;
824f52da98dSDaniel Lezcano 
825f52da98dSDaniel Lezcano 	for (i = 0; i < ARRAY_SIZE(tis); i++) {
826f52da98dSDaniel Lezcano 		pr_info("---> Injecting intervals number #%d (count=%zd)\n",
827f52da98dSDaniel Lezcano 			i, tis[i].count);
828f52da98dSDaniel Lezcano 		ret = irq_timings_test_irqs(&tis[i]);
829f52da98dSDaniel Lezcano 		if (ret)
830f52da98dSDaniel Lezcano 			break;
8316aed82deSDaniel Lezcano 	}
8326aed82deSDaniel Lezcano 
8336aed82deSDaniel Lezcano 	return ret;
8346aed82deSDaniel Lezcano }
8356aed82deSDaniel Lezcano 
irq_timings_test_irqts(struct irq_timings * irqts,unsigned count)8366aed82deSDaniel Lezcano static int __init irq_timings_test_irqts(struct irq_timings *irqts,
8376aed82deSDaniel Lezcano 					 unsigned count)
8386aed82deSDaniel Lezcano {
8396aed82deSDaniel Lezcano 	int start = count >= IRQ_TIMINGS_SIZE ? count - IRQ_TIMINGS_SIZE : 0;
8406aed82deSDaniel Lezcano 	int i, irq, oirq = 0xBEEF;
8416aed82deSDaniel Lezcano 	u64 ots = 0xDEAD, ts;
8426aed82deSDaniel Lezcano 
8436aed82deSDaniel Lezcano 	/*
8446aed82deSDaniel Lezcano 	 * Fill the circular buffer by using the dedicated function.
8456aed82deSDaniel Lezcano 	 */
8466aed82deSDaniel Lezcano 	for (i = 0; i < count; i++) {
8476aed82deSDaniel Lezcano 		pr_debug("%d: index=%d, ts=%llX irq=%X\n",
8486aed82deSDaniel Lezcano 			 i, i & IRQ_TIMINGS_MASK, ots + i, oirq + i);
8496aed82deSDaniel Lezcano 
8506aed82deSDaniel Lezcano 		irq_timings_push(ots + i, oirq + i);
8516aed82deSDaniel Lezcano 	}
8526aed82deSDaniel Lezcano 
8536aed82deSDaniel Lezcano 	/*
8546aed82deSDaniel Lezcano 	 * Compute the first elements values after the index wrapped
8556aed82deSDaniel Lezcano 	 * up or not.
8566aed82deSDaniel Lezcano 	 */
8576aed82deSDaniel Lezcano 	ots += start;
8586aed82deSDaniel Lezcano 	oirq += start;
8596aed82deSDaniel Lezcano 
8606aed82deSDaniel Lezcano 	/*
8616aed82deSDaniel Lezcano 	 * Test the circular buffer count is correct.
8626aed82deSDaniel Lezcano 	 */
8636aed82deSDaniel Lezcano 	pr_debug("---> Checking timings array count (%d) is right\n", count);
8646aed82deSDaniel Lezcano 	if (WARN_ON(irqts->count != count))
8656aed82deSDaniel Lezcano 		return -EINVAL;
8666aed82deSDaniel Lezcano 
8676aed82deSDaniel Lezcano 	/*
8686aed82deSDaniel Lezcano 	 * Test the macro allowing to browse all the irqts.
8696aed82deSDaniel Lezcano 	 */
8706aed82deSDaniel Lezcano 	pr_debug("---> Checking the for_each_irqts() macro\n");
8716aed82deSDaniel Lezcano 	for_each_irqts(i, irqts) {
8726aed82deSDaniel Lezcano 
8736aed82deSDaniel Lezcano 		irq = irq_timing_decode(irqts->values[i], &ts);
8746aed82deSDaniel Lezcano 
8756aed82deSDaniel Lezcano 		pr_debug("index=%d, ts=%llX / %llX, irq=%X / %X\n",
8766aed82deSDaniel Lezcano 			 i, ts, ots, irq, oirq);
8776aed82deSDaniel Lezcano 
8786aed82deSDaniel Lezcano 		if (WARN_ON(ts != ots || irq != oirq))
8796aed82deSDaniel Lezcano 			return -EINVAL;
8806aed82deSDaniel Lezcano 
8816aed82deSDaniel Lezcano 		ots++; oirq++;
8826aed82deSDaniel Lezcano 	}
8836aed82deSDaniel Lezcano 
8846aed82deSDaniel Lezcano 	/*
8856aed82deSDaniel Lezcano 	 * The circular buffer should have be flushed when browsed
8866aed82deSDaniel Lezcano 	 * with for_each_irqts
8876aed82deSDaniel Lezcano 	 */
8886aed82deSDaniel Lezcano 	pr_debug("---> Checking timings array is empty after browsing it\n");
8896aed82deSDaniel Lezcano 	if (WARN_ON(irqts->count))
8906aed82deSDaniel Lezcano 		return -EINVAL;
8916aed82deSDaniel Lezcano 
8926aed82deSDaniel Lezcano 	return 0;
8936aed82deSDaniel Lezcano }
8946aed82deSDaniel Lezcano 
irq_timings_irqts_selftest(void)8956aed82deSDaniel Lezcano static int __init irq_timings_irqts_selftest(void)
8966aed82deSDaniel Lezcano {
8976aed82deSDaniel Lezcano 	struct irq_timings *irqts = this_cpu_ptr(&irq_timings);
8986aed82deSDaniel Lezcano 	int i, ret;
8996aed82deSDaniel Lezcano 
9006aed82deSDaniel Lezcano 	/*
9016aed82deSDaniel Lezcano 	 * Test the circular buffer with different number of
9026aed82deSDaniel Lezcano 	 * elements. The purpose is to test at the limits (empty, half
9036aed82deSDaniel Lezcano 	 * full, full, wrapped with the cursor at the boundaries,
9046aed82deSDaniel Lezcano 	 * wrapped several times, etc ...
9056aed82deSDaniel Lezcano 	 */
9066aed82deSDaniel Lezcano 	int count[] = { 0,
9076aed82deSDaniel Lezcano 			IRQ_TIMINGS_SIZE >> 1,
9086aed82deSDaniel Lezcano 			IRQ_TIMINGS_SIZE,
9096aed82deSDaniel Lezcano 			IRQ_TIMINGS_SIZE + (IRQ_TIMINGS_SIZE >> 1),
9106aed82deSDaniel Lezcano 			2 * IRQ_TIMINGS_SIZE,
9116aed82deSDaniel Lezcano 			(2 * IRQ_TIMINGS_SIZE) + 3,
9126aed82deSDaniel Lezcano 	};
9136aed82deSDaniel Lezcano 
9146aed82deSDaniel Lezcano 	for (i = 0; i < ARRAY_SIZE(count); i++) {
9156aed82deSDaniel Lezcano 
9166aed82deSDaniel Lezcano 		pr_info("---> Checking the timings with %d/%d values\n",
9176aed82deSDaniel Lezcano 			count[i], IRQ_TIMINGS_SIZE);
9186aed82deSDaniel Lezcano 
9196aed82deSDaniel Lezcano 		ret = irq_timings_test_irqts(irqts, count[i]);
9206aed82deSDaniel Lezcano 		if (ret)
9216aed82deSDaniel Lezcano 			break;
9226aed82deSDaniel Lezcano 	}
9236aed82deSDaniel Lezcano 
9246aed82deSDaniel Lezcano 	return ret;
9256aed82deSDaniel Lezcano }
9266aed82deSDaniel Lezcano 
irq_timings_selftest(void)9276aed82deSDaniel Lezcano static int __init irq_timings_selftest(void)
9286aed82deSDaniel Lezcano {
9296aed82deSDaniel Lezcano 	int ret;
9306aed82deSDaniel Lezcano 
9316aed82deSDaniel Lezcano 	pr_info("------------------- selftest start -----------------\n");
9326aed82deSDaniel Lezcano 
9336aed82deSDaniel Lezcano 	/*
9346aed82deSDaniel Lezcano 	 * At this point, we don't except any subsystem to use the irq
9356aed82deSDaniel Lezcano 	 * timings but us, so it should not be enabled.
9366aed82deSDaniel Lezcano 	 */
9376aed82deSDaniel Lezcano 	if (static_branch_unlikely(&irq_timing_enabled)) {
938f52da98dSDaniel Lezcano 		pr_warn("irq timings already initialized, skipping selftest\n");
939f52da98dSDaniel Lezcano 		return 0;
9406aed82deSDaniel Lezcano 	}
941f52da98dSDaniel Lezcano 
942699785f5SDaniel Lezcano 	ret = irq_timings_irqts_selftest();
943699785f5SDaniel Lezcano 	if (ret)
944699785f5SDaniel Lezcano 		goto out;
945699785f5SDaniel Lezcano 
946f52da98dSDaniel Lezcano 	ret = irq_timings_irqs_selftest();
9476aed82deSDaniel Lezcano 	if (ret)
9486aed82deSDaniel Lezcano 		goto out;
9496aed82deSDaniel Lezcano 
9506aed82deSDaniel Lezcano 	ret = irq_timings_next_index_selftest();
9516aed82deSDaniel Lezcano out:
9526aed82deSDaniel Lezcano 	pr_info("---------- selftest end with %s -----------\n",
9536aed82deSDaniel Lezcano 		ret ? "failure" : "success");
954 
955 	return ret;
956 }
957 early_initcall(irq_timings_selftest);
958 #endif
959