Skip to content

Commit acaa21a

Browse files
committed
Merge tag 'x86_urgent_for_v6.17_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Borislav Petkov: - Fix an interrupt vector setup race which leads to a non-functioning device - Add new Intel CPU models *and* a family: 0x12. Finally. Yippie! :-) * tag 'x86_urgent_for_v6.17_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/irq: Plug vector setup race x86/cpu: Add new Intel CPU model numbers for Wildcatlake and Novalake
2 parents 8e8f6b6 + ce0b5ee commit acaa21a

File tree

3 files changed

+60
-20
lines changed

3 files changed

+60
-20
lines changed

arch/x86/include/asm/hw_irq.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,23 @@ struct irq_cfg {
9292

9393
extern struct irq_cfg *irq_cfg(unsigned int irq);
9494
extern struct irq_cfg *irqd_cfg(struct irq_data *irq_data);
95-
extern void lock_vector_lock(void);
96-
extern void unlock_vector_lock(void);
9795
#ifdef CONFIG_SMP
9896
extern void vector_schedule_cleanup(struct irq_cfg *);
9997
extern void irq_complete_move(struct irq_cfg *cfg);
10098
#else
10199
static inline void vector_schedule_cleanup(struct irq_cfg *c) { }
102100
static inline void irq_complete_move(struct irq_cfg *c) { }
103101
#endif
104-
105102
extern void apic_ack_edge(struct irq_data *data);
106-
#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
103+
#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
104+
105+
#ifdef CONFIG_X86_LOCAL_APIC
106+
extern void lock_vector_lock(void);
107+
extern void unlock_vector_lock(void);
108+
#else
107109
static inline void lock_vector_lock(void) {}
108110
static inline void unlock_vector_lock(void) {}
109-
#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
111+
#endif
110112

111113
/* Statistics */
112114
extern atomic_t irq_err_count;

arch/x86/include/asm/intel-family.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@
150150

151151
#define INTEL_PANTHERLAKE_L IFM(6, 0xCC) /* Cougar Cove / Crestmont */
152152

153+
#define INTEL_WILDCATLAKE_L IFM(6, 0xD5)
154+
155+
#define INTEL_NOVALAKE IFM(18, 0x01)
156+
#define INTEL_NOVALAKE_L IFM(18, 0x03)
157+
153158
/* "Small Core" Processors (Atom/E-Core) */
154159

155160
#define INTEL_ATOM_BONNELL IFM(6, 0x1C) /* Diamondville, Pineview */

arch/x86/kernel/irq.c

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -256,26 +256,59 @@ static __always_inline void handle_irq(struct irq_desc *desc,
256256
__handle_irq(desc, regs);
257257
}
258258

259-
static __always_inline int call_irq_handler(int vector, struct pt_regs *regs)
259+
static struct irq_desc *reevaluate_vector(int vector)
260260
{
261-
struct irq_desc *desc;
262-
int ret = 0;
261+
struct irq_desc *desc = __this_cpu_read(vector_irq[vector]);
262+
263+
if (!IS_ERR_OR_NULL(desc))
264+
return desc;
265+
266+
if (desc == VECTOR_UNUSED)
267+
pr_emerg_ratelimited("No irq handler for %d.%u\n", smp_processor_id(), vector);
268+
else
269+
__this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
270+
return NULL;
271+
}
272+
273+
static __always_inline bool call_irq_handler(int vector, struct pt_regs *regs)
274+
{
275+
struct irq_desc *desc = __this_cpu_read(vector_irq[vector]);
263276

264-
desc = __this_cpu_read(vector_irq[vector]);
265277
if (likely(!IS_ERR_OR_NULL(desc))) {
266278
handle_irq(desc, regs);
267-
} else {
268-
ret = -EINVAL;
269-
if (desc == VECTOR_UNUSED) {
270-
pr_emerg_ratelimited("%s: %d.%u No irq handler for vector\n",
271-
__func__, smp_processor_id(),
272-
vector);
273-
} else {
274-
__this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
275-
}
279+
return true;
276280
}
277281

278-
return ret;
282+
/*
283+
* Reevaluate with vector_lock held to prevent a race against
284+
* request_irq() setting up the vector:
285+
*
286+
* CPU0 CPU1
287+
* interrupt is raised in APIC IRR
288+
* but not handled
289+
* free_irq()
290+
* per_cpu(vector_irq, CPU1)[vector] = VECTOR_SHUTDOWN;
291+
*
292+
* request_irq() common_interrupt()
293+
* d = this_cpu_read(vector_irq[vector]);
294+
*
295+
* per_cpu(vector_irq, CPU1)[vector] = desc;
296+
*
297+
* if (d == VECTOR_SHUTDOWN)
298+
* this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
299+
*
300+
* This requires that the same vector on the same target CPU is
301+
* handed out or that a spurious interrupt hits that CPU/vector.
302+
*/
303+
lock_vector_lock();
304+
desc = reevaluate_vector(vector);
305+
unlock_vector_lock();
306+
307+
if (!desc)
308+
return false;
309+
310+
handle_irq(desc, regs);
311+
return true;
279312
}
280313

281314
/*
@@ -289,7 +322,7 @@ DEFINE_IDTENTRY_IRQ(common_interrupt)
289322
/* entry code tells RCU that we're not quiescent. Check it. */
290323
RCU_LOCKDEP_WARN(!rcu_is_watching(), "IRQ failed to wake up RCU");
291324

292-
if (unlikely(call_irq_handler(vector, regs)))
325+
if (unlikely(!call_irq_handler(vector, regs)))
293326
apic_eoi();
294327

295328
set_irq_regs(old_regs);

0 commit comments

Comments
 (0)