@@ -124,10 +124,11 @@ void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend,
124
124
}
125
125
}
126
126
127
- static void __imsic_local_sync (struct imsic_local_priv * lpriv )
127
+ static bool __imsic_local_sync (struct imsic_local_priv * lpriv )
128
128
{
129
129
struct imsic_local_config * mlocal ;
130
130
struct imsic_vector * vec , * mvec ;
131
+ bool ret = true;
131
132
int i ;
132
133
133
134
lockdep_assert_held (& lpriv -> lock );
@@ -143,35 +144,75 @@ static void __imsic_local_sync(struct imsic_local_priv *lpriv)
143
144
__imsic_id_clear_enable (i );
144
145
145
146
/*
146
- * If the ID was being moved to a new ID on some other CPU
147
- * then we can get a MSI during the movement so check the
148
- * ID pending bit and re-trigger the new ID on other CPU
149
- * using MMIO write.
147
+ * Clear the previous vector pointer of the new vector only
148
+ * after the movement is complete on the old CPU.
150
149
*/
151
- mvec = READ_ONCE (vec -> move );
152
- WRITE_ONCE (vec -> move , NULL );
153
- if (mvec && mvec != vec ) {
150
+ mvec = READ_ONCE (vec -> move_prev );
151
+ if (mvec ) {
152
+ /*
153
+ * If the old vector has not been updated then
154
+ * try again in the next sync-up call.
155
+ */
156
+ if (READ_ONCE (mvec -> move_next )) {
157
+ ret = false;
158
+ continue ;
159
+ }
160
+
161
+ WRITE_ONCE (vec -> move_prev , NULL );
162
+ }
163
+
164
+ /*
165
+ * If a vector was being moved to a new vector on some other
166
+ * CPU then we can get a MSI during the movement so check the
167
+ * ID pending bit and re-trigger the new ID on other CPU using
168
+ * MMIO write.
169
+ */
170
+ mvec = READ_ONCE (vec -> move_next );
171
+ if (mvec ) {
154
172
if (__imsic_id_read_clear_pending (i )) {
155
173
mlocal = per_cpu_ptr (imsic -> global .local , mvec -> cpu );
156
174
writel_relaxed (mvec -> local_id , mlocal -> msi_va );
157
175
}
158
176
177
+ WRITE_ONCE (vec -> move_next , NULL );
159
178
imsic_vector_free (& lpriv -> vectors [i ]);
160
179
}
161
180
162
181
skip :
163
182
bitmap_clear (lpriv -> dirty_bitmap , i , 1 );
164
183
}
184
+
185
+ return ret ;
165
186
}
166
187
167
- void imsic_local_sync_all (void )
188
+ #ifdef CONFIG_SMP
189
+ static void __imsic_local_timer_start (struct imsic_local_priv * lpriv )
190
+ {
191
+ lockdep_assert_held (& lpriv -> lock );
192
+
193
+ if (!timer_pending (& lpriv -> timer )) {
194
+ lpriv -> timer .expires = jiffies + 1 ;
195
+ add_timer_on (& lpriv -> timer , smp_processor_id ());
196
+ }
197
+ }
198
+ #else
199
+ static inline void __imsic_local_timer_start (struct imsic_local_priv * lpriv )
200
+ {
201
+ }
202
+ #endif
203
+
204
+ void imsic_local_sync_all (bool force_all )
168
205
{
169
206
struct imsic_local_priv * lpriv = this_cpu_ptr (imsic -> lpriv );
170
207
unsigned long flags ;
171
208
172
209
raw_spin_lock_irqsave (& lpriv -> lock , flags );
173
- bitmap_fill (lpriv -> dirty_bitmap , imsic -> global .nr_ids + 1 );
174
- __imsic_local_sync (lpriv );
210
+
211
+ if (force_all )
212
+ bitmap_fill (lpriv -> dirty_bitmap , imsic -> global .nr_ids + 1 );
213
+ if (!__imsic_local_sync (lpriv ))
214
+ __imsic_local_timer_start (lpriv );
215
+
175
216
raw_spin_unlock_irqrestore (& lpriv -> lock , flags );
176
217
}
177
218
@@ -190,12 +231,7 @@ void imsic_local_delivery(bool enable)
190
231
#ifdef CONFIG_SMP
191
232
static void imsic_local_timer_callback (struct timer_list * timer )
192
233
{
193
- struct imsic_local_priv * lpriv = this_cpu_ptr (imsic -> lpriv );
194
- unsigned long flags ;
195
-
196
- raw_spin_lock_irqsave (& lpriv -> lock , flags );
197
- __imsic_local_sync (lpriv );
198
- raw_spin_unlock_irqrestore (& lpriv -> lock , flags );
234
+ imsic_local_sync_all (false);
199
235
}
200
236
201
237
static void __imsic_remote_sync (struct imsic_local_priv * lpriv , unsigned int cpu )
@@ -216,14 +252,11 @@ static void __imsic_remote_sync(struct imsic_local_priv *lpriv, unsigned int cpu
216
252
*/
217
253
if (cpu_online (cpu )) {
218
254
if (cpu == smp_processor_id ()) {
219
- __imsic_local_sync (lpriv );
220
- return ;
255
+ if ( __imsic_local_sync (lpriv ))
256
+ return ;
221
257
}
222
258
223
- if (!timer_pending (& lpriv -> timer )) {
224
- lpriv -> timer .expires = jiffies + 1 ;
225
- add_timer_on (& lpriv -> timer , cpu );
226
- }
259
+ __imsic_local_timer_start (lpriv );
227
260
}
228
261
}
229
262
#else
@@ -278,8 +311,9 @@ void imsic_vector_unmask(struct imsic_vector *vec)
278
311
raw_spin_unlock (& lpriv -> lock );
279
312
}
280
313
281
- static bool imsic_vector_move_update (struct imsic_local_priv * lpriv , struct imsic_vector * vec ,
282
- bool new_enable , struct imsic_vector * new_move )
314
+ static bool imsic_vector_move_update (struct imsic_local_priv * lpriv ,
315
+ struct imsic_vector * vec , bool is_old_vec ,
316
+ bool new_enable , struct imsic_vector * move_vec )
283
317
{
284
318
unsigned long flags ;
285
319
bool enabled ;
@@ -289,7 +323,10 @@ static bool imsic_vector_move_update(struct imsic_local_priv *lpriv, struct imsi
289
323
/* Update enable and move details */
290
324
enabled = READ_ONCE (vec -> enable );
291
325
WRITE_ONCE (vec -> enable , new_enable );
292
- WRITE_ONCE (vec -> move , new_move );
326
+ if (is_old_vec )
327
+ WRITE_ONCE (vec -> move_next , move_vec );
328
+ else
329
+ WRITE_ONCE (vec -> move_prev , move_vec );
293
330
294
331
/* Mark the vector as dirty and synchronize */
295
332
bitmap_set (lpriv -> dirty_bitmap , vec -> local_id , 1 );
@@ -322,8 +359,8 @@ void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_ve
322
359
* interrupt on the old vector while device was being moved
323
360
* to the new vector.
324
361
*/
325
- enabled = imsic_vector_move_update (old_lpriv , old_vec , false, new_vec );
326
- imsic_vector_move_update (new_lpriv , new_vec , enabled , new_vec );
362
+ enabled = imsic_vector_move_update (old_lpriv , old_vec , true, false, new_vec );
363
+ imsic_vector_move_update (new_lpriv , new_vec , false, enabled , old_vec );
327
364
}
328
365
329
366
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
@@ -386,7 +423,8 @@ struct imsic_vector *imsic_vector_alloc(unsigned int hwirq, const struct cpumask
386
423
vec = & lpriv -> vectors [local_id ];
387
424
vec -> hwirq = hwirq ;
388
425
vec -> enable = false;
389
- vec -> move = NULL ;
426
+ vec -> move_next = NULL ;
427
+ vec -> move_prev = NULL ;
390
428
391
429
return vec ;
392
430
}
0 commit comments