@@ -124,10 +124,11 @@ void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend,
124124 }
125125}
126126
127- static void __imsic_local_sync (struct imsic_local_priv * lpriv )
127+ static bool __imsic_local_sync (struct imsic_local_priv * lpriv )
128128{
129129 struct imsic_local_config * mlocal ;
130130 struct imsic_vector * vec , * mvec ;
131+ bool ret = true;
131132 int i ;
132133
133134 lockdep_assert_held (& lpriv -> lock );
@@ -143,35 +144,75 @@ static void __imsic_local_sync(struct imsic_local_priv *lpriv)
143144 __imsic_id_clear_enable (i );
144145
145146 /*
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.
150149 */
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 ) {
154172 if (__imsic_id_read_clear_pending (i )) {
155173 mlocal = per_cpu_ptr (imsic -> global .local , mvec -> cpu );
156174 writel_relaxed (mvec -> local_id , mlocal -> msi_va );
157175 }
158176
177+ WRITE_ONCE (vec -> move_next , NULL );
159178 imsic_vector_free (& lpriv -> vectors [i ]);
160179 }
161180
162181skip :
163182 bitmap_clear (lpriv -> dirty_bitmap , i , 1 );
164183 }
184+
185+ return ret ;
165186}
166187
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 )
168205{
169206 struct imsic_local_priv * lpriv = this_cpu_ptr (imsic -> lpriv );
170207 unsigned long flags ;
171208
172209 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+
175216 raw_spin_unlock_irqrestore (& lpriv -> lock , flags );
176217}
177218
@@ -190,12 +231,7 @@ void imsic_local_delivery(bool enable)
190231#ifdef CONFIG_SMP
191232static void imsic_local_timer_callback (struct timer_list * timer )
192233{
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);
199235}
200236
201237static 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
216252 */
217253 if (cpu_online (cpu )) {
218254 if (cpu == smp_processor_id ()) {
219- __imsic_local_sync (lpriv );
220- return ;
255+ if ( __imsic_local_sync (lpriv ))
256+ return ;
221257 }
222258
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 );
227260 }
228261}
229262#else
@@ -278,8 +311,9 @@ void imsic_vector_unmask(struct imsic_vector *vec)
278311 raw_spin_unlock (& lpriv -> lock );
279312}
280313
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 )
283317{
284318 unsigned long flags ;
285319 bool enabled ;
@@ -289,7 +323,10 @@ static bool imsic_vector_move_update(struct imsic_local_priv *lpriv, struct imsi
289323 /* Update enable and move details */
290324 enabled = READ_ONCE (vec -> enable );
291325 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 );
293330
294331 /* Mark the vector as dirty and synchronize */
295332 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
322359 * interrupt on the old vector while device was being moved
323360 * to the new vector.
324361 */
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 );
327364}
328365
329366#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
@@ -386,7 +423,8 @@ struct imsic_vector *imsic_vector_alloc(unsigned int hwirq, const struct cpumask
386423 vec = & lpriv -> vectors [local_id ];
387424 vec -> hwirq = hwirq ;
388425 vec -> enable = false;
389- vec -> move = NULL ;
426+ vec -> move_next = NULL ;
427+ vec -> move_prev = NULL ;
390428
391429 return vec ;
392430}
0 commit comments