Commit ccd8ec4a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86-irq-2021-08-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 PIRQ updates from Thomas Gleixner:
 "A set of updates to support port 0x22/0x23 based PCI configuration
  space which can be found on various ALi chipsets and is also available
  on older Intel systems which expose a PIRQ router.

  While the Intel support is more or less nostalgia, the ALi chips are
  still in use on popular embedded boards used for routers"

* tag 'x86-irq-2021-08-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86: Fix typo s/ECLR/ELCR/ for the PIC register
  x86: Avoid magic number with ELCR register accesses
  x86/PCI: Add support for the Intel 82426EX PIRQ router
  x86/PCI: Add support for the Intel 82374EB/82374SB (ESC) PIRQ router
  x86/PCI: Add support for the ALi M1487 (IBC) PIRQ router
  x86: Add support for 0x22/0x23 port I/O configuration space
parents 0a096f24 34739a28
...@@ -19,6 +19,8 @@ extern unsigned int cached_irq_mask; ...@@ -19,6 +19,8 @@ extern unsigned int cached_irq_mask;
#define PIC_MASTER_OCW3 PIC_MASTER_ISR #define PIC_MASTER_OCW3 PIC_MASTER_ISR
#define PIC_SLAVE_CMD 0xa0 #define PIC_SLAVE_CMD 0xa0
#define PIC_SLAVE_IMR 0xa1 #define PIC_SLAVE_IMR 0xa1
#define PIC_ELCR1 0x4d0
#define PIC_ELCR2 0x4d1
/* i8259A PIC related value */ /* i8259A PIC related value */
#define PIC_CASCADE_IR 2 #define PIC_CASCADE_IR 2
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Support for the configuration register space at port I/O locations
* 0x22 and 0x23 variously used by PC architectures, e.g. the MP Spec,
* Cyrix CPUs, numerous chipsets.
*/
#ifndef _ASM_X86_PC_CONF_REG_H
#define _ASM_X86_PC_CONF_REG_H
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#define PC_CONF_INDEX 0x22
#define PC_CONF_DATA 0x23
#define PC_CONF_MPS_IMCR 0x70
extern raw_spinlock_t pc_conf_lock;
static inline u8 pc_conf_get(u8 reg)
{
outb(reg, PC_CONF_INDEX);
return inb(PC_CONF_DATA);
}
static inline void pc_conf_set(u8 reg, u8 data)
{
outb(reg, PC_CONF_INDEX);
outb(data, PC_CONF_DATA);
}
#endif /* _ASM_X86_PC_CONF_REG_H */
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
* Access order is always 0x22 (=offset), 0x23 (=value) * Access order is always 0x22 (=offset), 0x23 (=value)
*/ */
#include <asm/pc-conf-reg.h>
static inline u8 getCx86(u8 reg) static inline u8 getCx86(u8 reg)
{ {
outb(reg, 0x22); return pc_conf_get(reg);
return inb(0x23);
} }
static inline void setCx86(u8 reg, u8 data) static inline void setCx86(u8 reg, u8 data)
{ {
outb(reg, 0x22); pc_conf_set(reg, data);
outb(data, 0x23);
} }
...@@ -558,10 +558,10 @@ acpi_parse_nmi_src(union acpi_subtable_headers * header, const unsigned long end ...@@ -558,10 +558,10 @@ acpi_parse_nmi_src(union acpi_subtable_headers * header, const unsigned long end
* If a PIC-mode SCI is not recognized or gives spurious IRQ7's * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
* it may require Edge Trigger -- use "acpi_sci=edge" * it may require Edge Trigger -- use "acpi_sci=edge"
* *
* Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers * Port 0x4d0-4d1 are ELCR1 and ELCR2, the Edge/Level Control Registers
* for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge.
* ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0) * ELCR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
* ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0) * ELCR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
*/ */
void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
...@@ -570,7 +570,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) ...@@ -570,7 +570,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
unsigned int old, new; unsigned int old, new;
/* Real old ELCR mask */ /* Real old ELCR mask */
old = inb(0x4d0) | (inb(0x4d1) << 8); old = inb(PIC_ELCR1) | (inb(PIC_ELCR2) << 8);
/* /*
* If we use ACPI to set PCI IRQs, then we should clear ELCR * If we use ACPI to set PCI IRQs, then we should clear ELCR
...@@ -596,8 +596,8 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) ...@@ -596,8 +596,8 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
return; return;
pr_warn("setting ELCR to %04x (from %04x)\n", new, old); pr_warn("setting ELCR to %04x (from %04x)\n", new, old);
outb(new, 0x4d0); outb(new, PIC_ELCR1);
outb(new >> 8, 0x4d1); outb(new >> 8, PIC_ELCR2);
} }
int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <asm/trace/irq_vectors.h> #include <asm/trace/irq_vectors.h>
#include <asm/irq_remapping.h> #include <asm/irq_remapping.h>
#include <asm/pc-conf-reg.h>
#include <asm/perf_event.h> #include <asm/perf_event.h>
#include <asm/x86_init.h> #include <asm/x86_init.h>
#include <linux/atomic.h> #include <linux/atomic.h>
...@@ -132,18 +133,14 @@ static int enabled_via_apicbase __ro_after_init; ...@@ -132,18 +133,14 @@ static int enabled_via_apicbase __ro_after_init;
*/ */
static inline void imcr_pic_to_apic(void) static inline void imcr_pic_to_apic(void)
{ {
/* select IMCR register */
outb(0x70, 0x22);
/* NMI and 8259 INTR go through APIC */ /* NMI and 8259 INTR go through APIC */
outb(0x01, 0x23); pc_conf_set(PC_CONF_MPS_IMCR, 0x01);
} }
static inline void imcr_apic_to_pic(void) static inline void imcr_apic_to_pic(void)
{ {
/* select IMCR register */
outb(0x70, 0x22);
/* NMI and 8259 INTR go directly to BSP */ /* NMI and 8259 INTR go directly to BSP */
outb(0x00, 0x23); pc_conf_set(PC_CONF_MPS_IMCR, 0x00);
} }
#endif #endif
......
...@@ -764,7 +764,7 @@ static bool irq_active_low(int idx) ...@@ -764,7 +764,7 @@ static bool irq_active_low(int idx)
static bool EISA_ELCR(unsigned int irq) static bool EISA_ELCR(unsigned int irq)
{ {
if (irq < nr_legacy_irqs()) { if (irq < nr_legacy_irqs()) {
unsigned int port = 0x4d0 + (irq >> 3); unsigned int port = PIC_ELCR1 + (irq >> 3);
return (inb(port) >> (irq & 7)) & 1; return (inb(port) >> (irq & 7)) & 1;
} }
apic_printk(APIC_VERBOSE, KERN_INFO apic_printk(APIC_VERBOSE, KERN_INFO
......
...@@ -1299,7 +1299,7 @@ static void __init print_PIC(void) ...@@ -1299,7 +1299,7 @@ static void __init print_PIC(void)
pr_debug("... PIC ISR: %04x\n", v); pr_debug("... PIC ISR: %04x\n", v);
v = inb(0x4d1) << 8 | inb(0x4d0); v = inb(PIC_ELCR2) << 8 | inb(PIC_ELCR1);
pr_debug("... PIC ELCR: %04x\n", v); pr_debug("... PIC ELCR: %04x\n", v);
} }
......
...@@ -235,15 +235,15 @@ static char irq_trigger[2]; ...@@ -235,15 +235,15 @@ static char irq_trigger[2];
*/ */
static void restore_ELCR(char *trigger) static void restore_ELCR(char *trigger)
{ {
outb(trigger[0], 0x4d0); outb(trigger[0], PIC_ELCR1);
outb(trigger[1], 0x4d1); outb(trigger[1], PIC_ELCR2);
} }
static void save_ELCR(char *trigger) static void save_ELCR(char *trigger)
{ {
/* IRQ 0,1,2,8,13 are marked as reserved */ /* IRQ 0,1,2,8,13 are marked as reserved */
trigger[0] = inb(0x4d0) & 0xF8; trigger[0] = inb(PIC_ELCR1) & 0xF8;
trigger[1] = inb(0x4d1) & 0xDE; trigger[1] = inb(PIC_ELCR2) & 0xDE;
} }
static void i8259A_resume(void) static void i8259A_resume(void)
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/i8259.h>
#include <asm/io_apic.h> #include <asm/io_apic.h>
#include <asm/acpi.h> #include <asm/acpi.h>
#include <asm/irqdomain.h> #include <asm/irqdomain.h>
...@@ -251,7 +252,7 @@ static int __init ELCR_trigger(unsigned int irq) ...@@ -251,7 +252,7 @@ static int __init ELCR_trigger(unsigned int irq)
{ {
unsigned int port; unsigned int port;
port = 0x4d0 + (irq >> 3); port = PIC_ELCR1 + (irq >> 3);
return (inb(port) >> (irq & 7)) & 1; return (inb(port) >> (irq & 7)) & 1;
} }
......
...@@ -541,17 +541,17 @@ static int picdev_slave_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, ...@@ -541,17 +541,17 @@ static int picdev_slave_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
addr, len, val); addr, len, val);
} }
static int picdev_eclr_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, static int picdev_elcr_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
gpa_t addr, int len, const void *val) gpa_t addr, int len, const void *val)
{ {
return picdev_write(container_of(dev, struct kvm_pic, dev_eclr), return picdev_write(container_of(dev, struct kvm_pic, dev_elcr),
addr, len, val); addr, len, val);
} }
static int picdev_eclr_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, static int picdev_elcr_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
gpa_t addr, int len, void *val) gpa_t addr, int len, void *val)
{ {
return picdev_read(container_of(dev, struct kvm_pic, dev_eclr), return picdev_read(container_of(dev, struct kvm_pic, dev_elcr),
addr, len, val); addr, len, val);
} }
...@@ -577,9 +577,9 @@ static const struct kvm_io_device_ops picdev_slave_ops = { ...@@ -577,9 +577,9 @@ static const struct kvm_io_device_ops picdev_slave_ops = {
.write = picdev_slave_write, .write = picdev_slave_write,
}; };
static const struct kvm_io_device_ops picdev_eclr_ops = { static const struct kvm_io_device_ops picdev_elcr_ops = {
.read = picdev_eclr_read, .read = picdev_elcr_read,
.write = picdev_eclr_write, .write = picdev_elcr_write,
}; };
int kvm_pic_init(struct kvm *kvm) int kvm_pic_init(struct kvm *kvm)
...@@ -602,7 +602,7 @@ int kvm_pic_init(struct kvm *kvm) ...@@ -602,7 +602,7 @@ int kvm_pic_init(struct kvm *kvm)
*/ */
kvm_iodevice_init(&s->dev_master, &picdev_master_ops); kvm_iodevice_init(&s->dev_master, &picdev_master_ops);
kvm_iodevice_init(&s->dev_slave, &picdev_slave_ops); kvm_iodevice_init(&s->dev_slave, &picdev_slave_ops);
kvm_iodevice_init(&s->dev_eclr, &picdev_eclr_ops); kvm_iodevice_init(&s->dev_elcr, &picdev_elcr_ops);
mutex_lock(&kvm->slots_lock); mutex_lock(&kvm->slots_lock);
ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x20, 2, ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x20, 2,
&s->dev_master); &s->dev_master);
...@@ -613,7 +613,7 @@ int kvm_pic_init(struct kvm *kvm) ...@@ -613,7 +613,7 @@ int kvm_pic_init(struct kvm *kvm)
if (ret < 0) if (ret < 0)
goto fail_unreg_2; goto fail_unreg_2;
ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x4d0, 2, &s->dev_eclr); ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x4d0, 2, &s->dev_elcr);
if (ret < 0) if (ret < 0)
goto fail_unreg_1; goto fail_unreg_1;
...@@ -647,7 +647,7 @@ void kvm_pic_destroy(struct kvm *kvm) ...@@ -647,7 +647,7 @@ void kvm_pic_destroy(struct kvm *kvm)
mutex_lock(&kvm->slots_lock); mutex_lock(&kvm->slots_lock);
kvm_io_bus_unregister_dev(vpic->kvm, KVM_PIO_BUS, &vpic->dev_master); kvm_io_bus_unregister_dev(vpic->kvm, KVM_PIO_BUS, &vpic->dev_master);
kvm_io_bus_unregister_dev(vpic->kvm, KVM_PIO_BUS, &vpic->dev_slave); kvm_io_bus_unregister_dev(vpic->kvm, KVM_PIO_BUS, &vpic->dev_slave);
kvm_io_bus_unregister_dev(vpic->kvm, KVM_PIO_BUS, &vpic->dev_eclr); kvm_io_bus_unregister_dev(vpic->kvm, KVM_PIO_BUS, &vpic->dev_elcr);
mutex_unlock(&kvm->slots_lock); mutex_unlock(&kvm->slots_lock);
kvm->arch.vpic = NULL; kvm->arch.vpic = NULL;
......
...@@ -55,7 +55,7 @@ struct kvm_pic { ...@@ -55,7 +55,7 @@ struct kvm_pic {
int output; /* intr from master PIC */ int output; /* intr from master PIC */
struct kvm_io_device dev_master; struct kvm_io_device dev_master;
struct kvm_io_device dev_slave; struct kvm_io_device dev_slave;
struct kvm_io_device dev_eclr; struct kvm_io_device dev_elcr;
void (*ack_notifier)(void *opaque, int irq); void (*ack_notifier)(void *opaque, int irq);
unsigned long irq_states[PIC_NUM_PINS]; unsigned long irq_states[PIC_NUM_PINS];
}; };
......
...@@ -44,6 +44,7 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o ...@@ -44,6 +44,7 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
lib-y := delay.o misc.o cmdline.o cpu.o lib-y := delay.o misc.o cmdline.o cpu.o
lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
lib-y += memcpy_$(BITS).o lib-y += memcpy_$(BITS).o
lib-y += pc-conf-reg.o
lib-$(CONFIG_ARCH_HAS_COPY_MC) += copy_mc.o copy_mc_64.o lib-$(CONFIG_ARCH_HAS_COPY_MC) += copy_mc.o copy_mc_64.o
lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o
lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Support for the configuration register space at port I/O locations
* 0x22 and 0x23 variously used by PC architectures, e.g. the MP Spec,
* Cyrix CPUs, numerous chipsets. As the space is indirectly addressed
* it may have to be protected with a spinlock, depending on the context.
*/
#include <linux/spinlock.h>
#include <asm/pc-conf-reg.h>
DEFINE_RAW_SPINLOCK(pc_conf_lock);
This diff is collapsed.
...@@ -1121,6 +1121,7 @@ ...@@ -1121,6 +1121,7 @@
#define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a #define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a
#define PCI_VENDOR_ID_AL 0x10b9 #define PCI_VENDOR_ID_AL 0x10b9
#define PCI_DEVICE_ID_AL_M1489 0x1489
#define PCI_DEVICE_ID_AL_M1533 0x1533 #define PCI_DEVICE_ID_AL_M1533 0x1533
#define PCI_DEVICE_ID_AL_M1535 0x1535 #define PCI_DEVICE_ID_AL_M1535 0x1535
#define PCI_DEVICE_ID_AL_M1541 0x1541 #define PCI_DEVICE_ID_AL_M1541 0x1541
...@@ -2643,6 +2644,7 @@ ...@@ -2643,6 +2644,7 @@
#define PCI_DEVICE_ID_INTEL_82375 0x0482 #define PCI_DEVICE_ID_INTEL_82375 0x0482
#define PCI_DEVICE_ID_INTEL_82424 0x0483 #define PCI_DEVICE_ID_INTEL_82424 0x0483
#define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82378 0x0484
#define PCI_DEVICE_ID_INTEL_82425 0x0486
#define PCI_DEVICE_ID_INTEL_MRST_SD0 0x0807 #define PCI_DEVICE_ID_INTEL_MRST_SD0 0x0807
#define PCI_DEVICE_ID_INTEL_MRST_SD1 0x0808 #define PCI_DEVICE_ID_INTEL_MRST_SD1 0x0808
#define PCI_DEVICE_ID_INTEL_MFD_SD 0x0820 #define PCI_DEVICE_ID_INTEL_MFD_SD 0x0820
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment