Skip to content

Commit 43af987

Browse files
committed
Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 apic updates from Thomas Gleixner: "This udpate contains: - rework the irq vector array to store a pointer to the irq descriptor instead of the irq number to avoid a lookup of the irq descriptor in the irq entry path - lguest interrupt handling cleanups - conversion of the local apic timer to the new clockevent callbacks - preparatory changes for the irq argument removal of interrupt flow handlers" * 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/irq: Do not dereference irq descriptor before checking it tools/lguest: Clean up include dir tools/lguest: Fix redefinition of struct virtio_pci_cfg_cap x86/irq: Store irq descriptor in vector array genirq: Provide irq_desc_has_action x86/irq: Get rid of an indentation level x86/irq: Rename VECTOR_UNDEFINED to VECTOR_UNUSED x86/irq: Replace numeric constant x86/irq: Protect smp_cleanup_move x86/lguest: Do not setup unused irq vectors x86/lguest: Clean up lguest_setup_irq x86/apic: Drop local_irq_save/restore in timer callbacks x86/apic: Migrate apic timer to new set_state interface x86/irq: Use access helper irq_data_get_affinity_mask() x86/irq: Use accessor irq_data_get_irq_handler_data() x86/irq: Use accessor irq_data_get_node()
2 parents 17e6b00 + a47d457 commit 43af987

File tree

18 files changed

+214
-193
lines changed

18 files changed

+214
-193
lines changed

arch/x86/include/asm/hw_irq.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,10 @@ extern char irq_entries_start[];
182182
#define trace_irq_entries_start irq_entries_start
183183
#endif
184184

185-
#define VECTOR_UNDEFINED (-1)
186-
#define VECTOR_RETRIGGERED (-2)
185+
#define VECTOR_UNUSED NULL
186+
#define VECTOR_RETRIGGERED ((void *)~0UL)
187187

188-
typedef int vector_irq_t[NR_VECTORS];
188+
typedef struct irq_desc* vector_irq_t[NR_VECTORS];
189189
DECLARE_PER_CPU(vector_irq_t, vector_irq);
190190

191191
#endif /* !ASSEMBLY_ */

arch/x86/include/asm/irq.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void));
3636

3737
extern void (*x86_platform_ipi_callback)(void);
3838
extern void native_init_IRQ(void);
39-
extern bool handle_irq(unsigned irq, struct pt_regs *regs);
39+
40+
struct irq_desc;
41+
extern bool handle_irq(struct irq_desc *desc, struct pt_regs *regs);
4042

4143
extern __visible unsigned int do_IRQ(struct pt_regs *regs);
4244

arch/x86/kernel/apic/apic.c

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -462,40 +462,40 @@ static int lapic_next_deadline(unsigned long delta,
462462
return 0;
463463
}
464464

465-
/*
466-
* Setup the lapic timer in periodic or oneshot mode
467-
*/
468-
static void lapic_timer_setup(enum clock_event_mode mode,
469-
struct clock_event_device *evt)
465+
static int lapic_timer_shutdown(struct clock_event_device *evt)
470466
{
471-
unsigned long flags;
472467
unsigned int v;
473468

474469
/* Lapic used as dummy for broadcast ? */
475470
if (evt->features & CLOCK_EVT_FEAT_DUMMY)
476-
return;
471+
return 0;
477472

478-
local_irq_save(flags);
473+
v = apic_read(APIC_LVTT);
474+
v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
475+
apic_write(APIC_LVTT, v);
476+
apic_write(APIC_TMICT, 0);
477+
return 0;
478+
}
479479

480-
switch (mode) {
481-
case CLOCK_EVT_MODE_PERIODIC:
482-
case CLOCK_EVT_MODE_ONESHOT:
483-
__setup_APIC_LVTT(lapic_timer_frequency,
484-
mode != CLOCK_EVT_MODE_PERIODIC, 1);
485-
break;
486-
case CLOCK_EVT_MODE_UNUSED:
487-
case CLOCK_EVT_MODE_SHUTDOWN:
488-
v = apic_read(APIC_LVTT);
489-
v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
490-
apic_write(APIC_LVTT, v);
491-
apic_write(APIC_TMICT, 0);
492-
break;
493-
case CLOCK_EVT_MODE_RESUME:
494-
/* Nothing to do here */
495-
break;
496-
}
480+
static inline int
481+
lapic_timer_set_periodic_oneshot(struct clock_event_device *evt, bool oneshot)
482+
{
483+
/* Lapic used as dummy for broadcast ? */
484+
if (evt->features & CLOCK_EVT_FEAT_DUMMY)
485+
return 0;
497486

498-
local_irq_restore(flags);
487+
__setup_APIC_LVTT(lapic_timer_frequency, oneshot, 1);
488+
return 0;
489+
}
490+
491+
static int lapic_timer_set_periodic(struct clock_event_device *evt)
492+
{
493+
return lapic_timer_set_periodic_oneshot(evt, false);
494+
}
495+
496+
static int lapic_timer_set_oneshot(struct clock_event_device *evt)
497+
{
498+
return lapic_timer_set_periodic_oneshot(evt, true);
499499
}
500500

501501
/*
@@ -513,15 +513,18 @@ static void lapic_timer_broadcast(const struct cpumask *mask)
513513
* The local apic timer can be used for any function which is CPU local.
514514
*/
515515
static struct clock_event_device lapic_clockevent = {
516-
.name = "lapic",
517-
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
518-
| CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
519-
.shift = 32,
520-
.set_mode = lapic_timer_setup,
521-
.set_next_event = lapic_next_event,
522-
.broadcast = lapic_timer_broadcast,
523-
.rating = 100,
524-
.irq = -1,
516+
.name = "lapic",
517+
.features = CLOCK_EVT_FEAT_PERIODIC |
518+
CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP
519+
| CLOCK_EVT_FEAT_DUMMY,
520+
.shift = 32,
521+
.set_state_shutdown = lapic_timer_shutdown,
522+
.set_state_periodic = lapic_timer_set_periodic,
523+
.set_state_oneshot = lapic_timer_set_oneshot,
524+
.set_next_event = lapic_next_event,
525+
.broadcast = lapic_timer_broadcast,
526+
.rating = 100,
527+
.irq = -1,
525528
};
526529
static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
527530

@@ -778,7 +781,7 @@ static int __init calibrate_APIC_clock(void)
778781
* Setup the apic timer manually
779782
*/
780783
levt->event_handler = lapic_cal_handler;
781-
lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
784+
lapic_timer_set_periodic(levt);
782785
lapic_cal_loops = -1;
783786

784787
/* Let the interrupts run */
@@ -788,7 +791,8 @@ static int __init calibrate_APIC_clock(void)
788791
cpu_relax();
789792

790793
/* Stop the lapic timer */
791-
lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
794+
local_irq_disable();
795+
lapic_timer_shutdown(levt);
792796

793797
/* Jiffies delta */
794798
deltaj = lapic_cal_j2 - lapic_cal_j1;
@@ -799,8 +803,8 @@ static int __init calibrate_APIC_clock(void)
799803
apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
800804
else
801805
levt->features |= CLOCK_EVT_FEAT_DUMMY;
802-
} else
803-
local_irq_enable();
806+
}
807+
local_irq_enable();
804808

805809
if (levt->features & CLOCK_EVT_FEAT_DUMMY) {
806810
pr_warning("APIC timer disabled due to verification failure\n");
@@ -878,7 +882,7 @@ static void local_apic_timer_interrupt(void)
878882
if (!evt->event_handler) {
879883
pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", cpu);
880884
/* Switch it off */
881-
lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
885+
lapic_timer_shutdown(evt);
882886
return;
883887
}
884888

arch/x86/kernel/apic/io_apic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2541,7 +2541,7 @@ void __init setup_ioapic_dest(void)
25412541
* Honour affinities which have been set in early boot
25422542
*/
25432543
if (!irqd_can_balance(idata) || irqd_affinity_was_set(idata))
2544-
mask = idata->affinity;
2544+
mask = irq_data_get_affinity_mask(idata);
25452545
else
25462546
mask = apic->target_cpus();
25472547

arch/x86/kernel/apic/msi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ static inline int hpet_dev_id(struct irq_domain *domain)
264264

265265
static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
266266
{
267-
hpet_msi_write(data->handler_data, msg);
267+
hpet_msi_write(irq_data_get_irq_handler_data(data), msg);
268268
}
269269

270270
static struct irq_chip hpet_msi_controller = {

arch/x86/kernel/apic/vector.c

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,7 @@ static int __assign_irq_vector(int irq, struct apic_chip_data *d,
169169
goto next;
170170

171171
for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) {
172-
if (per_cpu(vector_irq, new_cpu)[vector] >
173-
VECTOR_UNDEFINED)
172+
if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector]))
174173
goto next;
175174
}
176175
/* Found one! */
@@ -182,7 +181,7 @@ static int __assign_irq_vector(int irq, struct apic_chip_data *d,
182181
cpumask_intersects(d->old_domain, cpu_online_mask);
183182
}
184183
for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask)
185-
per_cpu(vector_irq, new_cpu)[vector] = irq;
184+
per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq);
186185
d->cfg.vector = vector;
187186
cpumask_copy(d->domain, vector_cpumask);
188187
err = 0;
@@ -224,15 +223,16 @@ static int assign_irq_vector_policy(int irq, int node,
224223

225224
static void clear_irq_vector(int irq, struct apic_chip_data *data)
226225
{
227-
int cpu, vector;
226+
struct irq_desc *desc;
228227
unsigned long flags;
228+
int cpu, vector;
229229

230230
raw_spin_lock_irqsave(&vector_lock, flags);
231231
BUG_ON(!data->cfg.vector);
232232

233233
vector = data->cfg.vector;
234234
for_each_cpu_and(cpu, data->domain, cpu_online_mask)
235-
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
235+
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
236236

237237
data->cfg.vector = 0;
238238
cpumask_clear(data->domain);
@@ -242,12 +242,13 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data)
242242
return;
243243
}
244244

245+
desc = irq_to_desc(irq);
245246
for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
246247
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
247248
vector++) {
248-
if (per_cpu(vector_irq, cpu)[vector] != irq)
249+
if (per_cpu(vector_irq, cpu)[vector] != desc)
249250
continue;
250-
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
251+
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
251252
break;
252253
}
253254
}
@@ -296,7 +297,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
296297
struct irq_alloc_info *info = arg;
297298
struct apic_chip_data *data;
298299
struct irq_data *irq_data;
299-
int i, err;
300+
int i, err, node;
300301

301302
if (disable_apic)
302303
return -ENXIO;
@@ -308,12 +309,13 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
308309
for (i = 0; i < nr_irqs; i++) {
309310
irq_data = irq_domain_get_irq_data(domain, virq + i);
310311
BUG_ON(!irq_data);
312+
node = irq_data_get_node(irq_data);
311313
#ifdef CONFIG_X86_IO_APIC
312314
if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i])
313315
data = legacy_irq_data[virq + i];
314316
else
315317
#endif
316-
data = alloc_apic_chip_data(irq_data->node);
318+
data = alloc_apic_chip_data(node);
317319
if (!data) {
318320
err = -ENOMEM;
319321
goto error;
@@ -322,8 +324,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
322324
irq_data->chip = &lapic_controller;
323325
irq_data->chip_data = data;
324326
irq_data->hwirq = virq + i;
325-
err = assign_irq_vector_policy(virq + i, irq_data->node, data,
326-
info);
327+
err = assign_irq_vector_policy(virq + i, node, data, info);
327328
if (err)
328329
goto error;
329330
}
@@ -403,32 +404,32 @@ int __init arch_early_irq_init(void)
403404
return arch_early_ioapic_init();
404405
}
405406

407+
/* Initialize vector_irq on a new cpu */
406408
static void __setup_vector_irq(int cpu)
407409
{
408-
/* Initialize vector_irq on a new cpu */
409-
int irq, vector;
410410
struct apic_chip_data *data;
411+
struct irq_desc *desc;
412+
int irq, vector;
411413

412414
/* Mark the inuse vectors */
413-
for_each_active_irq(irq) {
414-
data = apic_chip_data(irq_get_irq_data(irq));
415-
if (!data)
416-
continue;
415+
for_each_irq_desc(irq, desc) {
416+
struct irq_data *idata = irq_desc_get_irq_data(desc);
417417

418-
if (!cpumask_test_cpu(cpu, data->domain))
418+
data = apic_chip_data(idata);
419+
if (!data || !cpumask_test_cpu(cpu, data->domain))
419420
continue;
420421
vector = data->cfg.vector;
421-
per_cpu(vector_irq, cpu)[vector] = irq;
422+
per_cpu(vector_irq, cpu)[vector] = desc;
422423
}
423424
/* Mark the free vectors */
424425
for (vector = 0; vector < NR_VECTORS; ++vector) {
425-
irq = per_cpu(vector_irq, cpu)[vector];
426-
if (irq <= VECTOR_UNDEFINED)
426+
desc = per_cpu(vector_irq, cpu)[vector];
427+
if (IS_ERR_OR_NULL(desc))
427428
continue;
428429

429-
data = apic_chip_data(irq_get_irq_data(irq));
430+
data = apic_chip_data(irq_desc_get_irq_data(desc));
430431
if (!cpumask_test_cpu(cpu, data->domain))
431-
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
432+
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
432433
}
433434
}
434435

@@ -448,7 +449,7 @@ void setup_vector_irq(int cpu)
448449
* legacy vector to irq mapping:
449450
*/
450451
for (irq = 0; irq < nr_legacy_irqs(); irq++)
451-
per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq;
452+
per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq_to_desc(irq);
452453

453454
__setup_vector_irq(cpu);
454455
}
@@ -490,7 +491,8 @@ static int apic_set_affinity(struct irq_data *irq_data,
490491
if (err) {
491492
struct irq_data *top = irq_get_irq_data(irq);
492493

493-
if (assign_irq_vector(irq, data, top->affinity))
494+
if (assign_irq_vector(irq, data,
495+
irq_data_get_affinity_mask(top)))
494496
pr_err("Failed to recover vector for irq %d\n", irq);
495497
return err;
496498
}
@@ -538,27 +540,30 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
538540

539541
entering_ack_irq();
540542

543+
/* Prevent vectors vanishing under us */
544+
raw_spin_lock(&vector_lock);
545+
541546
me = smp_processor_id();
542547
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
543-
int irq;
544-
unsigned int irr;
545-
struct irq_desc *desc;
546548
struct apic_chip_data *data;
549+
struct irq_desc *desc;
550+
unsigned int irr;
547551

548-
irq = __this_cpu_read(vector_irq[vector]);
549-
550-
if (irq <= VECTOR_UNDEFINED)
552+
retry:
553+
desc = __this_cpu_read(vector_irq[vector]);
554+
if (IS_ERR_OR_NULL(desc))
551555
continue;
552556

553-
desc = irq_to_desc(irq);
554-
if (!desc)
555-
continue;
557+
if (!raw_spin_trylock(&desc->lock)) {
558+
raw_spin_unlock(&vector_lock);
559+
cpu_relax();
560+
raw_spin_lock(&vector_lock);
561+
goto retry;
562+
}
556563

557-
data = apic_chip_data(&desc->irq_data);
564+
data = apic_chip_data(irq_desc_get_irq_data(desc));
558565
if (!data)
559-
continue;
560-
561-
raw_spin_lock(&desc->lock);
566+
goto unlock;
562567

563568
/*
564569
* Check if the irq migration is in progress. If so, we
@@ -583,11 +588,13 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
583588
apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
584589
goto unlock;
585590
}
586-
__this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
591+
__this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
587592
unlock:
588593
raw_spin_unlock(&desc->lock);
589594
}
590595

596+
raw_spin_unlock(&vector_lock);
597+
591598
exiting_irq();
592599
}
593600

0 commit comments

Comments
 (0)