^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) // Copyright (C) 2016, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #define pr_fmt(fmt) "irq_timings: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/percpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/static_key.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/idr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/math64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/log2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <trace/events/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "internals.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) DEFINE_STATIC_KEY_FALSE(irq_timing_enabled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) DEFINE_PER_CPU(struct irq_timings, irq_timings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static DEFINE_IDR(irqt_stats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) void irq_timings_enable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static_branch_enable(&irq_timing_enabled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) void irq_timings_disable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static_branch_disable(&irq_timing_enabled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * The main goal of this algorithm is to predict the next interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * occurrence on the current CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * Currently, the interrupt timings are stored in a circular array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * buffer every time there is an interrupt, as a tuple: the interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * number and the associated timestamp when the event occurred <irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * timestamp>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * For every interrupt occurring in a short period of time, we can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * measure the elapsed time between the occurrences for the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * interrupt and we end up with a suite of intervals. The experience
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * showed the interrupts are often coming following a periodic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * pattern.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * The objective of the algorithm is to find out this periodic pattern
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * in a fastest way and use its period to predict the next irq event.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * When the next interrupt event is requested, we are in the situation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * where the interrupts are disabled and the circular buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * containing the timings is filled with the events which happened
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * after the previous next-interrupt-event request.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * At this point, we read the circular buffer and we fill the irq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * related statistics structure. After this step, the circular array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * containing the timings is empty because all the values are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * dispatched in their corresponding buffers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * Now for each interrupt, we can predict the next event by using the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * suffix array, log interval and exponential moving average
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * 1. Suffix array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * Suffix array is an array of all the suffixes of a string. It is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * widely used as a data structure for compression, text search, ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * For instance for the word 'banana', the suffixes will be: 'banana'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * 'anana' 'nana' 'ana' 'na' 'a'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * Usually, the suffix array is sorted but for our purpose it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * not necessary and won't provide any improvement in the context of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * the solved problem where we clearly define the boundaries of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * search by a max period and min period.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * The suffix array will build a suite of intervals of different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * length and will look for the repetition of each suite. If the suite
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * is repeating then we have the period because it is the length of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * the suite whatever its position in the buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * 2. Log interval
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * We saw the irq timings allow to compute the interval of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * occurrences for a specific interrupt. We can reasonibly assume the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * longer is the interval, the higher is the error for the next event
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * and we can consider storing those interval values into an array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * where each slot in the array correspond to an interval at the power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * of 2 of the index. For example, index 12 will contain values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * between 2^11 and 2^12.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * At the end we have an array of values where at each index defines a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * [2^index - 1, 2 ^ index] interval values allowing to store a large
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * number of values inside a small array.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * For example, if we have the value 1123, then we store it at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * ilog2(1123) = 10 index value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * Storing those value at the specific index is done by computing an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * exponential moving average for this specific slot. For instance,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * for values 1800, 1123, 1453, ... fall under the same slot (10) and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * the exponential moving average is computed every time a new value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * is stored at this slot.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * 3. Exponential Moving Average
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * The EMA is largely used to track a signal for stocks or as a low
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * pass filter. The magic of the formula, is it is very simple and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * reactivity of the average can be tuned with the factors called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * alpha.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * The higher the alphas are, the faster the average respond to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * signal change. In our case, if a slot in the array is a big
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * interval, we can have numbers with a big difference between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * them. The impact of those differences in the average computation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * can be tuned by changing the alpha value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * -- The algorithm --
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * We saw the different processing above, now let's see how they are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * used together.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * For each interrupt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * For each interval:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * Compute the index = ilog2(interval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * Compute a new_ema(buffer[index], interval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * Store the index in a circular buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * Compute the suffix array of the indexes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * For each suffix:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * If the suffix is reverse-found 3 times
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * Return suffix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * Return Not found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * However we can not have endless suffix array to be build, it won't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * make sense and it will add an extra overhead, so we can restrict
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * this to a maximum suffix length of 5 and a minimum suffix length of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * 2. The experience showed 5 is the majority of the maximum pattern
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * period found for different devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * The result is a pattern finding less than 1us for an interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * Example based on real values:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * Example 1 : MMC write/read interrupt interval:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * 223947, 1240, 1384, 1386, 1386,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * 217416, 1236, 1384, 1386, 1387,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * 214719, 1241, 1386, 1387, 1384,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * 213696, 1234, 1384, 1386, 1388,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * 219904, 1240, 1385, 1389, 1385,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * 212240, 1240, 1386, 1386, 1386,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * 214415, 1236, 1384, 1386, 1387,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * 214276, 1234, 1384, 1388, ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * For each element, apply ilog2(value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * 15, 8, 8, 8, ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * Max period of 5, we take the last (max_period * 3) 15 elements as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * we can be confident if the pattern repeats itself three times it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * a repeating pattern.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * 15, 8, 8, 8, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * 15, 8, 8, 8, ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * Suffixes are:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * 1) 8, 15, 8, 8, 8 <- max period
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * 2) 8, 15, 8, 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * 3) 8, 15, 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * 4) 8, 15 <- min period
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * From there we search the repeating pattern for each suffix.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * buffer: 8, 15, 8, 8, 8, 8, 15, 8, 8, 8, 8, 15, 8, 8, 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * | | | | | | | | | | | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * 8, 15, 8, 8, 8 | | | | | | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * 8, 15, 8, 8, 8 | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * 8, 15, 8, 8, 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * When moving the suffix, we found exactly 3 matches.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * The first suffix with period 5 is repeating.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * The next event is (3 * max_period) % suffix_period
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * In this example, the result 0, so the next event is suffix[0] => 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * However, 8 is the index in the array of exponential moving average
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * which was calculated on the fly when storing the values, so the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * interval is ema[8] = 1366
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * Example 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * 4, 3, 5, 100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * 3, 3, 5, 117,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * 4, 4, 5, 112,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * 4, 3, 4, 110,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * 3, 5, 3, 117,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * 4, 4, 5, 112,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * 4, 3, 4, 110,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * 3, 4, 5, 112,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * 4, 3, 4, 110
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * ilog2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * 0, 0, 0, 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * Max period 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * 0, 0, 0, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * 0, 0, 0, 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * Suffixes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * 1) 0, 0, 4, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * 2) 0, 0, 4, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * 3) 0, 0, 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * 4) 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * buffer: 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * | | | | | | X
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * 0, 0, 4, 0, 0, | X
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * buffer: 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * | | | | | | | | | | | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * 0, 0, 4, 0, | | | | | | | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * 0, 0, 4, 0, | | | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * 0, 0, 4, 0, | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * 0 0 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * Pattern is found 3 times, the remaining is 1 which results from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * (max_period * 3) % suffix_period. This value is the index in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * suffix arrays. The suffix array for a period 4 has the value 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * at index 1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) #define EMA_ALPHA_VAL 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) #define EMA_ALPHA_SHIFT 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) #define PREDICTION_PERIOD_MIN 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) #define PREDICTION_PERIOD_MAX 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) #define PREDICTION_FACTOR 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) #define PREDICTION_MAX 10 /* 2 ^ PREDICTION_MAX useconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) #define PREDICTION_BUFFER_SIZE 16 /* slots for EMAs, hardly more than 16 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * Number of elements in the circular buffer: If it happens it was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * flushed before, then the number of elements could be smaller than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * IRQ_TIMINGS_SIZE, so the count is used, otherwise the array size is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * used as we wrapped. The index begins from zero when we did not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * wrap. That could be done in a nicer way with the proper circular
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * array structure type but with the cost of extra computation in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * interrupt handler hot path. We choose efficiency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) #define for_each_irqts(i, irqts) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) for (i = irqts->count < IRQ_TIMINGS_SIZE ? \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 0 : irqts->count & IRQ_TIMINGS_MASK, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) irqts->count = min(IRQ_TIMINGS_SIZE, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) irqts->count); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) irqts->count > 0; irqts->count--, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) i = (i + 1) & IRQ_TIMINGS_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) struct irqt_stat {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) u64 last_ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) u64 ema_time[PREDICTION_BUFFER_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) int timings[IRQ_TIMINGS_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) int circ_timings[IRQ_TIMINGS_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * Exponential moving average computation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static u64 irq_timings_ema_new(u64 value, u64 ema_old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) s64 diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (unlikely(!ema_old))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) diff = (value - ema_old) * EMA_ALPHA_VAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) * We can use a s64 type variable to be added with the u64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * ema_old variable as this one will never have its topmost
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * bit set, it will be always smaller than 2^63 nanosec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * interrupt interval (292 years).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return ema_old + (diff >> EMA_ALPHA_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static int irq_timings_next_event_index(int *buffer, size_t len, int period_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) int period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) * Move the beginning pointer to the end minus the max period x 3.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * We are at the point we can begin searching the pattern
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) buffer = &buffer[len - (period_max * 3)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) /* Adjust the length to the maximum allowed period x 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) len = period_max * 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) * The buffer contains the suite of intervals, in a ilog2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * basis, we are looking for a repetition. We point the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * beginning of the search three times the length of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) * period beginning at the end of the buffer. We do that for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * each suffix.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) for (period = period_max; period >= PREDICTION_PERIOD_MIN; period--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * The first comparison always succeed because the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * suffix is deduced from the first n-period bytes of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * the buffer and we compare the initial suffix with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) * itself, so we can skip the first iteration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) int idx = period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) size_t size = period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * We look if the suite with period 'i' repeat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) * itself. If it is truncated at the end, as it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * repeats we can use the period to find out the next
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * element with the modulo.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) while (!memcmp(buffer, &buffer[idx], size * sizeof(int))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) * Move the index in a period basis
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) idx += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * If this condition is reached, all previous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) * memcmp were successful, so the period is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (idx == len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return buffer[len % period];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * If the remaining elements to compare are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * smaller than the period, readjust the size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) * of the comparison for the last iteration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (len - idx < period)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) size = len - idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) static u64 __irq_timings_next_event(struct irqt_stat *irqs, int irq, u64 now)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) int index, i, period_max, count, start, min = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if ((now - irqs->last_ts) >= NSEC_PER_SEC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) irqs->count = irqs->last_ts = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return U64_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * As we want to find three times the repetition, we need a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * number of intervals greater or equal to three times the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * maximum period, otherwise we truncate the max period.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) period_max = irqs->count > (3 * PREDICTION_PERIOD_MAX) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) PREDICTION_PERIOD_MAX : irqs->count / 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * If we don't have enough irq timings for this prediction,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * just bail out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (period_max <= PREDICTION_PERIOD_MIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return U64_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * 'count' will depends if the circular buffer wrapped or not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) count = irqs->count < IRQ_TIMINGS_SIZE ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) irqs->count : IRQ_TIMINGS_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) start = irqs->count < IRQ_TIMINGS_SIZE ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 0 : (irqs->count & IRQ_TIMINGS_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * Copy the content of the circular buffer into another buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) * in order to linearize the buffer instead of dealing with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * wrapping indexes and shifted array which will be prone to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * error and extremelly difficult to debug.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) int index = (start + i) & IRQ_TIMINGS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) irqs->timings[i] = irqs->circ_timings[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) min = min_t(int, irqs->timings[i], min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) index = irq_timings_next_event_index(irqs->timings, count, period_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (index < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return irqs->last_ts + irqs->ema_time[min];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return irqs->last_ts + irqs->ema_time[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) static __always_inline int irq_timings_interval_index(u64 interval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * The PREDICTION_FACTOR increase the interval size for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * array of exponential average.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) u64 interval_us = (interval >> 10) / PREDICTION_FACTOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return likely(interval_us) ? ilog2(interval_us) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) static __always_inline void __irq_timings_store(int irq, struct irqt_stat *irqs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) u64 interval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * Get the index in the ema table for this interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) index = irq_timings_interval_index(interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (index > PREDICTION_BUFFER_SIZE - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) irqs->count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) * Store the index as an element of the pattern in another
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * circular array.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) irqs->circ_timings[irqs->count & IRQ_TIMINGS_MASK] = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) irqs->ema_time[index] = irq_timings_ema_new(interval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) irqs->ema_time[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) irqs->count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static inline void irq_timings_store(int irq, struct irqt_stat *irqs, u64 ts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) u64 old_ts = irqs->last_ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) u64 interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) * The timestamps are absolute time values, we need to compute
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) * the timing interval between two interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) irqs->last_ts = ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) * The interval type is u64 in order to deal with the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) * type in our computation, that prevent mindfuck issues with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) * overflow, sign and division.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) interval = ts - old_ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) * The interrupt triggered more than one second apart, that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * ends the sequence as predictible for our purpose. In this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) * case, assume we have the beginning of a sequence and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * timestamp is the first value. As it is impossible to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * predict anything at this point, return.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * Note the first timestamp of the sequence will always fall
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * in this test because the old_ts is zero. That is what we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * want as we need another timestamp to compute an interval.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (interval >= NSEC_PER_SEC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) irqs->count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) __irq_timings_store(irq, irqs, interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) * irq_timings_next_event - Return when the next event is supposed to arrive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * During the last busy cycle, the number of interrupts is incremented
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * and stored in the irq_timings structure. This information is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) * necessary to:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * - know if the index in the table wrapped up:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * If more than the array size interrupts happened during the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) * last busy/idle cycle, the index wrapped up and we have to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) * begin with the next element in the array which is the last one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) * in the sequence, otherwise it is a the index 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * - have an indication of the interrupts activity on this CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * (eg. irq/sec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * The values are 'consumed' after inserting in the statistical model,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * thus the count is reinitialized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) * The array of values **must** be browsed in the time direction, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * timestamp must increase between an element and the next one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) * Returns a nanosec time based estimation of the earliest interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) * U64_MAX otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) u64 irq_timings_next_event(u64 now)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) struct irq_timings *irqts = this_cpu_ptr(&irq_timings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) struct irqt_stat *irqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct irqt_stat __percpu *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) u64 ts, next_evt = U64_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) int i, irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) * This function must be called with the local irq disabled in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) * order to prevent the timings circular buffer to be updated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) * while we are reading it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) lockdep_assert_irqs_disabled();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if (!irqts->count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return next_evt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * Number of elements in the circular buffer: If it happens it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * was flushed before, then the number of elements could be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * smaller than IRQ_TIMINGS_SIZE, so the count is used,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * otherwise the array size is used as we wrapped. The index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * begins from zero when we did not wrap. That could be done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * in a nicer way with the proper circular array structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * type but with the cost of extra computation in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * interrupt handler hot path. We choose efficiency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * Inject measured irq/timestamp to the pattern prediction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * model while decrementing the counter because we consume the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * data from our circular buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) for_each_irqts(i, irqts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) irq = irq_timing_decode(irqts->values[i], &ts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) s = idr_find(&irqt_stats, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) irq_timings_store(irq, this_cpu_ptr(s), ts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * Look in the list of interrupts' statistics, the earliest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * next event.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) idr_for_each_entry(&irqt_stats, s, i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) irqs = this_cpu_ptr(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) ts = __irq_timings_next_event(irqs, i, now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) if (ts <= now)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) return now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (ts < next_evt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) next_evt = ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) return next_evt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) void irq_timings_free(int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) struct irqt_stat __percpu *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) s = idr_find(&irqt_stats, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if (s) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) free_percpu(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) idr_remove(&irqt_stats, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) int irq_timings_alloc(int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) struct irqt_stat __percpu *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) * Some platforms can have the same private interrupt per cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) * so this function may be called several times with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) * same interrupt number. Just bail out in case the per cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) * stat structure is already allocated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) s = idr_find(&irqt_stats, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) s = alloc_percpu(*s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (!s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) idr_preload(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) id = idr_alloc(&irqt_stats, s, irq, irq + 1, GFP_NOWAIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) idr_preload_end();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) if (id < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) free_percpu(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) #ifdef CONFIG_TEST_IRQ_TIMINGS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) struct timings_intervals {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) u64 *intervals;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) size_t count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * Intervals are given in nanosecond base
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) static u64 intervals0[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 10000, 50000, 200000, 500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 10000, 50000, 200000, 500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 10000, 50000, 200000, 500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 10000, 50000, 200000, 500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 10000, 50000, 200000, 500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 10000, 50000, 200000, 500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 10000, 50000, 200000, 500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 10000, 50000, 200000, 500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 10000, 50000, 200000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) static u64 intervals1[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 223947000, 1240000, 1384000, 1386000, 1386000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 217416000, 1236000, 1384000, 1386000, 1387000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 214719000, 1241000, 1386000, 1387000, 1384000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 213696000, 1234000, 1384000, 1386000, 1388000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 219904000, 1240000, 1385000, 1389000, 1385000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 212240000, 1240000, 1386000, 1386000, 1386000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 214415000, 1236000, 1384000, 1386000, 1387000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 214276000, 1234000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) static u64 intervals2[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 4000, 3000, 5000, 100000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 3000, 3000, 5000, 117000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 4000, 4000, 5000, 112000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 4000, 3000, 4000, 110000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 3000, 5000, 3000, 117000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 4000, 4000, 5000, 112000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 4000, 3000, 4000, 110000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 3000, 4000, 5000, 112000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 4000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) static u64 intervals3[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 1385000, 212240000, 1240000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 1386000, 214415000, 1236000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 1384000, 214276000, 1234000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 1386000, 214415000, 1236000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 1385000, 212240000, 1240000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 1386000, 214415000, 1236000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 1384000, 214276000, 1234000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 1386000, 214415000, 1236000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 1385000, 212240000, 1240000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) static u64 intervals4[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 10000, 50000, 10000, 50000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 10000, 50000, 10000, 50000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 10000, 50000, 10000, 50000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 10000, 50000, 10000, 50000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 10000, 50000, 10000, 50000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 10000, 50000, 10000, 50000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 10000, 50000, 10000, 50000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 10000, 50000, 10000, 50000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 10000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) static struct timings_intervals tis[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) { intervals0, ARRAY_SIZE(intervals0) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) { intervals1, ARRAY_SIZE(intervals1) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) { intervals2, ARRAY_SIZE(intervals2) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) { intervals3, ARRAY_SIZE(intervals3) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) { intervals4, ARRAY_SIZE(intervals4) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) static int __init irq_timings_test_next_index(struct timings_intervals *ti)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) int _buffer[IRQ_TIMINGS_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) int buffer[IRQ_TIMINGS_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) int index, start, i, count, period_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) count = ti->count - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) period_max = count > (3 * PREDICTION_PERIOD_MAX) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) PREDICTION_PERIOD_MAX : count / 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * Inject all values except the last one which will be used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) * to compare with the next index result.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) pr_debug("index suite: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) index = irq_timings_interval_index(ti->intervals[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) _buffer[i & IRQ_TIMINGS_MASK] = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) pr_cont("%d ", index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) start = count < IRQ_TIMINGS_SIZE ? 0 :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) count & IRQ_TIMINGS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) count = min_t(int, count, IRQ_TIMINGS_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) int index = (start + i) & IRQ_TIMINGS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) buffer[i] = _buffer[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) index = irq_timings_next_event_index(buffer, count, period_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) i = irq_timings_interval_index(ti->intervals[ti->count - 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) if (index != i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) pr_err("Expected (%d) and computed (%d) next indexes differ\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) i, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) static int __init irq_timings_next_index_selftest(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) for (i = 0; i < ARRAY_SIZE(tis); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) pr_info("---> Injecting intervals number #%d (count=%zd)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) i, tis[i].count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) ret = irq_timings_test_next_index(&tis[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) static int __init irq_timings_test_irqs(struct timings_intervals *ti)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) struct irqt_stat __percpu *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) struct irqt_stat *irqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) int i, index, ret, irq = 0xACE5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) ret = irq_timings_alloc(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) pr_err("Failed to allocate irq timings\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) s = idr_find(&irqt_stats, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) if (!s) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) ret = -EIDRM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) irqs = this_cpu_ptr(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) for (i = 0; i < ti->count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) index = irq_timings_interval_index(ti->intervals[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) pr_debug("%d: interval=%llu ema_index=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) i, ti->intervals[i], index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) __irq_timings_store(irq, irqs, ti->intervals[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) if (irqs->circ_timings[i & IRQ_TIMINGS_MASK] != index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) ret = -EBADSLT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) pr_err("Failed to store in the circular buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) if (irqs->count != ti->count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) ret = -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) pr_err("Count differs\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) irq_timings_free(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) static int __init irq_timings_irqs_selftest(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) for (i = 0; i < ARRAY_SIZE(tis); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) pr_info("---> Injecting intervals number #%d (count=%zd)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) i, tis[i].count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) ret = irq_timings_test_irqs(&tis[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) static int __init irq_timings_test_irqts(struct irq_timings *irqts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) unsigned count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) int start = count >= IRQ_TIMINGS_SIZE ? count - IRQ_TIMINGS_SIZE : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) int i, irq, oirq = 0xBEEF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) u64 ots = 0xDEAD, ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) * Fill the circular buffer by using the dedicated function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) pr_debug("%d: index=%d, ts=%llX irq=%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) i, i & IRQ_TIMINGS_MASK, ots + i, oirq + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) irq_timings_push(ots + i, oirq + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) * Compute the first elements values after the index wrapped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * up or not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) ots += start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) oirq += start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) * Test the circular buffer count is correct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) pr_debug("---> Checking timings array count (%d) is right\n", count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (WARN_ON(irqts->count != count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) * Test the macro allowing to browse all the irqts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) pr_debug("---> Checking the for_each_irqts() macro\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) for_each_irqts(i, irqts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) irq = irq_timing_decode(irqts->values[i], &ts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) pr_debug("index=%d, ts=%llX / %llX, irq=%X / %X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) i, ts, ots, irq, oirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if (WARN_ON(ts != ots || irq != oirq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) ots++; oirq++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) * The circular buffer should have be flushed when browsed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) * with for_each_irqts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) pr_debug("---> Checking timings array is empty after browsing it\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) if (WARN_ON(irqts->count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) static int __init irq_timings_irqts_selftest(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) struct irq_timings *irqts = this_cpu_ptr(&irq_timings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) * Test the circular buffer with different number of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) * elements. The purpose is to test at the limits (empty, half
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) * full, full, wrapped with the cursor at the boundaries,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) * wrapped several times, etc ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) int count[] = { 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) IRQ_TIMINGS_SIZE >> 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) IRQ_TIMINGS_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) IRQ_TIMINGS_SIZE + (IRQ_TIMINGS_SIZE >> 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) 2 * IRQ_TIMINGS_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) (2 * IRQ_TIMINGS_SIZE) + 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) for (i = 0; i < ARRAY_SIZE(count); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) pr_info("---> Checking the timings with %d/%d values\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) count[i], IRQ_TIMINGS_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) ret = irq_timings_test_irqts(irqts, count[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) static int __init irq_timings_selftest(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) pr_info("------------------- selftest start -----------------\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) * At this point, we don't except any subsystem to use the irq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) * timings but us, so it should not be enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) if (static_branch_unlikely(&irq_timing_enabled)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) pr_warn("irq timings already initialized, skipping selftest\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) ret = irq_timings_irqts_selftest();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) ret = irq_timings_irqs_selftest();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) ret = irq_timings_next_index_selftest();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) pr_info("---------- selftest end with %s -----------\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) ret ? "failure" : "success");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) early_initcall(irq_timings_selftest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) #endif