@@ -266,11 +266,6 @@ struct timer_base {
266
266
267
267
static DEFINE_PER_CPU (struct timer_base , timer_bases [NR_BASES ]) ;
268
268
269
- struct timer_events {
270
- u64 local ;
271
- u64 global ;
272
- };
273
-
274
269
#ifdef CONFIG_NO_HZ_COMMON
275
270
276
271
static DEFINE_STATIC_KEY_FALSE (timers_nohz_active );
@@ -2058,6 +2053,21 @@ static unsigned long fetch_next_timer_interrupt(unsigned long basej, u64 basem,
2058
2053
if (time_before (nextevt , basej ))
2059
2054
nextevt = basej ;
2060
2055
tevt -> local = basem + (u64 )(nextevt - basej ) * TICK_NSEC ;
2056
+
2057
+ /*
2058
+ * This is required for the remote check only but it doesn't
2059
+ * hurt, when it is done for both call sites:
2060
+ *
2061
+ * * The remote callers will only take care of the global timers
2062
+ * as local timers will be handled by CPU itself. When not
2063
+ * updating tevt->global with the already missed first global
2064
+ * timer, it is possible that it will be missed completely.
2065
+ *
2066
+ * * The local callers will ignore the tevt->global anyway, when
2067
+ * nextevt is max. one tick away.
2068
+ */
2069
+ if (!local_first )
2070
+ tevt -> global = tevt -> local ;
2061
2071
return nextevt ;
2062
2072
}
2063
2073
@@ -2076,6 +2086,81 @@ static unsigned long fetch_next_timer_interrupt(unsigned long basej, u64 basem,
2076
2086
return nextevt ;
2077
2087
}
2078
2088
2089
+ # ifdef CONFIG_SMP
2090
+ /**
2091
+ * fetch_next_timer_interrupt_remote() - Store next timers into @tevt
2092
+ * @basej: base time jiffies
2093
+ * @basem: base time clock monotonic
2094
+ * @tevt: Pointer to the storage for the expiry values
2095
+ * @cpu: Remote CPU
2096
+ *
2097
+ * Stores the next pending local and global timer expiry values in the
2098
+ * struct pointed to by @tevt. If a queue is empty the corresponding
2099
+ * field is set to KTIME_MAX. If local event expires before global
2100
+ * event, global event is set to KTIME_MAX as well.
2101
+ *
2102
+ * Caller needs to make sure timer base locks are held (use
2103
+ * timer_lock_remote_bases() for this purpose).
2104
+ */
2105
+ void fetch_next_timer_interrupt_remote (unsigned long basej , u64 basem ,
2106
+ struct timer_events * tevt ,
2107
+ unsigned int cpu )
2108
+ {
2109
+ struct timer_base * base_local , * base_global ;
2110
+
2111
+ /* Preset local / global events */
2112
+ tevt -> local = tevt -> global = KTIME_MAX ;
2113
+
2114
+ base_local = per_cpu_ptr (& timer_bases [BASE_LOCAL ], cpu );
2115
+ base_global = per_cpu_ptr (& timer_bases [BASE_GLOBAL ], cpu );
2116
+
2117
+ lockdep_assert_held (& base_local -> lock );
2118
+ lockdep_assert_held (& base_global -> lock );
2119
+
2120
+ fetch_next_timer_interrupt (basej , basem , base_local , base_global , tevt );
2121
+ }
2122
+
2123
+ /**
2124
+ * timer_unlock_remote_bases - unlock timer bases of cpu
2125
+ * @cpu: Remote CPU
2126
+ *
2127
+ * Unlocks the remote timer bases.
2128
+ */
2129
+ void timer_unlock_remote_bases (unsigned int cpu )
2130
+ __releases (timer_bases [BASE_LOCAL ]-> lock )
2131
+ __releases (timer_bases [BASE_GLOBAL ]-> lock )
2132
+ {
2133
+ struct timer_base * base_local , * base_global ;
2134
+
2135
+ base_local = per_cpu_ptr (& timer_bases [BASE_LOCAL ], cpu );
2136
+ base_global = per_cpu_ptr (& timer_bases [BASE_GLOBAL ], cpu );
2137
+
2138
+ raw_spin_unlock (& base_global -> lock );
2139
+ raw_spin_unlock (& base_local -> lock );
2140
+ }
2141
+
2142
+ /**
2143
+ * timer_lock_remote_bases - lock timer bases of cpu
2144
+ * @cpu: Remote CPU
2145
+ *
2146
+ * Locks the remote timer bases.
2147
+ */
2148
+ void timer_lock_remote_bases (unsigned int cpu )
2149
+ __acquires (timer_bases [BASE_LOCAL ]-> lock )
2150
+ __acquires (timer_bases [BASE_GLOBAL ]-> lock )
2151
+ {
2152
+ struct timer_base * base_local , * base_global ;
2153
+
2154
+ base_local = per_cpu_ptr (& timer_bases [BASE_LOCAL ], cpu );
2155
+ base_global = per_cpu_ptr (& timer_bases [BASE_GLOBAL ], cpu );
2156
+
2157
+ lockdep_assert_irqs_disabled ();
2158
+
2159
+ raw_spin_lock (& base_local -> lock );
2160
+ raw_spin_lock_nested (& base_global -> lock , SINGLE_DEPTH_NESTING );
2161
+ }
2162
+ # endif /* CONFIG_SMP */
2163
+
2079
2164
static inline u64 __get_next_timer_interrupt (unsigned long basej , u64 basem ,
2080
2165
bool * idle )
2081
2166
{
0 commit comments