Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0be275e3 authored by Jiang Liu's avatar Jiang Liu Committed by Thomas Gleixner
Browse files

x86/irq: Use cached IOAPIC entry instead of reading from hardware



Use cached IOAPIC entry instead of reading data from IOAPIC hardware
registers to improve performance.

Signed-off-by: default avatarJiang Liu <jiang.liu@linux.intel.com>
Tested-by: default avatarJoerg Roedel <jroedel@suse.de>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: David Cohen <david.a.cohen@linux.intel.com>
Cc: Sander Eikelenboom <linux@eikelenboom.it>
Cc: David Vrabel <david.vrabel@citrix.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dimitri Sivanich <sivanich@sgi.com>
Cc: Grant Likely <grant.likely@linaro.org>
Link: http://lkml.kernel.org/r/1428978610-28986-21-git-send-email-jiang.liu@linux.intel.com


Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 154d9e50
Loading
Loading
Loading
Loading
+21 −57
Original line number Diff line number Diff line
@@ -69,6 +69,11 @@
/*
 * Is the SiS APIC rmw bug present ?
 *      -1 = don't know, 0 = no, 1 = yes
 * When doing a read-modify-write operation on IOAPIC registers, older SiS APIC
 * requires we rewrite the index register again where the read already set up
 * the index register.
 * The code to make use of sis_apic_bug has been removed, but we don't want to
 * lose this knowledge.
 */
int sis_apic_bug = -1;

@@ -293,22 +298,6 @@ static void io_apic_write(unsigned int apic, unsigned int reg,
	writel(value, &io_apic->data);
}

/*
 * Re-write a value: to be used for read-modify-write
 * cycles where the read already set up the index register.
 *
 * Older SiS APIC requires we rewrite the index register
 */
static void io_apic_modify(unsigned int apic, unsigned int reg,
			   unsigned int value)
{
	struct io_apic __iomem *io_apic = io_apic_base(apic);

	if (sis_apic_bug)
		writel(reg, &io_apic->index);
	writel(value, &io_apic->data);
}

union entry_union {
	struct { u32 w1, w2; };
	struct IO_APIC_route_entry entry;
@@ -445,29 +434,23 @@ static void __init replace_pin_at_irq_node(struct mp_chip_data *data, int node,
	add_pin_to_irq_node(data, node, newapic, newpin);
}

static void __io_apic_modify_irq(struct irq_pin_list *entry,
static void io_apic_modify_irq(struct mp_chip_data *data,
			       int mask_and, int mask_or,
			       void (*final)(struct irq_pin_list *entry))
{
	unsigned int reg, pin;
	union entry_union eu;
	struct irq_pin_list *entry;

	pin = entry->pin;
	reg = io_apic_read(entry->apic, 0x10 + pin * 2);
	reg &= mask_and;
	reg |= mask_or;
	io_apic_modify(entry->apic, 0x10 + pin * 2, reg);
	eu.entry = data->entry;
	eu.w1 &= mask_and;
	eu.w1 |= mask_or;
	data->entry = eu.entry;

	for_each_irq_pin(entry, data->irq_2_pin) {
		io_apic_write(entry->apic, 0x10 + 2 * entry->pin, eu.w1);
		if (final)
			final(entry);
	}

static void io_apic_modify_irq(struct mp_chip_data *data,
			       int mask_and, int mask_or,
			       void (*final)(struct irq_pin_list *entry))
{
	struct irq_pin_list *entry;

	for_each_irq_pin(entry, data->irq_2_pin)
		__io_apic_modify_irq(entry, mask_and, mask_or, final);
}

static void io_apic_sync(struct irq_pin_list *entry)
@@ -1739,28 +1722,6 @@ static unsigned int startup_ioapic_irq(struct irq_data *data)
	return was_pending;
}

static void __target_IO_APIC_irq(unsigned int irq, struct irq_cfg *cfg,
				 struct mp_chip_data *data)
{
	int apic, pin;
	struct irq_pin_list *entry;
	u8 vector = cfg->vector;
	unsigned int dest = SET_APIC_LOGICAL_ID(cfg->dest_apicid);

	for_each_irq_pin(entry, data->irq_2_pin) {
		unsigned int reg;

		apic = entry->apic;
		pin = entry->pin;

		io_apic_write(apic, 0x11 + pin*2, dest);
		reg = io_apic_read(apic, 0x10 + pin*2);
		reg &= ~IO_APIC_REDIR_VECTOR_MASK;
		reg |= vector;
		io_apic_modify(apic, 0x10 + pin*2, reg);
	}
}

atomic_t irq_mis_count;

#ifdef CONFIG_GENERIC_PENDING_IRQ
@@ -1926,6 +1887,7 @@ static int ioapic_set_affinity(struct irq_data *irq_data,
{
	struct irq_data *parent = irq_data->parent_data;
	struct mp_chip_data *data = irq_data->chip_data;
	struct irq_pin_list *entry;
	struct irq_cfg *cfg;
	unsigned long flags;
	int ret;
@@ -1936,7 +1898,9 @@ static int ioapic_set_affinity(struct irq_data *irq_data,
		cfg = irqd_cfg(irq_data);
		data->entry.dest = cfg->dest_apicid;
		data->entry.vector = cfg->vector;
		__target_IO_APIC_irq(irq_data->irq, cfg, irq_data->chip_data);
		for_each_irq_pin(entry, data->irq_2_pin)
			__ioapic_write_entry(entry->apic, entry->pin,
					     data->entry);
	}
	raw_spin_unlock_irqrestore(&ioapic_lock, flags);