Skip to content

Commit

Permalink
Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/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()
  • Loading branch information
Linus Torvalds committed Sep 1, 2015
2 parents 17e6b00 + a47d457 commit 43af987
Show file tree
Hide file tree
Showing 18 changed files with 214 additions and 193 deletions.
6 changes: 3 additions & 3 deletions arch/x86/include/asm/hw_irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,10 @@ extern char irq_entries_start[];
#define trace_irq_entries_start irq_entries_start
#endif

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

typedef int vector_irq_t[NR_VECTORS];
typedef struct irq_desc* vector_irq_t[NR_VECTORS];
DECLARE_PER_CPU(vector_irq_t, vector_irq);

#endif /* !ASSEMBLY_ */
Expand Down
4 changes: 3 additions & 1 deletion arch/x86/include/asm/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void));

extern void (*x86_platform_ipi_callback)(void);
extern void native_init_IRQ(void);
extern bool handle_irq(unsigned irq, struct pt_regs *regs);

struct irq_desc;
extern bool handle_irq(struct irq_desc *desc, struct pt_regs *regs);

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

Expand Down
84 changes: 44 additions & 40 deletions arch/x86/kernel/apic/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -462,40 +462,40 @@ static int lapic_next_deadline(unsigned long delta,
return 0;
}

/*
* Setup the lapic timer in periodic or oneshot mode
*/
static void lapic_timer_setup(enum clock_event_mode mode,
struct clock_event_device *evt)
static int lapic_timer_shutdown(struct clock_event_device *evt)
{
unsigned long flags;
unsigned int v;

/* Lapic used as dummy for broadcast ? */
if (evt->features & CLOCK_EVT_FEAT_DUMMY)
return;
return 0;

local_irq_save(flags);
v = apic_read(APIC_LVTT);
v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
apic_write(APIC_LVTT, v);
apic_write(APIC_TMICT, 0);
return 0;
}

switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
case CLOCK_EVT_MODE_ONESHOT:
__setup_APIC_LVTT(lapic_timer_frequency,
mode != CLOCK_EVT_MODE_PERIODIC, 1);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
v = apic_read(APIC_LVTT);
v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
apic_write(APIC_LVTT, v);
apic_write(APIC_TMICT, 0);
break;
case CLOCK_EVT_MODE_RESUME:
/* Nothing to do here */
break;
}
static inline int
lapic_timer_set_periodic_oneshot(struct clock_event_device *evt, bool oneshot)
{
/* Lapic used as dummy for broadcast ? */
if (evt->features & CLOCK_EVT_FEAT_DUMMY)
return 0;

local_irq_restore(flags);
__setup_APIC_LVTT(lapic_timer_frequency, oneshot, 1);
return 0;
}

static int lapic_timer_set_periodic(struct clock_event_device *evt)
{
return lapic_timer_set_periodic_oneshot(evt, false);
}

static int lapic_timer_set_oneshot(struct clock_event_device *evt)
{
return lapic_timer_set_periodic_oneshot(evt, true);
}

/*
Expand All @@ -513,15 +513,18 @@ static void lapic_timer_broadcast(const struct cpumask *mask)
* The local apic timer can be used for any function which is CPU local.
*/
static struct clock_event_device lapic_clockevent = {
.name = "lapic",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
| CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
.shift = 32,
.set_mode = lapic_timer_setup,
.set_next_event = lapic_next_event,
.broadcast = lapic_timer_broadcast,
.rating = 100,
.irq = -1,
.name = "lapic",
.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP
| CLOCK_EVT_FEAT_DUMMY,
.shift = 32,
.set_state_shutdown = lapic_timer_shutdown,
.set_state_periodic = lapic_timer_set_periodic,
.set_state_oneshot = lapic_timer_set_oneshot,
.set_next_event = lapic_next_event,
.broadcast = lapic_timer_broadcast,
.rating = 100,
.irq = -1,
};
static DEFINE_PER_CPU(struct clock_event_device, lapic_events);

Expand Down Expand Up @@ -778,7 +781,7 @@ static int __init calibrate_APIC_clock(void)
* Setup the apic timer manually
*/
levt->event_handler = lapic_cal_handler;
lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
lapic_timer_set_periodic(levt);
lapic_cal_loops = -1;

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

/* Stop the lapic timer */
lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
local_irq_disable();
lapic_timer_shutdown(levt);

/* Jiffies delta */
deltaj = lapic_cal_j2 - lapic_cal_j1;
Expand All @@ -799,8 +803,8 @@ static int __init calibrate_APIC_clock(void)
apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
else
levt->features |= CLOCK_EVT_FEAT_DUMMY;
} else
local_irq_enable();
}
local_irq_enable();

if (levt->features & CLOCK_EVT_FEAT_DUMMY) {
pr_warning("APIC timer disabled due to verification failure\n");
Expand Down Expand Up @@ -878,7 +882,7 @@ static void local_apic_timer_interrupt(void)
if (!evt->event_handler) {
pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", cpu);
/* Switch it off */
lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
lapic_timer_shutdown(evt);
return;
}

Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/apic/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -2541,7 +2541,7 @@ void __init setup_ioapic_dest(void)
* Honour affinities which have been set in early boot
*/
if (!irqd_can_balance(idata) || irqd_affinity_was_set(idata))
mask = idata->affinity;
mask = irq_data_get_affinity_mask(idata);
else
mask = apic->target_cpus();

Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/apic/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ static inline int hpet_dev_id(struct irq_domain *domain)

static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
{
hpet_msi_write(data->handler_data, msg);
hpet_msi_write(irq_data_get_irq_handler_data(data), msg);
}

static struct irq_chip hpet_msi_controller = {
Expand Down
85 changes: 46 additions & 39 deletions arch/x86/kernel/apic/vector.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ static int __assign_irq_vector(int irq, struct apic_chip_data *d,
goto next;

for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) {
if (per_cpu(vector_irq, new_cpu)[vector] >
VECTOR_UNDEFINED)
if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector]))
goto next;
}
/* Found one! */
Expand All @@ -182,7 +181,7 @@ static int __assign_irq_vector(int irq, struct apic_chip_data *d,
cpumask_intersects(d->old_domain, cpu_online_mask);
}
for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask)
per_cpu(vector_irq, new_cpu)[vector] = irq;
per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq);
d->cfg.vector = vector;
cpumask_copy(d->domain, vector_cpumask);
err = 0;
Expand Down Expand Up @@ -224,15 +223,16 @@ static int assign_irq_vector_policy(int irq, int node,

static void clear_irq_vector(int irq, struct apic_chip_data *data)
{
int cpu, vector;
struct irq_desc *desc;
unsigned long flags;
int cpu, vector;

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

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

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

desc = irq_to_desc(irq);
for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
vector++) {
if (per_cpu(vector_irq, cpu)[vector] != irq)
if (per_cpu(vector_irq, cpu)[vector] != desc)
continue;
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
break;
}
}
Expand Down Expand Up @@ -296,7 +297,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
struct irq_alloc_info *info = arg;
struct apic_chip_data *data;
struct irq_data *irq_data;
int i, err;
int i, err, node;

if (disable_apic)
return -ENXIO;
Expand All @@ -308,12 +309,13 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
for (i = 0; i < nr_irqs; i++) {
irq_data = irq_domain_get_irq_data(domain, virq + i);
BUG_ON(!irq_data);
node = irq_data_get_node(irq_data);
#ifdef CONFIG_X86_IO_APIC
if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i])
data = legacy_irq_data[virq + i];
else
#endif
data = alloc_apic_chip_data(irq_data->node);
data = alloc_apic_chip_data(node);
if (!data) {
err = -ENOMEM;
goto error;
Expand All @@ -322,8 +324,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
irq_data->chip = &lapic_controller;
irq_data->chip_data = data;
irq_data->hwirq = virq + i;
err = assign_irq_vector_policy(virq + i, irq_data->node, data,
info);
err = assign_irq_vector_policy(virq + i, node, data, info);
if (err)
goto error;
}
Expand Down Expand Up @@ -403,32 +404,32 @@ int __init arch_early_irq_init(void)
return arch_early_ioapic_init();
}

/* Initialize vector_irq on a new cpu */
static void __setup_vector_irq(int cpu)
{
/* Initialize vector_irq on a new cpu */
int irq, vector;
struct apic_chip_data *data;
struct irq_desc *desc;
int irq, vector;

/* Mark the inuse vectors */
for_each_active_irq(irq) {
data = apic_chip_data(irq_get_irq_data(irq));
if (!data)
continue;
for_each_irq_desc(irq, desc) {
struct irq_data *idata = irq_desc_get_irq_data(desc);

if (!cpumask_test_cpu(cpu, data->domain))
data = apic_chip_data(idata);
if (!data || !cpumask_test_cpu(cpu, data->domain))
continue;
vector = data->cfg.vector;
per_cpu(vector_irq, cpu)[vector] = irq;
per_cpu(vector_irq, cpu)[vector] = desc;
}
/* Mark the free vectors */
for (vector = 0; vector < NR_VECTORS; ++vector) {
irq = per_cpu(vector_irq, cpu)[vector];
if (irq <= VECTOR_UNDEFINED)
desc = per_cpu(vector_irq, cpu)[vector];
if (IS_ERR_OR_NULL(desc))
continue;

data = apic_chip_data(irq_get_irq_data(irq));
data = apic_chip_data(irq_desc_get_irq_data(desc));
if (!cpumask_test_cpu(cpu, data->domain))
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
}
}

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

__setup_vector_irq(cpu);
}
Expand Down Expand Up @@ -490,7 +491,8 @@ static int apic_set_affinity(struct irq_data *irq_data,
if (err) {
struct irq_data *top = irq_get_irq_data(irq);

if (assign_irq_vector(irq, data, top->affinity))
if (assign_irq_vector(irq, data,
irq_data_get_affinity_mask(top)))
pr_err("Failed to recover vector for irq %d\n", irq);
return err;
}
Expand Down Expand Up @@ -538,27 +540,30 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)

entering_ack_irq();

/* Prevent vectors vanishing under us */
raw_spin_lock(&vector_lock);

me = smp_processor_id();
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
int irq;
unsigned int irr;
struct irq_desc *desc;
struct apic_chip_data *data;
struct irq_desc *desc;
unsigned int irr;

irq = __this_cpu_read(vector_irq[vector]);

if (irq <= VECTOR_UNDEFINED)
retry:
desc = __this_cpu_read(vector_irq[vector]);
if (IS_ERR_OR_NULL(desc))
continue;

desc = irq_to_desc(irq);
if (!desc)
continue;
if (!raw_spin_trylock(&desc->lock)) {
raw_spin_unlock(&vector_lock);
cpu_relax();
raw_spin_lock(&vector_lock);
goto retry;
}

data = apic_chip_data(&desc->irq_data);
data = apic_chip_data(irq_desc_get_irq_data(desc));
if (!data)
continue;

raw_spin_lock(&desc->lock);
goto unlock;

/*
* Check if the irq migration is in progress. If so, we
Expand All @@ -583,11 +588,13 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
goto unlock;
}
__this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
__this_cpu_write(vector_irq[vector], VECTOR_UNUSED);
unlock:
raw_spin_unlock(&desc->lock);
}

raw_spin_unlock(&vector_lock);

exiting_irq();
}

Expand Down
Loading

0 comments on commit 43af987

Please sign in to comment.