Skip to content

Commit 0f67911

Browse files
avpatelKAGA-KOKO
authored andcommitted
irqchip/riscv-imsic: Separate next and previous pointers in IMSIC vector
Currently, there is only one "move" pointer in struct imsic_vector so during vector movement the old vector points to the new vector and new vector points to itself. To support forced cleanup of the old vector, add separate "move_next" and "move_prev" pointers to struct imsic_vector, where during vector movement the "move_next" pointer of the old vector points to the new vector and the "move_prev" pointer of the new vector points to the old vector. Both "move_next" and "move_prev" pointers are cleared separately by __imsic_local_sync() with a restriction that "move_prev" on the new CPU is cleared only after the old CPU has cleared "move_next". Signed-off-by: Anup Patel <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent 58d868b commit 0f67911

File tree

3 files changed

+78
-33
lines changed

3 files changed

+78
-33
lines changed

drivers/irqchip/irq-riscv-imsic-early.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ static void imsic_handle_irq(struct irq_desc *desc)
7777
struct imsic_vector *vec;
7878
unsigned long local_id;
7979

80+
/*
81+
* Process pending local synchronization instead of waiting
82+
* for per-CPU local timer to expire.
83+
*/
84+
imsic_local_sync_all(false);
85+
8086
chained_irq_enter(chip, desc);
8187

8288
while ((local_id = csr_swap(CSR_TOPEI, 0))) {
@@ -120,7 +126,7 @@ static int imsic_starting_cpu(unsigned int cpu)
120126
* Interrupts identities might have been enabled/disabled while
121127
* this CPU was not running so sync-up local enable/disable state.
122128
*/
123-
imsic_local_sync_all();
129+
imsic_local_sync_all(true);
124130

125131
/* Enable local interrupt delivery */
126132
imsic_local_delivery(true);

drivers/irqchip/irq-riscv-imsic-state.c

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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

162181
skip:
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
191232
static 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

201237
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
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
}

drivers/irqchip/irq-riscv-imsic-state.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ struct imsic_vector {
2323
unsigned int hwirq;
2424
/* Details accessed using local lock held */
2525
bool enable;
26-
struct imsic_vector *move;
26+
struct imsic_vector *move_next;
27+
struct imsic_vector *move_prev;
2728
};
2829

2930
struct imsic_local_priv {
@@ -74,7 +75,7 @@ static inline void __imsic_id_clear_enable(unsigned long id)
7475
__imsic_eix_update(id, 1, false, false);
7576
}
7677

77-
void imsic_local_sync_all(void);
78+
void imsic_local_sync_all(bool force_all);
7879
void imsic_local_delivery(bool enable);
7980

8081
void imsic_vector_mask(struct imsic_vector *vec);
@@ -87,7 +88,7 @@ static inline bool imsic_vector_isenabled(struct imsic_vector *vec)
8788

8889
static inline struct imsic_vector *imsic_vector_get_move(struct imsic_vector *vec)
8990
{
90-
return READ_ONCE(vec->move);
91+
return READ_ONCE(vec->move_prev);
9192
}
9293

9394
void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_vec);

0 commit comments

Comments
 (0)