linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
@ 2021-07-20  3:27 Maciej W. Rozycki
  2021-07-20  3:27 ` [PATCH 1/6] x86: Add support for 0x22/0x23 port I/O configuration space Maciej W. Rozycki
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-07-20  3:27 UTC (permalink / raw)
  To: Nikolai Zhubr, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, Bjorn Helgaas, Rafael J. Wysocki, Len Brown,
	Pavel Machek, Paolo Bonzini, Sean Christopherson,
	Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel
  Cc: x86, linux-pci, linux-pm, kvm, linux-kernel

Hi,

 In the course of adding PIRQ routing support for Nikolai's FinALi system 
I realised we need to have some infrastructure for the indirectly accessed
configuration space implemented by some chipsets as well as Cyrix CPUs and 
also included with the Intel MP spec for the IMCR register via port I/O 
space locations 0x22/0x23.  With that in place I implemented PIRQ support 
for the Intel PCEB/ESC combined EISA southbridge using the same scheme to 
access the relevant registers and for the final remaining Intel chipset of 
the era, that is the i420EX.

 While at it I chose to rewrite ELCR register accesses to avoid using 
magic numbers scattered across our code and use proper macros like with 
the remaining PIC registers, and while at it again I noticed and fixed a 
number of typos: s/ECLR/ELCR/.

 Since there are mechanical dependencies between the patches (except for 
typo fixes) I chose to send them as a series rather than individually, 
though 3/6 depends on: <https://lore.kernel.org/patchwork/patch/1452772/> 
necessarily as well, the fate of which is currently unclear to me.

 See individual change descriptions for details.

 Nikolai: for your system only 1/6 and 2/6 are required, though you are 
free to experiment with all the patches.  Mind that 3/6 mechanically 
depends on the earlier change for the SIO PIRQ router referred above.  In 
any case please use the debug patch for PCI code as well as the earlier 
patches for your other system and send the resulting bootstrap log for 
confirmation.

 Ideally this would be verified with PCI interrupt sharing, but for that 
you'd have to track down one or more multifunction option cards (USB 2.0 
interfaces with legacy 1.1 functions or serial/parallel multi-I/O cards 
are good candidates, but of course there are more) or option devices with 
PCI-to-PCI bridges, and then actually use some of these devices as well.  
Any interrupt sharing will be reported, e.g.:

pci 0000:00:07.0: SIO/PIIX/ICH IRQ router [8086:7000]
pci 0000:00:11.0: PCI INT A -> PIRQ 63, mask deb8, excl 0c20
pci 0000:00:11.0: PCI INT A -> newirq 0
PCI: setting IRQ 11 as level-triggered
pci 0000:00:11.0: found PCI INT A -> IRQ 11
pci 0000:00:11.0: sharing IRQ 11 with 0000:00:07.2
pci 0000:02:00.0: using bridge 0000:00:11.0 INT A to get INT A
pci 0000:00:11.0: sharing IRQ 11 with 0000:02:00.0
pci 0000:02:01.0: using bridge 0000:00:11.0 INT B to get INT A
pci 0000:02:02.0: using bridge 0000:00:11.0 INT C to get INT A
pci 0000:03:00.0: using bridge 0000:00:11.0 INT A to get INT A
pci 0000:00:11.0: sharing IRQ 11 with 0000:03:00.0
pci 0000:04:00.0: using bridge 0000:00:11.0 INT B to get INT A
pci 0000:04:00.3: using bridge 0000:00:11.0 INT A to get INT D
pci 0000:00:11.0: sharing IRQ 11 with 0000:04:00.3
pci 0000:06:05.0: using bridge 0000:00:11.0 INT D to get INT A
pci 0000:06:08.0: using bridge 0000:00:11.0 INT C to get INT A
pci 0000:06:08.1: using bridge 0000:00:11.0 INT D to get INT B
pci 0000:06:08.2: using bridge 0000:00:11.0 INT A to get INT C
pci 0000:00:11.0: sharing IRQ 11 with 0000:06:08.2

-- a lot of sharing and swizzling here. :)  You'd most definitely need: 
<https://lore.kernel.org/patchwork/patch/1454747/> for that though, as I 
can't imagine PCI BIOS 2.1 PIRQ routers to commonly enumerate devices 
behind PCI-to-PCI bridges, given that they fail to cope with more complex 
bus topologies created by option devices in the first place.

  Maciej

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/6] x86: Add support for 0x22/0x23 port I/O configuration space
  2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
@ 2021-07-20  3:27 ` Maciej W. Rozycki
  2021-07-20  3:27 ` [PATCH 2/6] x86/PCI: Add support for the ALi M1487 (IBC) PIRQ router Maciej W. Rozycki
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-07-20  3:27 UTC (permalink / raw)
  To: Nikolai Zhubr, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, Bjorn Helgaas, Rafael J. Wysocki, Len Brown,
	Pavel Machek, Paolo Bonzini, Sean Christopherson,
	Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel
  Cc: x86, linux-pci, linux-pm, kvm, linux-kernel

Define macros and accessors for the configuration space addressed 
indirectly with an index register and a data register at the port I/O 
locations of 0x22 and 0x23 respectively.

This space is defined by the Intel MultiProcessor Specification for the 
IMCR register used to switch between the PIC and the APIC mode[1], by 
Cyrix processors for their configuration[2][3], and also some chipsets.

Given the lack of atomicity with the indirect addressing a spinlock is 
required to protect accesses, although for Cyrix processors it is enough 
if accesses are executed with interrupts locally disabled, because the 
registers are local to the accessing CPU, and IMCR is only ever poked at 
by the BSP and early enough for interrupts not to have been configured 
yet.  Therefore existing code does not have to change or use the new 
spinlock and neither it does.

Put the spinlock in a library file then, so that it does not get pulled 
unnecessarily for configurations that do not refer it.

Convert Cyrix accessors to wrappers so as to retain the brevity and 
clarity of the `getCx86' and `setCx86' calls.

References:

[1] "MultiProcessor Specification", Version 1.4, Intel Corporation, 
    Order Number: 242016-006, May 1997, Section 3.6.2.1 "PIC Mode", pp. 
    3-7, 3-8

[2] "5x86 Microprocessor", Cyrix Corporation, Order Number: 94192-00, 
    July 1995, Section 2.3.2.4 "Configuration Registers", p. 2-23

[3] "6x86 Processor", Cyrix Corporation, Order Number: 94175-01, March 
    1996, Section 2.4.4 "6x86 Configuration Registers", p. 2-23

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
Verified with `objdump' not to change arch/x86/kernel/apic/apic.o or 
arch/x86/kernel/cpu/cyrix.o code produced.
---
 arch/x86/include/asm/pc-conf-reg.h     |   33 +++++++++++++++++++++++++++++++++
 arch/x86/include/asm/processor-cyrix.h |    8 ++++----
 arch/x86/kernel/apic/apic.c            |    9 +++------
 arch/x86/lib/Makefile                  |    1 +
 arch/x86/lib/pc-conf-reg.c             |   13 +++++++++++++
 5 files changed, 54 insertions(+), 10 deletions(-)

linux-x86-pc-conf-reg.diff
Index: linux-macro-pirq/arch/x86/include/asm/pc-conf-reg.h
===================================================================
--- /dev/null
+++ linux-macro-pirq/arch/x86/include/asm/pc-conf-reg.h
@@ -0,0 +1,33 @@
+/* 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 */
Index: linux-macro-pirq/arch/x86/include/asm/processor-cyrix.h
===================================================================
--- linux-macro-pirq.orig/arch/x86/include/asm/processor-cyrix.h
+++ linux-macro-pirq/arch/x86/include/asm/processor-cyrix.h
@@ -5,14 +5,14 @@
  * Access order is always 0x22 (=offset), 0x23 (=value)
  */
 
+#include <asm/pc-conf-reg.h>
+
 static inline u8 getCx86(u8 reg)
 {
-	outb(reg, 0x22);
-	return inb(0x23);
+	return pc_conf_get(reg);
 }
 
 static inline void setCx86(u8 reg, u8 data)
 {
-	outb(reg, 0x22);
-	outb(data, 0x23);
+	pc_conf_set(reg, data);
 }
Index: linux-macro-pirq/arch/x86/kernel/apic/apic.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/kernel/apic/apic.c
+++ linux-macro-pirq/arch/x86/kernel/apic/apic.c
@@ -38,6 +38,7 @@
 
 #include <asm/trace/irq_vectors.h>
 #include <asm/irq_remapping.h>
+#include <asm/pc-conf-reg.h>
 #include <asm/perf_event.h>
 #include <asm/x86_init.h>
 #include <linux/atomic.h>
@@ -132,18 +133,14 @@ static int enabled_via_apicbase __ro_aft
  */
 static inline void imcr_pic_to_apic(void)
 {
-	/* select IMCR register */
-	outb(0x70, 0x22);
 	/* 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)
 {
-	/* select IMCR register */
-	outb(0x70, 0x22);
 	/* NMI and 8259 INTR go directly to BSP */
-	outb(0x00, 0x23);
+	pc_conf_set(PC_CONF_MPS_IMCR, 0x00);
 }
 #endif
 
Index: linux-macro-pirq/arch/x86/lib/Makefile
===================================================================
--- linux-macro-pirq.orig/arch/x86/lib/Makefile
+++ linux-macro-pirq/arch/x86/lib/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp
 lib-y := delay.o misc.o cmdline.o cpu.o
 lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.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_INSTRUCTION_DECODER) += insn.o inat.o insn-eval.o
 lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
Index: linux-macro-pirq/arch/x86/lib/pc-conf-reg.c
===================================================================
--- /dev/null
+++ linux-macro-pirq/arch/x86/lib/pc-conf-reg.c
@@ -0,0 +1,13 @@
+// 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);

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 2/6] x86/PCI: Add support for the ALi M1487 (IBC) PIRQ router
  2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
  2021-07-20  3:27 ` [PATCH 1/6] x86: Add support for 0x22/0x23 port I/O configuration space Maciej W. Rozycki
@ 2021-07-20  3:27 ` Maciej W. Rozycki
  2021-07-20  3:27 ` [PATCH 3/6] x86/PCI: Add support for the Intel 82374EB/82374SB (ESC) " Maciej W. Rozycki
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-07-20  3:27 UTC (permalink / raw)
  To: Nikolai Zhubr, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, Bjorn Helgaas, Rafael J. Wysocki, Len Brown,
	Pavel Machek, Paolo Bonzini, Sean Christopherson,
	Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel
  Cc: x86, linux-pci, linux-pm, kvm, linux-kernel

The ALi M1487 ISA Bus Controller (IBC), a part of the ALi FinALi 486 
chipset, implements PCI interrupt steering with a PIRQ router[1] in the 
form of four 4-bit mappings, spread across two PCI INTx Routing Table 
Mapping Registers, available in the port I/O space accessible indirectly 
via the index/data register pair at 0x22/0x23, located at indices 0x42 
and 0x43 for the INT1/INT2 and INT3/INT4 lines respectively.

Additionally there is a separate PCI INTx Sensitivity Register at index 
0x44 in the same port I/O space, whose bits 3:0 select the trigger mode 
for INT[4:1] lines respectively[2].  Manufacturer's documentation says 
that this register has to be set consistently with the relevant ELCR 
register[3].  Add a router-specific hook then and use it to handle this 
register.

Accesses to the port I/O space concerned here need to be unlocked by 
writing the value of 0xc5 to the Lock Register at index 0x03 
beforehand[4].  Do so then and then lock access after use for safety.

The IBC is implemented as a peer bridge on the host bus rather than a 
southbridge on PCI and therefore it does not itself appear in the PCI 
configuration space.  It is complemented by the M1489 Cache-Memory PCI 
Controller (CMP) host-to-PCI bridge, so use that device's identification 
for determining the presence of the IBC.

References:

[1] "M1489/M1487: 486 PCI Chip Set", Version 1.2, Acer Laboratories 
    Inc., July 1997, Section 4: "Configuration Registers", pp. 76-77

[2] same, p. 77

[3] same, Section 5: "M1489/M1487 Software Programming Guide", pp. 
    99-100

[4] same, Section 4: "Configuration Registers", p. 37

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
 arch/x86/pci/irq.c      |  154 +++++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pci_ids.h |    1 
 2 files changed, 153 insertions(+), 2 deletions(-)

linux-x86-pirq-router-finali.diff
Index: linux-macro-pirq/arch/x86/pci/irq.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/pci/irq.c
+++ linux-macro-pirq/arch/x86/pci/irq.c
@@ -13,9 +13,12 @@
 #include <linux/dmi.h>
 #include <linux/io.h>
 #include <linux/smp.h>
+#include <linux/spinlock.h>
 #include <asm/io_apic.h>
 #include <linux/irq.h>
 #include <linux/acpi.h>
+
+#include <asm/pc-conf-reg.h>
 #include <asm/pci_x86.h>
 
 #define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
@@ -47,6 +50,8 @@ struct irq_router {
 	int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
 	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq,
 		int new);
+	int (*lvl)(struct pci_dev *router, struct pci_dev *dev, int pirq,
+		int irq);
 };
 
 struct irq_router_handler {
@@ -171,6 +176,139 @@ void elcr_set_level_irq(unsigned int irq
 }
 
 /*
+ *	PIRQ routing for the M1487 ISA Bus Controller (IBC) ASIC used
+ *	with the ALi FinALi 486 chipset.  The IBC is not decoded in the
+ *	PCI configuration space, so we identify it by the accompanying
+ *	M1489 Cache-Memory PCI Controller (CMP) ASIC.
+ *
+ *	There are four 4-bit mappings provided, spread across two PCI
+ *	INTx Routing Table Mapping Registers, available in the port I/O
+ *	space accessible indirectly via the index/data register pair at
+ *	0x22/0x23, located at indices 0x42 and 0x43 for the INT1/INT2
+ *	and INT3/INT4 lines respectively.  The INT1/INT3 and INT2/INT4
+ *	lines are mapped in the low and the high 4-bit nibble of the
+ *	corresponding register as follows:
+ *
+ *	0000 : Disabled
+ *	0001 : IRQ9
+ *	0010 : IRQ3
+ *	0011 : IRQ10
+ *	0100 : IRQ4
+ *	0101 : IRQ5
+ *	0110 : IRQ7
+ *	0111 : IRQ6
+ *	1000 : Reserved
+ *	1001 : IRQ11
+ *	1010 : Reserved
+ *	1011 : IRQ12
+ *	1100 : Reserved
+ *	1101 : IRQ14
+ *	1110 : Reserved
+ *	1111 : IRQ15
+ *
+ *	In addition to the usual ELCR register pair there is a separate
+ *	PCI INTx Sensitivity Register at index 0x44 in the same port I/O
+ *	space, whose bits 3:0 select the trigger mode for INT[4:1] lines
+ *	respectively.  Any bit set to 1 causes interrupts coming on the
+ *	corresponding line to be passed to ISA as edge-triggered and
+ *	otherwise they are passed as level-triggered.  Manufacturer's
+ *	documentation says this register has to be set consistently with
+ *	the relevant ELCR register.
+ *
+ *	Accesses to the port I/O space concerned here need to be unlocked
+ *	by writing the value of 0xc5 to the Lock Register at index 0x03
+ *	beforehand.  Any other value written to said register prevents
+ *	further accesses from reaching the register file, except for the
+ *	Lock Register being written with 0xc5 again.
+ *
+ *	References:
+ *
+ *	"M1489/M1487: 486 PCI Chip Set", Version 1.2, Acer Laboratories
+ *	Inc., July 1997
+ */
+
+#define PC_CONF_FINALI_LOCK		0x03u
+#define PC_CONF_FINALI_PCI_INTX_RT1	0x42u
+#define PC_CONF_FINALI_PCI_INTX_RT2	0x43u
+#define PC_CONF_FINALI_PCI_INTX_SENS	0x44u
+
+#define PC_CONF_FINALI_LOCK_KEY		0xc5u
+
+static u8 read_pc_conf_nybble(u8 base, u8 index)
+{
+	u8 reg = base + (index >> 1);
+	u8 x;
+
+	x = pc_conf_get(reg);
+	return index & 1 ? x >> 4 : x & 0xf;
+}
+
+static void write_pc_conf_nybble(u8 base, u8 index, u8 val)
+{
+	u8 reg = base + (index >> 1);
+	u8 x;
+
+	x = pc_conf_get(reg);
+	x = index & 1 ? (x & 0x0f) | (val << 4) : (x & 0xf0) | val;
+	pc_conf_set(reg, x);
+}
+
+static int pirq_finali_get(struct pci_dev *router, struct pci_dev *dev,
+			   int pirq)
+{
+	static const u8 irqmap[16] = {
+		0, 9, 3, 10, 4, 5, 7, 6, 0, 11, 0, 12, 0, 14, 0, 15
+	};
+	unsigned long flags;
+	u8 x;
+
+	raw_spin_lock_irqsave(&pc_conf_lock, flags);
+	pc_conf_set(PC_CONF_FINALI_LOCK, PC_CONF_FINALI_LOCK_KEY);
+	x = irqmap[read_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, pirq - 1)];
+	pc_conf_set(PC_CONF_FINALI_LOCK, 0);
+	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
+	return x;
+}
+
+static int pirq_finali_set(struct pci_dev *router, struct pci_dev *dev,
+			   int pirq, int irq)
+{
+	static const u8 irqmap[16] = {
+		0, 0, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15
+	};
+	u8 val = irqmap[irq];
+	unsigned long flags;
+
+	if (!val)
+		return 0;
+
+	raw_spin_lock_irqsave(&pc_conf_lock, flags);
+	pc_conf_set(PC_CONF_FINALI_LOCK, PC_CONF_FINALI_LOCK_KEY);
+	write_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, pirq - 1, val);
+	pc_conf_set(PC_CONF_FINALI_LOCK, 0);
+	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
+	return 1;
+}
+
+static int pirq_finali_lvl(struct pci_dev *router, struct pci_dev *dev,
+			   int pirq, int irq)
+{
+	u8 mask = ~(1u << (pirq - 1));
+	unsigned long flags;
+	u8 trig;
+
+	elcr_set_level_irq(irq);
+	raw_spin_lock_irqsave(&pc_conf_lock, flags);
+	pc_conf_set(PC_CONF_FINALI_LOCK, PC_CONF_FINALI_LOCK_KEY);
+	trig = pc_conf_get(PC_CONF_FINALI_PCI_INTX_SENS);
+	trig &= mask;
+	pc_conf_set(PC_CONF_FINALI_PCI_INTX_SENS, trig);
+	pc_conf_set(PC_CONF_FINALI_LOCK, 0);
+	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
+	return 1;
+}
+
+/*
  * Common IRQ routing practice: nibbles in config space,
  * offset by some magic constant.
  */
@@ -838,6 +976,12 @@ static __init int ite_router_probe(struc
 static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
 	switch (device) {
+	case PCI_DEVICE_ID_AL_M1489:
+		r->name = "FinALi";
+		r->get = pirq_finali_get;
+		r->set = pirq_finali_set;
+		r->lvl = pirq_finali_lvl;
+		return 1;
 	case PCI_DEVICE_ID_AL_M1533:
 	case PCI_DEVICE_ID_AL_M1563:
 		r->name = "ALI";
@@ -1128,11 +1272,17 @@ static int pcibios_lookup_irq(struct pci
 	} else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
 	((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask))) {
 		msg = "found";
-		elcr_set_level_irq(irq);
+		if (r->lvl)
+			r->lvl(pirq_router_dev, dev, pirq, irq);
+		else
+			elcr_set_level_irq(irq);
 	} else if (newirq && r->set &&
 		(dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
 		if (r->set(pirq_router_dev, dev, pirq, newirq)) {
-			elcr_set_level_irq(newirq);
+			if (r->lvl)
+				r->lvl(pirq_router_dev, dev, pirq, newirq);
+			else
+				elcr_set_level_irq(newirq);
 			msg = "assigned";
 			irq = newirq;
 		}
Index: linux-macro-pirq/include/linux/pci_ids.h
===================================================================
--- linux-macro-pirq.orig/include/linux/pci_ids.h
+++ linux-macro-pirq/include/linux/pci_ids.h
@@ -1121,6 +1121,7 @@
 #define PCI_DEVICE_ID_3COM_3CR990SVR	0x990a
 
 #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_M1535		0x1535
 #define PCI_DEVICE_ID_AL_M1541		0x1541

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 3/6] x86/PCI: Add support for the Intel 82374EB/82374SB (ESC) PIRQ router
  2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
  2021-07-20  3:27 ` [PATCH 1/6] x86: Add support for 0x22/0x23 port I/O configuration space Maciej W. Rozycki
  2021-07-20  3:27 ` [PATCH 2/6] x86/PCI: Add support for the ALi M1487 (IBC) PIRQ router Maciej W. Rozycki
@ 2021-07-20  3:27 ` Maciej W. Rozycki
  2021-07-20  3:28 ` [PATCH 4/6] x86/PCI: Add support for the Intel 82426EX " Maciej W. Rozycki
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-07-20  3:27 UTC (permalink / raw)
  To: Nikolai Zhubr, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, Bjorn Helgaas, Rafael J. Wysocki, Len Brown,
	Pavel Machek, Paolo Bonzini, Sean Christopherson,
	Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel
  Cc: x86, linux-pci, linux-pm, kvm, linux-kernel

The Intel 82374EB/82374SB EISA System Component (ESC) devices implement 
PCI interrupt steering with a PIRQ router[1] in the form of four PIRQ 
Route Control registers, available in the port I/O space accessible 
indirectly via the index/data register pair at 0x22/0x23, located at 
indices 0x60/0x61/0x62/0x63 for the PIRQ0/1/2/3# lines respectively.  

The semantics is the same as with the PIIX router, however it is not 
clear if BIOSes use register indices or line numbers as the cookie to 
identify PCI interrupts in their routing tables and therefore support 
either scheme.

Accesses to the port I/O space concerned here need to be unlocked by 
writing the value of 0x0f to the ESC ID Register at index 0x02 
beforehand[2].  Do so then and then lock access after use for safety. 

This locking could possibly interfere with accesses to the Intel MP spec 
IMCR register, implemented by the 82374SB variant of the ESC only as the 
PCI/APIC Control Register at index 0x70[3], for which leaving access to 
the configuration space concerned unlocked may have been a requirement 
for the BIOS to remain compliant with the MP spec.  However we only poke 
at the IMCR register if the APIC mode is used, in which case the PIRQ 
router is not, so this arrangement is not going to interfere with IMCR 
access code.

The ESC is implemented as a part of the combined southbridge also made 
of 82375EB/82375SB PCI-EISA Bridge (PCEB) and does itself appear in the 
PCI configuration space.  Use the PCEB's device identification then for
determining the presence of the ESC.

References:

[1] "82374EB/82374SB EISA System Component (ESC)", Intel Corporation, 
    Order Number: 290476-004, March 1996, Section 3.1.12 
    "PIRQ[0:3]#--PIRQ Route Control Registers", pp. 44-45

[2] same, Section 3.1.1 "ESCID--ESC ID Register", p. 36

[3] same, Section 3.1.17 "PAC--PCI/APIC Control Register", p. 47

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
 arch/x86/pci/irq.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

linux-x86-pirq-router-esc.diff
Index: linux-macro-pirq/arch/x86/pci/irq.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/pci/irq.c
+++ linux-macro-pirq/arch/x86/pci/irq.c
@@ -359,6 +359,74 @@ static int pirq_ali_set(struct pci_dev *
 }
 
 /*
+ *	PIRQ routing for the 82374EB/82374SB EISA System Component (ESC)
+ *	ASIC used with the Intel 82420 and 82430 PCIsets.  The ESC is not
+ *	decoded in the PCI configuration space, so we identify it by the
+ *	accompanying 82375EB/82375SB PCI-EISA Bridge (PCEB) ASIC.
+ *
+ *	There are four PIRQ Route Control registers, available in the
+ *	port I/O space accessible indirectly via the index/data register
+ *	pair at 0x22/0x23, located at indices 0x60/0x61/0x62/0x63 for the
+ *	PIRQ0/1/2/3# lines respectively.  The semantics is the same as
+ *	with the PIIX router.
+ *
+ *	Accesses to the port I/O space concerned here need to be unlocked
+ *	by writing the value of 0x0f to the ESC ID Register at index 0x02
+ *	beforehand.  Any other value written to said register prevents
+ *	further accesses from reaching the register file, except for the
+ *	ESC ID Register being written with 0x0f again.
+ *
+ *	References:
+ *
+ *	"82374EB/82374SB EISA System Component (ESC)", Intel Corporation,
+ *	Order Number: 290476-004, March 1996
+ *
+ *	"82375EB/82375SB PCI-EISA Bridge (PCEB)", Intel Corporation, Order
+ *	Number: 290477-004, March 1996
+ */
+
+#define PC_CONF_I82374_ESC_ID			0x02u
+#define PC_CONF_I82374_PIRQ_ROUTE_CONTROL	0x60u
+
+#define PC_CONF_I82374_ESC_ID_KEY		0x0fu
+
+static int pirq_esc_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	unsigned long flags;
+	int reg;
+	u8 x;
+
+	reg = pirq;
+	if (reg >= 1 && reg <= 4)
+		reg += PC_CONF_I82374_PIRQ_ROUTE_CONTROL - 1;
+
+	raw_spin_lock_irqsave(&pc_conf_lock, flags);
+	pc_conf_set(PC_CONF_I82374_ESC_ID, PC_CONF_I82374_ESC_ID_KEY);
+	x = pc_conf_get(reg);
+	pc_conf_set(PC_CONF_I82374_ESC_ID, 0);
+	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
+	return (x < 16) ? x : 0;
+}
+
+static int pirq_esc_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
+		       int irq)
+{
+	unsigned long flags;
+	int reg;
+
+	reg = pirq;
+	if (reg >= 1 && reg <= 4)
+		reg += PC_CONF_I82374_PIRQ_ROUTE_CONTROL - 1;
+
+	raw_spin_lock_irqsave(&pc_conf_lock, flags);
+	pc_conf_set(PC_CONF_I82374_ESC_ID, PC_CONF_I82374_ESC_ID_KEY);
+	pc_conf_set(reg, irq);
+	pc_conf_set(PC_CONF_I82374_ESC_ID, 0);
+	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
+	return 1;
+}
+
+/*
  * The Intel PIIX4 pirq rules are fairly simple: "pirq" is
  * just a pointer to the config space.
  */
@@ -768,6 +836,11 @@ static __init int intel_router_probe(str
 
 	switch (device) {
 		u8 rid;
+	case PCI_DEVICE_ID_INTEL_82375:
+		r->name = "PCEB/ESC";
+		r->get = pirq_esc_get;
+		r->set = pirq_esc_set;
+		return 1;
 	case PCI_DEVICE_ID_INTEL_82378:
 		pci_read_config_byte(router, PCI_REVISION_ID, &rid);
 		/* Tell 82378IB (rev < 3) and 82378ZB/82379AB apart.  */

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 4/6] x86/PCI: Add support for the Intel 82426EX PIRQ router
  2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
                   ` (2 preceding siblings ...)
  2021-07-20  3:27 ` [PATCH 3/6] x86/PCI: Add support for the Intel 82374EB/82374SB (ESC) " Maciej W. Rozycki
@ 2021-07-20  3:28 ` Maciej W. Rozycki
  2021-07-20  3:28 ` [PATCH 5/6] x86: Avoid magic number with ELCR register accesses Maciej W. Rozycki
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-07-20  3:28 UTC (permalink / raw)
  To: Nikolai Zhubr, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, Bjorn Helgaas, Rafael J. Wysocki, Len Brown,
	Pavel Machek, Paolo Bonzini, Sean Christopherson,
	Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel
  Cc: x86, linux-pci, linux-pm, kvm, linux-kernel

The Intel 82426EX ISA Bridge (IB), a part of the Intel 82420EX PCIset, 
implements PCI interrupt steering with a PIRQ router in the form of two 
PIRQ Route Control registers, available in the PCI configuration space 
at locations 0x66 and 0x67 for the PIRQ0# and PIRQ1# lines respectively.

The semantics is the same as with the PIIX router, however it is not
clear if BIOSes use register indices or line numbers as the cookie to
identify PCI interrupts in their routing tables and therefore support
either scheme.

The IB is directly attached to the Intel 82425EX PCI System Controller 
(PSC) component of the chipset via a dedicated PSC/IB Link interface 
rather than the host bus or PCI.  Therefore it does not itself appear in 
the PCI configuration space even though it responds to configuration 
cycles addressing registers it implements.  Use 82425EX's identification 
then for determining the presence of the IB.

References:

[1] "82420EX PCIset Data Sheet, 82425EX PCI System Controller (PSC) and 
    82426EX ISA Bridge (IB)", Intel Corporation, Order Number: 
    290488-004, December 1995, Section 3.3.18 "PIRQ1RC/PIRQ0RC--PIRQ 
    Route Control Registers", p. 61

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
 arch/x86/pci/irq.c      |   49 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci_ids.h |    1 
 2 files changed, 50 insertions(+)

linux-x86-pirq-router-ib.diff
Index: linux-macro-pirq/arch/x86/pci/irq.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/pci/irq.c
+++ linux-macro-pirq/arch/x86/pci/irq.c
@@ -447,6 +447,50 @@ static int pirq_piix_set(struct pci_dev
 }
 
 /*
+ *	PIRQ routing for the 82426EX ISA Bridge (IB) ASIC used with the
+ *	Intel 82420EX PCIset.
+ *
+ *	There are only two PIRQ Route Control registers, available in the
+ *	combined 82425EX/82426EX PCI configuration space, at 0x66 and 0x67
+ *	for the PIRQ0# and PIRQ1# lines respectively.  The semantics is
+ *	the same as with the PIIX router.
+ *
+ *	References:
+ *
+ *	"82420EX PCIset Data Sheet, 82425EX PCI System Controller (PSC)
+ *	and 82426EX ISA Bridge (IB)", Intel Corporation, Order Number:
+ *	290488-004, December 1995
+ */
+
+#define PCI_I82426EX_PIRQ_ROUTE_CONTROL	0x66u
+
+static int pirq_ib_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	int reg;
+	u8 x;
+
+	reg = pirq;
+	if (reg >= 1 && reg <= 2)
+		reg += PCI_I82426EX_PIRQ_ROUTE_CONTROL - 1;
+
+	pci_read_config_byte(router, reg, &x);
+	return (x < 16) ? x : 0;
+}
+
+static int pirq_ib_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
+		       int irq)
+{
+	int reg;
+
+	reg = pirq;
+	if (reg >= 1 && reg <= 2)
+		reg += PCI_I82426EX_PIRQ_ROUTE_CONTROL - 1;
+
+	pci_write_config_byte(router, reg, irq);
+	return 1;
+}
+
+/*
  * The VIA pirq rules are nibble-based, like ALI,
  * but without the ugly irq number munging.
  * However, PIRQD is in the upper instead of lower 4 bits.
@@ -892,6 +936,11 @@ static __init int intel_router_probe(str
 		r->get = pirq_piix_get;
 		r->set = pirq_piix_set;
 		return 1;
+	case PCI_DEVICE_ID_INTEL_82425:
+		r->name = "PSC/IB";
+		r->get = pirq_ib_get;
+		r->set = pirq_ib_set;
+		return 1;
 	}
 
 	if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN && 
Index: linux-macro-pirq/include/linux/pci_ids.h
===================================================================
--- linux-macro-pirq.orig/include/linux/pci_ids.h
+++ linux-macro-pirq/include/linux/pci_ids.h
@@ -2644,6 +2644,7 @@
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
 #define PCI_DEVICE_ID_INTEL_82424	0x0483
 #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_SD1	0x0808
 #define PCI_DEVICE_ID_INTEL_MFD_SD	0x0820

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 5/6] x86: Avoid magic number with ELCR register accesses
  2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
                   ` (3 preceding siblings ...)
  2021-07-20  3:28 ` [PATCH 4/6] x86/PCI: Add support for the Intel 82426EX " Maciej W. Rozycki
@ 2021-07-20  3:28 ` Maciej W. Rozycki
  2021-07-20  3:28 ` [PATCH 6/6] x86: Fix typo s/ECLR/ELCR/ for the PIC register Maciej W. Rozycki
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-07-20  3:28 UTC (permalink / raw)
  To: Nikolai Zhubr, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, Bjorn Helgaas, Rafael J. Wysocki, Len Brown,
	Pavel Machek, Paolo Bonzini, Sean Christopherson,
	Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel
  Cc: x86, linux-pci, linux-pm, kvm, linux-kernel

Define PIC_ELCR1 and PIC_ELCR2 macros for accesses to the ELCR registers 
implemented by many chipsets in their embedded 8259A PIC cores, avoiding 
magic numbers that are difficult to handle, and complementing the macros 
we already have for registers originally defined with discrete 8259A PIC 
implementations.  No functional change.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
This deliberately doesn't touch KVM, which refrains from using macros for 
any PIC accesses.
---
 arch/x86/include/asm/i8259.h   |    2 ++
 arch/x86/kernel/acpi/boot.c    |    6 +++---
 arch/x86/kernel/apic/io_apic.c |    2 +-
 arch/x86/kernel/apic/vector.c  |    2 +-
 arch/x86/kernel/i8259.c        |    8 ++++----
 arch/x86/kernel/mpparse.c      |    3 ++-
 arch/x86/pci/irq.c             |    3 ++-
 7 files changed, 15 insertions(+), 11 deletions(-)

linux-x86-pic-elcr.diff
Index: linux-macro-pirq/arch/x86/include/asm/i8259.h
===================================================================
--- linux-macro-pirq.orig/arch/x86/include/asm/i8259.h
+++ linux-macro-pirq/arch/x86/include/asm/i8259.h
@@ -19,6 +19,8 @@ extern unsigned int cached_irq_mask;
 #define PIC_MASTER_OCW3		PIC_MASTER_ISR
 #define PIC_SLAVE_CMD		0xa0
 #define PIC_SLAVE_IMR		0xa1
+#define PIC_ELCR1		0x4d0
+#define PIC_ELCR2		0x4d1
 
 /* i8259A PIC related value */
 #define PIC_CASCADE_IR		2
Index: linux-macro-pirq/arch/x86/kernel/acpi/boot.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/kernel/acpi/boot.c
+++ linux-macro-pirq/arch/x86/kernel/acpi/boot.c
@@ -570,7 +570,7 @@ void __init acpi_pic_sci_set_trigger(uns
 	unsigned int old, new;
 
 	/* 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
@@ -596,8 +596,8 @@ void __init acpi_pic_sci_set_trigger(uns
 		return;
 
 	pr_warn("setting ELCR to %04x (from %04x)\n", new, old);
-	outb(new, 0x4d0);
-	outb(new >> 8, 0x4d1);
+	outb(new, PIC_ELCR1);
+	outb(new >> 8, PIC_ELCR2);
 }
 
 int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
Index: linux-macro-pirq/arch/x86/kernel/apic/io_apic.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/kernel/apic/io_apic.c
+++ linux-macro-pirq/arch/x86/kernel/apic/io_apic.c
@@ -764,7 +764,7 @@ static bool irq_active_low(int idx)
 static bool EISA_ELCR(unsigned int irq)
 {
 	if (irq < nr_legacy_irqs()) {
-		unsigned int port = 0x4d0 + (irq >> 3);
+		unsigned int port = PIC_ELCR1 + (irq >> 3);
 		return (inb(port) >> (irq & 7)) & 1;
 	}
 	apic_printk(APIC_VERBOSE, KERN_INFO
Index: linux-macro-pirq/arch/x86/kernel/apic/vector.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/kernel/apic/vector.c
+++ linux-macro-pirq/arch/x86/kernel/apic/vector.c
@@ -1299,7 +1299,7 @@ static void __init print_PIC(void)
 
 	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);
 }
 
Index: linux-macro-pirq/arch/x86/kernel/i8259.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/kernel/i8259.c
+++ linux-macro-pirq/arch/x86/kernel/i8259.c
@@ -235,15 +235,15 @@ static char irq_trigger[2];
  */
 static void restore_ELCR(char *trigger)
 {
-	outb(trigger[0], 0x4d0);
-	outb(trigger[1], 0x4d1);
+	outb(trigger[0], PIC_ELCR1);
+	outb(trigger[1], PIC_ELCR2);
 }
 
 static void save_ELCR(char *trigger)
 {
 	/* IRQ 0,1,2,8,13 are marked as reserved */
-	trigger[0] = inb(0x4d0) & 0xF8;
-	trigger[1] = inb(0x4d1) & 0xDE;
+	trigger[0] = inb(PIC_ELCR1) & 0xF8;
+	trigger[1] = inb(PIC_ELCR2) & 0xDE;
 }
 
 static void i8259A_resume(void)
Index: linux-macro-pirq/arch/x86/kernel/mpparse.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/kernel/mpparse.c
+++ linux-macro-pirq/arch/x86/kernel/mpparse.c
@@ -19,6 +19,7 @@
 #include <linux/smp.h>
 #include <linux/pci.h>
 
+#include <asm/i8259.h>
 #include <asm/io_apic.h>
 #include <asm/acpi.h>
 #include <asm/irqdomain.h>
@@ -251,7 +252,7 @@ static int __init ELCR_trigger(unsigned
 {
 	unsigned int port;
 
-	port = 0x4d0 + (irq >> 3);
+	port = PIC_ELCR1 + (irq >> 3);
 	return (inb(port) >> (irq & 7)) & 1;
 }
 
Index: linux-macro-pirq/arch/x86/pci/irq.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/pci/irq.c
+++ linux-macro-pirq/arch/x86/pci/irq.c
@@ -18,6 +18,7 @@
 #include <linux/irq.h>
 #include <linux/acpi.h>
 
+#include <asm/i8259.h>
 #include <asm/pc-conf-reg.h>
 #include <asm/pci_x86.h>
 
@@ -159,7 +160,7 @@ static void __init pirq_peer_trick(void)
 void elcr_set_level_irq(unsigned int irq)
 {
 	unsigned char mask = 1 << (irq & 7);
-	unsigned int port = 0x4d0 + (irq >> 3);
+	unsigned int port = PIC_ELCR1 + (irq >> 3);
 	unsigned char val;
 	static u16 elcr_irq_mask;
 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 6/6] x86: Fix typo s/ECLR/ELCR/ for the PIC register
  2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
                   ` (4 preceding siblings ...)
  2021-07-20  3:28 ` [PATCH 5/6] x86: Avoid magic number with ELCR register accesses Maciej W. Rozycki
@ 2021-07-20  3:28 ` Maciej W. Rozycki
  2021-07-21  0:12 ` [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Bjorn Helgaas
  2021-08-15 22:22 ` Nikolai Zhubr
  7 siblings, 0 replies; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-07-20  3:28 UTC (permalink / raw)
  To: Nikolai Zhubr, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, Bjorn Helgaas, Rafael J. Wysocki, Len Brown,
	Pavel Machek, Paolo Bonzini, Sean Christopherson,
	Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel
  Cc: x86, linux-pci, linux-pm, kvm, linux-kernel

The proper spelling for the acronym referring to the Edge/Level Control 
Register is ELCR rather than ECLR.  Adjust references accordingly.  No 
functional change.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
 arch/x86/kernel/acpi/boot.c |    6 +++---
 arch/x86/kvm/i8259.c        |   20 ++++++++++----------
 arch/x86/kvm/irq.h          |    2 +-
 3 files changed, 14 insertions(+), 14 deletions(-)

linux-x86-pic-elcr-typo.diff
Index: linux-macro-pirq/arch/x86/kernel/acpi/boot.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/kernel/acpi/boot.c
+++ linux-macro-pirq/arch/x86/kernel/acpi/boot.c
@@ -558,10 +558,10 @@ acpi_parse_nmi_src(union acpi_subtable_h
  * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
  * 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.
- * ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
- * ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
+ * ELCR1 is IRQs 0-7 (IRQ 0, 1, 2 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)
Index: linux-macro-pirq/arch/x86/kvm/i8259.c
===================================================================
--- linux-macro-pirq.orig/arch/x86/kvm/i8259.c
+++ linux-macro-pirq/arch/x86/kvm/i8259.c
@@ -541,17 +541,17 @@ static int picdev_slave_read(struct kvm_
 			    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)
 {
-	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);
 }
 
-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)
 {
-	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);
 }
 
@@ -577,9 +577,9 @@ static const struct kvm_io_device_ops pi
 	.write    = picdev_slave_write,
 };
 
-static const struct kvm_io_device_ops picdev_eclr_ops = {
-	.read     = picdev_eclr_read,
-	.write    = picdev_eclr_write,
+static const struct kvm_io_device_ops picdev_elcr_ops = {
+	.read     = picdev_elcr_read,
+	.write    = picdev_elcr_write,
 };
 
 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_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);
 	ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x20, 2,
 				      &s->dev_master);
@@ -613,7 +613,7 @@ int kvm_pic_init(struct kvm *kvm)
 	if (ret < 0)
 		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)
 		goto fail_unreg_1;
 
@@ -647,7 +647,7 @@ void kvm_pic_destroy(struct kvm *kvm)
 	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_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);
 
 	kvm->arch.vpic = NULL;
Index: linux-macro-pirq/arch/x86/kvm/irq.h
===================================================================
--- linux-macro-pirq.orig/arch/x86/kvm/irq.h
+++ linux-macro-pirq/arch/x86/kvm/irq.h
@@ -55,7 +55,7 @@ struct kvm_pic {
 	int output;		/* intr from master PIC */
 	struct kvm_io_device dev_master;
 	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);
 	unsigned long irq_states[PIC_NUM_PINS];
 };

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
                   ` (5 preceding siblings ...)
  2021-07-20  3:28 ` [PATCH 6/6] x86: Fix typo s/ECLR/ELCR/ for the PIC register Maciej W. Rozycki
@ 2021-07-21  0:12 ` Bjorn Helgaas
  2021-07-21 20:41   ` Thomas Gleixner
  2021-08-15 22:22 ` Nikolai Zhubr
  7 siblings, 1 reply; 16+ messages in thread
From: Bjorn Helgaas @ 2021-07-21  0:12 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Nikolai Zhubr, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin, Bjorn Helgaas, Rafael J. Wysocki, Len Brown,
	Pavel Machek, Paolo Bonzini, Sean Christopherson,
	Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel, x86,
	linux-pci, linux-pm, kvm, linux-kernel

On Tue, Jul 20, 2021 at 05:27:43AM +0200, Maciej W. Rozycki wrote:
> Hi,
> 
>  In the course of adding PIRQ routing support for Nikolai's FinALi system 
> I realised we need to have some infrastructure for the indirectly accessed
> configuration space implemented by some chipsets as well as Cyrix CPUs and 
> also included with the Intel MP spec for the IMCR register via port I/O 
> space locations 0x22/0x23.  With that in place I implemented PIRQ support 
> for the Intel PCEB/ESC combined EISA southbridge using the same scheme to 
> access the relevant registers and for the final remaining Intel chipset of 
> the era, that is the i420EX.
> 
>  While at it I chose to rewrite ELCR register accesses to avoid using 
> magic numbers scattered across our code and use proper macros like with 
> the remaining PIC registers, and while at it again I noticed and fixed a 
> number of typos: s/ECLR/ELCR/.
> 
>  Since there are mechanical dependencies between the patches (except for 
> typo fixes) I chose to send them as a series rather than individually, 
> though 3/6 depends on: <https://lore.kernel.org/patchwork/patch/1452772/> 
> necessarily as well, the fate of which is currently unclear to me.
> 
>  See individual change descriptions for details.
> 
>  Nikolai: for your system only 1/6 and 2/6 are required, though you are 
> free to experiment with all the patches.  Mind that 3/6 mechanically 
> depends on the earlier change for the SIO PIRQ router referred above.  In 
> any case please use the debug patch for PCI code as well as the earlier 
> patches for your other system and send the resulting bootstrap log for 
> confirmation.
> 
>  Ideally this would be verified with PCI interrupt sharing, but for that 
> you'd have to track down one or more multifunction option cards (USB 2.0 
> interfaces with legacy 1.1 functions or serial/parallel multi-I/O cards 
> are good candidates, but of course there are more) or option devices with 
> PCI-to-PCI bridges, and then actually use some of these devices as well.  
> Any interrupt sharing will be reported, e.g.:
> 
> pci 0000:00:07.0: SIO/PIIX/ICH IRQ router [8086:7000]
> pci 0000:00:11.0: PCI INT A -> PIRQ 63, mask deb8, excl 0c20
> pci 0000:00:11.0: PCI INT A -> newirq 0
> PCI: setting IRQ 11 as level-triggered
> pci 0000:00:11.0: found PCI INT A -> IRQ 11
> pci 0000:00:11.0: sharing IRQ 11 with 0000:00:07.2
> pci 0000:02:00.0: using bridge 0000:00:11.0 INT A to get INT A
> pci 0000:00:11.0: sharing IRQ 11 with 0000:02:00.0
> pci 0000:02:01.0: using bridge 0000:00:11.0 INT B to get INT A
> pci 0000:02:02.0: using bridge 0000:00:11.0 INT C to get INT A
> pci 0000:03:00.0: using bridge 0000:00:11.0 INT A to get INT A
> pci 0000:00:11.0: sharing IRQ 11 with 0000:03:00.0
> pci 0000:04:00.0: using bridge 0000:00:11.0 INT B to get INT A
> pci 0000:04:00.3: using bridge 0000:00:11.0 INT A to get INT D
> pci 0000:00:11.0: sharing IRQ 11 with 0000:04:00.3
> pci 0000:06:05.0: using bridge 0000:00:11.0 INT D to get INT A
> pci 0000:06:08.0: using bridge 0000:00:11.0 INT C to get INT A
> pci 0000:06:08.1: using bridge 0000:00:11.0 INT D to get INT B
> pci 0000:06:08.2: using bridge 0000:00:11.0 INT A to get INT C
> pci 0000:00:11.0: sharing IRQ 11 with 0000:06:08.2
> 
> -- a lot of sharing and swizzling here. :)  You'd most definitely need: 
> <https://lore.kernel.org/patchwork/patch/1454747/> for that though, as I 
> can't imagine PCI BIOS 2.1 PIRQ routers to commonly enumerate devices 
> behind PCI-to-PCI bridges, given that they fail to cope with more complex 
> bus topologies created by option devices in the first place.

Looks nicely done but I have no ability to review or test, so I assume
the x86 folks will take care of this.

Bjorn

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-07-21  0:12 ` [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Bjorn Helgaas
@ 2021-07-21 20:41   ` Thomas Gleixner
  0 siblings, 0 replies; 16+ messages in thread
From: Thomas Gleixner @ 2021-07-21 20:41 UTC (permalink / raw)
  To: Bjorn Helgaas, Maciej W. Rozycki
  Cc: Nikolai Zhubr, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Bjorn Helgaas, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, x86, linux-pci, linux-pm, kvm,
	linux-kernel

On Tue, Jul 20 2021 at 19:12, Bjorn Helgaas wrote:
> On Tue, Jul 20, 2021 at 05:27:43AM +0200, Maciej W. Rozycki wrote:
>> -- a lot of sharing and swizzling here. :)  You'd most definitely need: 
>> <https://lore.kernel.org/patchwork/patch/1454747/> for that though, as I 
>> can't imagine PCI BIOS 2.1 PIRQ routers to commonly enumerate devices 
>> behind PCI-to-PCI bridges, given that they fail to cope with more complex 
>> bus topologies created by option devices in the first place.
>
> Looks nicely done but I have no ability to review or test, so I assume
> the x86 folks will take care of this.

I can review it and pick it up, but for testing I have to rely on the
reporter/submitters.

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
                   ` (6 preceding siblings ...)
  2021-07-21  0:12 ` [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Bjorn Helgaas
@ 2021-08-15 22:22 ` Nikolai Zhubr
  2021-08-16 22:30   ` Maciej W. Rozycki
  7 siblings, 1 reply; 16+ messages in thread
From: Nikolai Zhubr @ 2021-08-15 22:22 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Bjorn Helgaas, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, x86, linux-pci, linux-pm, kvm,
	linux-kernel

Hello Maciej,

20.07.2021 6:27, Maciej W. Rozycki:
[...]
>   Nikolai: for your system only 1/6 and 2/6 are required, though you are
> free to experiment with all the patches.  Mind that 3/6 mechanically
> depends on the earlier change for the SIO PIRQ router referred above.  In
> any case please use the debug patch for PCI code as well as the earlier
> patches for your other system and send the resulting bootstrap log for
> confirmation.

Here is a new log with 1/6 and 2/6 applied:

https://pastebin.com/0MgXAGtG

It looks like something went a bit unexpected ("runtime IRQ mapping not 
provided by arch").


Thank you,

Regards,
Nikolai

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-08-15 22:22 ` Nikolai Zhubr
@ 2021-08-16 22:30   ` Maciej W. Rozycki
  2021-09-07 14:42     ` Nikolai Zhubr
  0 siblings, 1 reply; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-08-16 22:30 UTC (permalink / raw)
  To: Nikolai Zhubr
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Bjorn Helgaas, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, x86, linux-pci, linux-pm, kvm,
	linux-kernel

Hi Nikolai,

> >   Nikolai: for your system only 1/6 and 2/6 are required, though you are
> > free to experiment with all the patches.  Mind that 3/6 mechanically
> > depends on the earlier change for the SIO PIRQ router referred above.  In
> > any case please use the debug patch for PCI code as well as the earlier
> > patches for your other system and send the resulting bootstrap log for
> > confirmation.
> 
> Here is a new log with 1/6 and 2/6 applied:
> 
> https://pastebin.com/0MgXAGtG
> 
> It looks like something went a bit unexpected ("runtime IRQ mapping not
> provided by arch").

 Offhand it looks like your system does not supply a PIRQ table, not at 
least at the usual locations we look through.  The presence of the table 
is reported like:

PCI: IRQ init
PCI: Interrupt Routing Table found at 0xfde10
[...]
PCI: IRQ fixup

while your system says:

PCI: IRQ init
PCI: IRQ fixup

If you have a look through /dev/mem and see if there's a "$PIR" signature 
somewhere (though not a Linux kernel area of course), then we may know for 
sure.

 I'm a little busy at the moment with other stuff and may not be able to 
look into it properly right now.  There may be no solution, not at least 
an easy one.  A DMI quirk is not possible, because:

DMI not present or invalid.

There is a PCI BIOS:

PCI: PCI BIOS revision 2.10 entry at 0xf6f41, last bus=0

however, so CONFIG_PCI_BIOS just might work.  Please try that too, by 
choosing CONFIG_PCI_GOANY or CONFIG_PCI_GOBIOS (it may break things 
horribly though I imagine).

  Maciej

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-08-16 22:30   ` Maciej W. Rozycki
@ 2021-09-07 14:42     ` Nikolai Zhubr
  2021-09-11 15:31       ` Nikolai Zhubr
  2021-09-14  9:24       ` Maciej W. Rozycki
  0 siblings, 2 replies; 16+ messages in thread
From: Nikolai Zhubr @ 2021-09-07 14:42 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Bjorn Helgaas, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, x86, linux-pci

Hello Maciej,

17.08.2021 1:30, Maciej W. Rozycki:
[...]
> If you have a look through /dev/mem and see if there's a "$PIR" signature
> somewhere (though not a Linux kernel area of course), then we may know for
> sure.

There is no "$PIR" signature anywhere, including all uncompressed 
internal ROM modules. Instead though, there is an "$IRT" signature and a 
table following it:

F9A90: 24 49 52 54 04 04 00 00 00 18 10 F8 DE 28 F8 DE │ $IRT
F9AA0: 41 F8 DE 89 F8 DE 01 00 00 20 28 F8 DE 41 F8 DE │
F9AB0: 89 F8 DE 10 F8 DE 02 00 00 28 41 F8 DE 89 F8 DE │
F9AC0: 10 F8 DE 28 F8 DE 03 00 00 08 89 F8 DE 10 F8 DE │
F9AD0: 28 F8 DE 41 F8 DE 04 00 00 09 03 0A 04 05 07 06 │
F9AE0: 00 0B 00 0C 00 0E 00 0F 60 1E 0E 1F E8 98 00 8B │
F9AF0: FA 1F 72 6B 0A C0 74 67 3C F0 73 45 8A C8 24 01 │

By stepping through some BIOS initialization code in bochs, I've 
determined that this table is being consulted just before modifying 
chipset registers 44 and 42/43, so no doubt it is related to IRQs. From 
the same BIOS code it is clear that every entry is 16 bytes long (just 
like in pci_x86.h), the very first entry starts at offset 8 (counting 
from the start of the above fragment), and total number of entries is 
stored at offset 5 in a 16-bit word. My guess is 0-value byte at offset 
7 might be padding, and 4 at offset 4 looks like header size, because 
there is just nothing else in the header.

The entries look similar to irq_info defined in pci_x86.h, so I decided 
to give it a try. For a test, I've modified the struct irq_routing_table 
defined in pci_x86.h and irq.c to match this $IRT structure. Now I get this:

[    0.312000] PCI: IRQ init
[    0.316000] PCI: Interrupt Routing Table found at 0xc00f9a90
[    0.316000] 00:03 slot=01
[    0.316000]  0:10/def8
[    0.316000]  1:28/def8
[    0.316000]  2:41/def8
[    0.316000]  3:89/def8
[    0.316000] 00:04 slot=02
[    0.316000]  0:28/def8
[    0.316000]  1:41/def8
[    0.316000]  2:89/def8
[    0.316000]  3:10/def8
[    0.316000] 00:05 slot=03
[    0.316000]  0:41/def8
[    0.316000]  1:89/def8
[    0.316000]  2:10/def8
[    0.320000]  3:28/def8
[    0.320000] 00:01 slot=04
[    0.320000]  0:89/def8
[    0.320000]  1:10/def8
[    0.320000]  2:28/def8
[    0.320000]  3:41/def8
[    0.320000] PCI: Attempting to find IRQ router for [0000:0000]
[    0.320000] PCI: Trying IRQ router for [10b9:1489]
[    0.320000] pci 0000:00:00.0: FinALi IRQ router [10b9:1489]

Not sure if the table was parsed correcly, but the following messages 
later obviously show some problem:

[    0.625911] 8139too 0000:00:03.0: runtime IRQ mapping not provided by 
arch
[    0.625911] 8139too: 8139too Fast Ethernet driver 0.9.28
[    0.625911] 8139too 0000:00:03.0: PCI INT A -> PIRQ 10, mask def8, 
excl 0000
[    0.625911] 8139too 0000:00:03.0: PCI INT A -> newirq 11
[    0.630068] PCI: setting IRQ 15 as level-triggered
[    0.630068]  -> edge
[    0.630068] 8139too 0000:00:03.0: found PCI INT A -> IRQ 15
[    0.630068] 8139too 0000:00:03.0: IRQ routing conflict: have IRQ 11, 
want IRQ 15
[    0.641901] 8139too 0000:00:03.0 eth0: RealTek RTL8139 at 0xc2582f00, 
00:11:6b:32:85:74, IRQ 11

First, INTA is apparently routed to IRQ11 (and the network card works 
just fine with that), whereas pci code wants IRQ15 for some reason.

Second, dumping chipset reg 44 shows that INTA is still set to EDGE mode 
anyway, although dumping port 4D1 now shows IRQ15 was changed to LEVEL 
mode, exactly as indicated in the above output. I'm not sure, but the 
datasheet (page 77) seems to indicate that INTx mode set in reg 44 
should match the respective IRQx mode in port 4Dx (Although the ROM BIOS 
seems to only have code to change triggering mode in the 44 register and 
does not care about port 4Dx whatsoever, which kinda contradicts the 
datasheet)

I'll do some more digging later, but any hints are appreciated anyway.


Thank you,

Regards,
Nikolai

>
>   I'm a little busy at the moment with other stuff and may not be able to
> look into it properly right now.  There may be no solution, not at least
> an easy one.  A DMI quirk is not possible, because:
>
> DMI not present or invalid.
>
> There is a PCI BIOS:
>
> PCI: PCI BIOS revision 2.10 entry at 0xf6f41, last bus=0
>
> however, so CONFIG_PCI_BIOS just might work.  Please try that too, by
> choosing CONFIG_PCI_GOANY or CONFIG_PCI_GOBIOS (it may break things
> horribly though I imagine).
>
>    Maciej
>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-09-07 14:42     ` Nikolai Zhubr
@ 2021-09-11 15:31       ` Nikolai Zhubr
  2021-09-12 16:51         ` Nikolai Zhubr
  2021-09-14  9:24       ` Maciej W. Rozycki
  1 sibling, 1 reply; 16+ messages in thread
From: Nikolai Zhubr @ 2021-09-11 15:31 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Bjorn Helgaas, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, x86, linux-pci

Hello Maciej,

07.09.2021 17:42, I wrote:
> [ 0.625911] 8139too: 8139too Fast Ethernet driver 0.9.28
> [ 0.625911] 8139too 0000:00:03.0: PCI INT A -> PIRQ 10, mask def8, excl
> 0000
> [ 0.625911] 8139too 0000:00:03.0: PCI INT A -> newirq 11
> [ 0.630068] PCI: setting IRQ 15 as level-triggered
> [ 0.630068] -> edge
> [ 0.630068] 8139too 0000:00:03.0: found PCI INT A -> IRQ 15

Ok, I've sorted this out. Your patch works as intended, as long as the 
.link field values are encoded as numbers from 1 to 4. In the (severely 
obsolete) "$IRT" routing table I discovered in my BIOS, the .link values 
are some strange 0x10-0x28-0x41-0x89 numbers, whatever was the idea of 
BIOS writers behind this. AFAIK such numbering is not prohibited by PCI 
BIOS spec, but obviously it has to be in agreement with what register 
access routines expect, or otherwise it will all break apart.

Now because this old "$IRT" table can not normally be recognized anyway, 
I've converted the data to a more reasonable $PIR format, translating 
0x10-0x28-0x41-0x89 numbers into 1-2-3-4 along the way, and inserted 
this new table into a small unused ROM area. All looks good:
=====
[    0.623757] 8139too: 8139too Fast Ethernet driver 0.9.28
[    0.623757] 8139too 0000:00:03.0: PCI INT A -> PIRQ 01, mask def8, 
excl 0000
[    0.623757] 8139too 0000:00:03.0: PCI INT A -> newirq 11
[    0.623757] PCI: setting IRQ 11 as level-triggered
=====
Dumping registers with a separate program then confirmed that settings 
are correct indeed.
But I'd like to note that PIRQ values passed to pirq_finali_get/set 
should better be somewhow checked for validity, as otherwise some 
totally unrelated chipset registers are being unintentionally accessed.

I'm now going to test IRQ sharing.


Thank you,

Regards,
Nikolai


> [ 0.630068] 8139too 0000:00:03.0: IRQ routing conflict: have IRQ 11,
> want IRQ 15
> [ 0.641901] 8139too 0000:00:03.0 eth0: RealTek RTL8139 at 0xc2582f00,
> 00:11:6b:32:85:74, IRQ 11
>
> First, INTA is apparently routed to IRQ11 (and the network card works
> just fine with that), whereas pci code wants IRQ15 for some reason.
>
> Second, dumping chipset reg 44 shows that INTA is still set to EDGE mode
> anyway, although dumping port 4D1 now shows IRQ15 was changed to LEVEL
> mode, exactly as indicated in the above output. I'm not sure, but the
> datasheet (page 77) seems to indicate that INTx mode set in reg 44
> should match the respective IRQx mode in port 4Dx (Although the ROM BIOS
> seems to only have code to change triggering mode in the 44 register and
> does not care about port 4Dx whatsoever, which kinda contradicts the
> datasheet)
>
> I'll do some more digging later, but any hints are appreciated anyway.
>
>
> Thank you,
>
> Regards,
> Nikolai
>
>>
>> I'm a little busy at the moment with other stuff and may not be able to
>> look into it properly right now. There may be no solution, not at least
>> an easy one. A DMI quirk is not possible, because:
>>
>> DMI not present or invalid.
>>
>> There is a PCI BIOS:
>>
>> PCI: PCI BIOS revision 2.10 entry at 0xf6f41, last bus=0
>>
>> however, so CONFIG_PCI_BIOS just might work. Please try that too, by
>> choosing CONFIG_PCI_GOANY or CONFIG_PCI_GOBIOS (it may break things
>> horribly though I imagine).
>>
>> Maciej
>>
>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-09-11 15:31       ` Nikolai Zhubr
@ 2021-09-12 16:51         ` Nikolai Zhubr
  0 siblings, 0 replies; 16+ messages in thread
From: Nikolai Zhubr @ 2021-09-12 16:51 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Bjorn Helgaas, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, x86, linux-pci

Hello Maciej,

11.09.2021 18:31, I wrote:
> this new table into a small unused ROM area. All looks good:
> =====
> [ 0.623757] 8139too: 8139too Fast Ethernet driver 0.9.28
> [ 0.623757] 8139too 0000:00:03.0: PCI INT A -> PIRQ 01, mask def8, excl
> 0000
> [ 0.623757] 8139too 0000:00:03.0: PCI INT A -> newirq 11
> [ 0.623757] PCI: setting IRQ 11 as level-triggered
> =====
> Dumping registers with a separate program then confirmed that settings
> are correct indeed.
> But I'd like to note that PIRQ values passed to pirq_finali_get/set
> should better be somewhow checked for validity, as otherwise some
> totally unrelated chipset registers are being unintentionally accessed.
>
> I'm now going to test IRQ sharing.

I can confirm IRQ sharing works fine, too.
I've inserted some PCI USB addon card and added "pci=usepirqmask 
pci=irqmask=0x800" to force a collision, now /proc/interrups says:

11:      61350    XT-PIC      ehci_hcd:usb1, ohci_hcd:usb2, eth0

Now doing USB stick reading and ethernet benchmarking in parallel shows 
no problem whatsoever.

Excellent work, Maciej!


Thank you,

Regards,
Nikolai

>
> Thank you,
>
> Regards,
> Nikolai
>
>
>> [ 0.630068] 8139too 0000:00:03.0: IRQ routing conflict: have IRQ 11,
>> want IRQ 15
>> [ 0.641901] 8139too 0000:00:03.0 eth0: RealTek RTL8139 at 0xc2582f00,
>> 00:11:6b:32:85:74, IRQ 11
>>
>> First, INTA is apparently routed to IRQ11 (and the network card works
>> just fine with that), whereas pci code wants IRQ15 for some reason.
>>
>> Second, dumping chipset reg 44 shows that INTA is still set to EDGE mode
>> anyway, although dumping port 4D1 now shows IRQ15 was changed to LEVEL
>> mode, exactly as indicated in the above output. I'm not sure, but the
>> datasheet (page 77) seems to indicate that INTx mode set in reg 44
>> should match the respective IRQx mode in port 4Dx (Although the ROM BIOS
>> seems to only have code to change triggering mode in the 44 register and
>> does not care about port 4Dx whatsoever, which kinda contradicts the
>> datasheet)
>>
>> I'll do some more digging later, but any hints are appreciated anyway.
>>
>>
>> Thank you,
>>
>> Regards,
>> Nikolai
>>
>>>
>>> I'm a little busy at the moment with other stuff and may not be able to
>>> look into it properly right now. There may be no solution, not at least
>>> an easy one. A DMI quirk is not possible, because:
>>>
>>> DMI not present or invalid.
>>>
>>> There is a PCI BIOS:
>>>
>>> PCI: PCI BIOS revision 2.10 entry at 0xf6f41, last bus=0
>>>
>>> however, so CONFIG_PCI_BIOS just might work. Please try that too, by
>>> choosing CONFIG_PCI_GOANY or CONFIG_PCI_GOBIOS (it may break things
>>> horribly though I imagine).
>>>
>>> Maciej
>>>
>>
>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-09-07 14:42     ` Nikolai Zhubr
  2021-09-11 15:31       ` Nikolai Zhubr
@ 2021-09-14  9:24       ` Maciej W. Rozycki
  2021-09-16  0:25         ` Nikolai Zhubr
  1 sibling, 1 reply; 16+ messages in thread
From: Maciej W. Rozycki @ 2021-09-14  9:24 UTC (permalink / raw)
  To: Nikolai Zhubr
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Bjorn Helgaas, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, x86, linux-pci

Hello Nikolai,

> There is no "$PIR" signature anywhere, including all uncompressed internal ROM
> modules. Instead though, there is an "$IRT" signature and a table following
> it:
> 
> F9A90: 24 49 52 54 04 04 00 00 00 18 10 F8 DE 28 F8 DE │ $IRT
> F9AA0: 41 F8 DE 89 F8 DE 01 00 00 20 28 F8 DE 41 F8 DE │
> F9AB0: 89 F8 DE 10 F8 DE 02 00 00 28 41 F8 DE 89 F8 DE │
> F9AC0: 10 F8 DE 28 F8 DE 03 00 00 08 89 F8 DE 10 F8 DE │
> F9AD0: 28 F8 DE 41 F8 DE 04 00 00 09 03 0A 04 05 07 06 │
> F9AE0: 00 0B 00 0C 00 0E 00 0F 60 1E 0E 1F E8 98 00 8B │
> F9AF0: FA 1F 72 6B 0A C0 74 67 3C F0 73 45 8A C8 24 01 │
> 
> By stepping through some BIOS initialization code in bochs, I've determined
> that this table is being consulted just before modifying chipset registers 44
> and 42/43, so no doubt it is related to IRQs.

 IRT clearly must stand for Interrupt (or IRQ) Routing Table.

 Would you be able to share a disassembly of the piece of BIOS code in 
question?  I can read x86 assembly, so maybe the interpretation of the 
10/28/41/89 cookie can be inferred from it.  The high nibble looks 
remarkably like a bit lane selector and swizzling is clearly visible, but 
I fail to guess the algorithm from this pattern.  Given that the PIRQ 
routing handler is chipset-specific we could try interpreting just the 
high nibble, but would it work for the next system with the same chipset?

 Also who is the BIOS vendor?  Maybe they would be able to tell us 
something about the "$IRT" BIOS service.

> [    0.625911] 8139too 0000:00:03.0: runtime IRQ mapping not provided by arch
> [    0.625911] 8139too: 8139too Fast Ethernet driver 0.9.28
> [    0.625911] 8139too 0000:00:03.0: PCI INT A -> PIRQ 10, mask def8, excl
> 0000
> [    0.625911] 8139too 0000:00:03.0: PCI INT A -> newirq 11
> [    0.630068] PCI: setting IRQ 15 as level-triggered
> [    0.630068]  -> edge
> [    0.630068] 8139too 0000:00:03.0: found PCI INT A -> IRQ 15
> [    0.630068] 8139too 0000:00:03.0: IRQ routing conflict: have IRQ 11, want
> IRQ 15
> [    0.641901] 8139too 0000:00:03.0 eth0: RealTek RTL8139 at 0xc2582f00,
> 00:11:6b:32:85:74, IRQ 11
> 
> First, INTA is apparently routed to IRQ11 (and the network card works just
> fine with that), whereas pci code wants IRQ15 for some reason.

 Well, "PCI INT A -> PIRQ 10" cannot be right, the config register at 0x10 
is DRAM Configuration Register I and has nothing to do with PIRQ routing 
(you must have been lucky the system did not lock up).

> Second, dumping chipset reg 44 shows that INTA is still set to EDGE mode
> anyway, although dumping port 4D1 now shows IRQ15 was changed to LEVEL mode,
> exactly as indicated in the above output. I'm not sure, but the datasheet
> (page 77) seems to indicate that INTx mode set in reg 44 should match the
> respective IRQx mode in port 4Dx (Although the ROM BIOS seems to only have
> code to change triggering mode in the 44 register and does not care about port
> 4Dx whatsoever, which kinda contradicts the datasheet)

 Datasheets are not always right, but this one is the best source we have 
for this chipset.

  Maciej

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates
  2021-09-14  9:24       ` Maciej W. Rozycki
@ 2021-09-16  0:25         ` Nikolai Zhubr
  0 siblings, 0 replies; 16+ messages in thread
From: Nikolai Zhubr @ 2021-09-16  0:25 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
	Bjorn Helgaas, Rafael J. Wysocki, Len Brown, Pavel Machek,
	Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, x86, linux-pci

Hello Maciej,

14.09.2021 12:24, Maciej W. Rozycki:
>   Would you be able to share a disassembly of the piece of BIOS code in
> question?  I can read x86 assembly, so maybe the interpretation of the
> 10/28/41/89 cookie can be inferred from it.  The high nibble looks
> remarkably like a bit lane selector and swizzling is clearly visible, but

Ok, I've solved the puzzle.
High nibble is a ready-to-use bitmask for chipset reg 0x44 (so indeed, 
it is 1 << X).
Now, in low nibble, bit 0 selects one of two (0x42 or 0x43) chipset 
registers and further bit 3 selects one of two halves, and bits 1 and 2 
are apparently ignored. So actually, 10-28-41-89 is then just a freaky 
representation of simple 1-2-3-4 numbering. Good news it is exactly the 
numbering I chose when converting from $IRT to the supported $PIR 
format, and then it just worked (Some more details about my testing with 
this converted table where reported in my followup messages a bit 
earlier, you have probably seen them already).

Here is the relevant code with my remarks:

f9c1d: test al, 0x01 // Here AL bit 0 = Edge/Level CMOS setting.
f9c1f: pushf
f9c20: mov ah, dh // Here DH = PIRQ from $IRT table.
f9c22: shr ah, 4 // PIRQ's high nibble is a mask to set/clr E/L bit in 
reg 44 (1 << X)
f9c25: mov al, 0x44  // AH is ignored.
f9c27: call read_chipset_reg_AL // Register value returned in AL
f9c2a: or al, ah
f9c2c: popf
f9c2d: jnz .+4 (9c33)
f9c2f: not ah
f9c31: and al, ah
f9c33: mov ah, al
f9c35: mov al, 0x44 // Write AH to chipset register number 0x44.
f9c37: call write_chipset_reg_AL
f9c3a: mov al, 0x42
f9c3c: mov ah, dh
f9c3e: and ah, 0x01
f9c41: add al, ah    // PIRQ's bit 0 is reg 42/43 selector (X >> 1)
f9c43: mov ah, al    // AH is ignored
f9c45: call read_chipset_reg_AL // Register value returned in AL
f9c48: test dh, 0x08 // PIRQ's bit 3 is reg's nibble selector (X & 1)
f9c4b: jz .+3 (9c50) // Here 0 value selects lower nibble.
f9c4d: ror al, 0x04
f9c50: and al, 0xf0
f9c52: or al, dl     // Here DL contains wanted IRQ number to set.
f9c54: test dh, 0x08
f9c57: jz.+3 (9c5c)
f9c59: ror al, 0x04
f9c5c: xchg ah, al
f9c5e: call write_chipset_reg_AL

> I fail to guess the algorithm from this pattern.  Given that the PIRQ
> routing handler is chipset-specific we could try interpreting just the
> high nibble, but would it work for the next system with the same chipset?

This is certainly unclear. However, 10-28-41-89 can be arithmetically 
verified for consistency against the numbering scheme described above. 
So a respective test could be added somewhere. Also, prime numbers 1 to 
4 could probably be treated as valid numbering, too. Everything else 
should probably be refused unless some other numbering scheme pops up.

>   Also who is the BIOS vendor?  Maybe they would be able to tell us
> something about the "$IRT" BIOS service.

It is some regular AMIBIOS (American Megatrends) from 486 era, for 
EXP8449 motherboard, here is a manual I found for it:

https://www.elhvb.com/mobokive/Archive/Oldman.ixbt.com/mb/Expertboard_8449/exp84491.pdf 


>   Datasheets are not always right, but this one is the best source we have
> for this chipset.

Well, my testing has shown that practically, with your patch all works 
fine, including IRQ sharing. So other than this unclear numbering 
problem, I think it can be considered correct and usefull.


Thank you,

Regards,
Nikolai

>
>    Maciej
>


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-09-16  0:11 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-20  3:27 [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Maciej W. Rozycki
2021-07-20  3:27 ` [PATCH 1/6] x86: Add support for 0x22/0x23 port I/O configuration space Maciej W. Rozycki
2021-07-20  3:27 ` [PATCH 2/6] x86/PCI: Add support for the ALi M1487 (IBC) PIRQ router Maciej W. Rozycki
2021-07-20  3:27 ` [PATCH 3/6] x86/PCI: Add support for the Intel 82374EB/82374SB (ESC) " Maciej W. Rozycki
2021-07-20  3:28 ` [PATCH 4/6] x86/PCI: Add support for the Intel 82426EX " Maciej W. Rozycki
2021-07-20  3:28 ` [PATCH 5/6] x86: Avoid magic number with ELCR register accesses Maciej W. Rozycki
2021-07-20  3:28 ` [PATCH 6/6] x86: Fix typo s/ECLR/ELCR/ for the PIC register Maciej W. Rozycki
2021-07-21  0:12 ` [PATCH 0/6] x86: PIRQ/ELCR-related fixes and updates Bjorn Helgaas
2021-07-21 20:41   ` Thomas Gleixner
2021-08-15 22:22 ` Nikolai Zhubr
2021-08-16 22:30   ` Maciej W. Rozycki
2021-09-07 14:42     ` Nikolai Zhubr
2021-09-11 15:31       ` Nikolai Zhubr
2021-09-12 16:51         ` Nikolai Zhubr
2021-09-14  9:24       ` Maciej W. Rozycki
2021-09-16  0:25         ` Nikolai Zhubr

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).