Skip to contentSkip to conversation

x86: Add a function to assign IRQ numbers to PCI device

PATCH Superseded Bin Meng 2 participants 11 messages Apr 22, 2015 – Apr 24, 2015 1 message not in the archive x86

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Bin Meng

author
#1 lore raw

PATCH 1/4 x86: Add a function to assign IRQ numbers to PCI device

Add a function to assign an IRQ number to PCI device's interrupt line register in its configuration space, so that the PCI device can have its interrupt working under PIC mode after OS boots up.

---

 arch/x86/cpu/pci.c         | 21 +++++++++++++++++++++
 arch/x86/include/asm/pci.h | 14 ++++++++++++++
 2 files changed, 35 insertions(+)
arch/x86/cpu/pci.c +21 -0
index e23b233..c209f15 100644
@@ -151,3 +151,24 @@ int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset,
 
 	return 0;
 }
+
+void pci_assign_irqs(int bus, int device, int func, u8 irq[4])
+{
+	pci_dev_t bdf;
+	u8 pin, line;
+
+	bdf = PCI_BDF(bus, device, func);
+
+	pin = x86_pci_read_config8(bdf, PCI_INTERRUPT_PIN);
+
+	/* PCI spec says all values except 1..4 are reserved */
+	if ((pin < 1) || (pin > 4))
+		return;
+
+	line = irq[pin - 1];
+
+	debug("Assigning IRQ %d to PCI device %d.%x.%d (INT%c)\n",
+	      line, bus, device, func, 'A' + pin - 1);
+
+	x86_pci_write_config8(bdf, PCI_INTERRUPT_LINE, line);
+}
arch/x86/include/asm/pci.h +14 -0
index a1969ed..56eaa25 100644
@@ -64,6 +64,20 @@ int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset,
 int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset,
 			 ulong value, enum pci_size_t size);
 
+/**
+ * Assign IRQ number to a PCI device
+ *
+ * This function assigns IRQ for a PCI device. If the device does not exist
+ * or does not require interrupts then this function has no effect.
+ *
+ * @bus:	PCI bus number
+ * @device:	PCI device number
+ * @func:	PCI function number
+ * @irq:	An array of IRQ numbers that are assigned to INTA through
+ *		INTD of this PCI device.
+ */
+void pci_assign_irqs(int bus, int device, int func, u8 irq[4]);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _PCI_I386_H_ */
Signature · 1 line
1.8.2.1
#2 lore raw

PATCH 1/4 x86: Add a function to assign IRQ numbers to PCI device

Quoted 10 lines · Bin Meng

Add a function to assign an IRQ number to PCI device's interrupt line register in its configuration space, so that the PCI device can have its interrupt working under PIC mode after OS boots up.

---

 arch/x86/cpu/pci.c         | 21 +++++++++++++++++++++
 arch/x86/include/asm/pci.h | 14 ++++++++++++++
 2 files changed, 35 insertions(+)
author
#3 lore raw

PATCH 2/4 x86: Write configuration tables in last_stage_init()

In reply to a message not in the archive

We can write the configuration table in last_stage_init() for all x86 boards, but not with coreboot since coreboot already has them.

---

 arch/x86/cpu/cpu.c            | 10 +++++++++
 arch/x86/include/asm/tables.h | 49 +++++++++++++++++++++++++++++++++++++++++++
 arch/x86/lib/Makefile         |  1 +
 arch/x86/lib/tables.c         | 30 ++++++++++++++++++++++++++
 include/configs/x86-common.h  |  1 +
 5 files changed, 91 insertions(+)
 create mode 100644 arch/x86/include/asm/tables.h
 create mode 100644 arch/x86/lib/tables.c
arch/x86/cpu/cpu.c +10 -0
index a9ca50b..c9614f1 100644
@@ -29,6 +29,7 @@
 #include <asm/processor.h>
 #include <asm/processor-flags.h>
 #include <asm/interrupt.h>
+#include <asm/tables.h>
 #include <linux/compiler.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -593,3 +594,12 @@ void show_boot_progress(int val)
 #endif
 	outb(val, POST_PORT);
 }
+
+#ifndef CONFIG_SYS_COREBOOT
+int last_stage_init(void)
+{
+	write_tables();
+
+	return 0;
+}
+#endif
arch/x86/include/asm/tables.h new file +49 -0

49 lines not on this page · raw message

arch/x86/lib/Makefile +1 -0
index e49de05..0de0d89 100644
@@ -26,6 +26,7 @@ obj-y	+= relocate.o
 obj-y += physmem.o
 obj-$(CONFIG_X86_RAMTEST) += ramtest.o
 obj-y	+= string.o
+obj-y	+= tables.o
 obj-$(CONFIG_SYS_X86_TSC_TIMER)	+= tsc_timer.o
 obj-$(CONFIG_CMD_ZBOOT)	+= zimage.o
 obj-$(CONFIG_HAVE_FSP) += fsp/
arch/x86/lib/tables.c new file +30 -0
new file mode 100644
index 0000000..b390a4b
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015, Bin Meng <[email protected]>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/tables.h>
+
+u8 table_compute_checksum(void *v, int len)
+{
+	u8 *bytes = v;
+	u8 checksum = 0;
+	int i;
+
+	for (i = 0; i < len; i++)
+		checksum -= bytes[i];
+
+	return checksum;
+}
+
+void write_tables(void)
+{
+	u32 __maybe_unused rom_table_end = ROM_TABLE_ADDR;
+
+#if CONFIG_GENERATE_PIRQ_TABLE
+	rom_table_end = write_pirq_routing_table(rom_table_end);
+	rom_table_end = ALIGN(rom_table_end, 1024);
+#endif
+}
include/configs/x86-common.h +1 -0
index 07a5aca..3e21e09 100644
@@ -20,6 +20,7 @@
 #define CONFIG_PHYSMEM
 #define CONFIG_DISPLAY_BOARDINFO_LATE
 #define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_LAST_STAGE_INIT
 
 #define CONFIG_LMB
 #define CONFIG_OF_LIBFDT
Signature · 1 line
1.8.2.1
#4 lore raw

PATCH 2/4 x86: Write configuration tables in last_stage_init()

Quoted 6 lines · Bin Meng

We can write the configuration table in last_stage_init() for all x86 boards, but not with coreboot since coreboot already has them.

---

Quoted 8 lines
 arch/x86/cpu/cpu.c            | 10 +++++++++
 arch/x86/include/asm/tables.h | 49 +++++++++++++++++++++++++++++++++++++++++++
 arch/x86/lib/Makefile         |  1 +
 arch/x86/lib/tables.c         | 30 ++++++++++++++++++++++++++
 include/configs/x86-common.h  |  1 +
 5 files changed, 91 insertions(+)
 create mode 100644 arch/x86/include/asm/tables.h
 create mode 100644 arch/x86/lib/tables.c
author
#5 lore raw

PATCH 3/4 x86: Support platform PIRQ routing

In reply to a message not in the archive

On x86 boards, platform chipset receives up to four different interrupt signals from PCI devices (INTA/B/C/D), which in turn will be routed to chipset internal PIRQ lines then routed to 8259 PIC finally if configuring the whole system to work under the so-called PIC mode (in contrast to symmetric IO mode which uses IOAPIC).

We add two major APIs to aid this, one for routing PIRQ and the other one for generating a PIRQ routing table.

---

 arch/x86/Kconfig                    |  31 ++++++++
 arch/x86/include/asm/pirq_routing.h | 139 ++++++++++++++++++++++++++++++++++++
 arch/x86/lib/Makefile               |   1 +
 arch/x86/lib/pirq_routing.c         | 129 +++++++++++++++++++++++++++++++++
 4 files changed, 300 insertions(+)
 create mode 100644 arch/x86/include/asm/pirq_routing.h
 create mode 100644 arch/x86/lib/pirq_routing.c
arch/x86/Kconfig +31 -0
index 3f1401a..aaceaef 100644
@@ -442,6 +442,37 @@ config TSC_FREQ_IN_MHZ
 	help
 	  The running frequency in MHz of Time-Stamp Counter (TSC).
 
+menu "System tables"
+
+config GENERATE_PIRQ_TABLE
+	bool "Generate a PIRQ table"
+	default n
+	help
+	  Generate a PIRQ routing table for this board. The PIRQ routing table
+	  is generated by U-Boot in the system memory from 0xf0000 to 0xfffff
+	  at every 16-byte boundary with a PCI IRQ routing signature ("$PIR").
+	  It specifies the interrupt router information as well how all the PCI
+	  devices' interrupt pins are wired to PIRQs.
+
+endmenu
+
+config MAX_PIRQ_LINKS
+	int
+	default 8
+	help
+	  This variable specifies the number of PIRQ interrupt links which are
+	  routable. On most older chipsets, this is 4, PIRQA through PIRQD.
+	  Some newer chipsets offer more than four links, commonly up to PIRQH.
+
+config IRQ_SLOT_COUNT
+	int
+	default 128
+	help
+	  U-Boot can support up to 254 IRQ slot info in the PIRQ routing table
+	  which in turns forms a table of exact 4KiB. The default value 128
+	  should be enough for most boards. If this does not fit your board,
+	  change it according to your needs.
+
 source "board/coreboot/coreboot/Kconfig"
 
 source "board/google/chromebook_link/Kconfig"
arch/x86/include/asm/pirq_routing.h new file +139 -0

139 lines not on this page · raw message

arch/x86/lib/Makefile +1 -0
index 0de0d89..0178fe1 100644
@@ -22,6 +22,7 @@ ifndef CONFIG_DM_PCI
 obj-$(CONFIG_PCI) += pci_type1.o
 endif
 obj-y	+= pch-uclass.o
+obj-y	+= pirq_routing.o
 obj-y	+= relocate.o
 obj-y += physmem.o
 obj-$(CONFIG_X86_RAMTEST) += ramtest.o
arch/x86/lib/pirq_routing.c new file +129 -0

129 lines not on this page · raw message

Signature · 1 line
1.8.2.1
#6 lore raw

PATCH 3/4 x86: Support platform PIRQ routing

Quoted 13 lines · Bin Meng

On x86 boards, platform chipset receives up to four different interrupt signals from PCI devices (INTA/B/C/D), which in turn will be routed to chipset internal PIRQ lines then routed to 8259 PIC finally if configuring the whole system to work under the so-called PIC mode (in contrast to symmetric IO mode which uses IOAPIC).

We add two major APIs to aid this, one for routing PIRQ and the other one for generating a PIRQ routing table.

---

Quoted 7 lines
 arch/x86/Kconfig                    |  31 ++++++++
 arch/x86/include/asm/pirq_routing.h | 139 ++++++++++++++++++++++++++++++++++++
 arch/x86/lib/Makefile               |   1 +
 arch/x86/lib/pirq_routing.c         | 129 +++++++++++++++++++++++++++++++++
 4 files changed, 300 insertions(+)
 create mode 100644 arch/x86/include/asm/pirq_routing.h
 create mode 100644 arch/x86/lib/pirq_routing.c
author
#7 lore raw

PATCH 4/4 x86: queensbay: Implement PIRQ routing

In reply to a message not in the archive

Implement Intel Queensbay platform-specific PIRQ routing support. The chipset PIRQ routing setup is called in the arch_mist_init().

---

 arch/x86/cpu/queensbay/Makefile              |   2 +-
 arch/x86/cpu/queensbay/irq.c                 | 236 +++++++++++++++++++++++++++
 arch/x86/cpu/queensbay/tnc.c                 |  10 +-
 arch/x86/include/asm/arch-queensbay/device.h |  94 +++++++++++
 arch/x86/include/asm/arch-queensbay/irq.h    |  55 +++++++
 arch/x86/include/asm/arch-queensbay/tnc.h    |  26 ++-
 arch/x86/include/asm/u-boot-x86.h            |   2 +
 configs/crownbay_defconfig                   |   1 +
 include/configs/crownbay.h                   |   1 +
 9 files changed, 423 insertions(+), 4 deletions(-)
 create mode 100644 arch/x86/cpu/queensbay/irq.c
 create mode 100644 arch/x86/include/asm/arch-queensbay/device.h
 create mode 100644 arch/x86/include/asm/arch-queensbay/irq.h
arch/x86/cpu/queensbay/Makefile +1 -1
index d8761fd..4599a48 100644
@@ -5,5 +5,5 @@
 #
 
 obj-y += fsp_configs.o
-obj-y += tnc.o topcliff.o
+obj-y += irq.o tnc.o topcliff.o
 obj-$(CONFIG_PCI) += tnc_pci.o
arch/x86/cpu/queensbay/irq.c new file +236 -0

236 lines not on this page · raw message

arch/x86/cpu/queensbay/tnc.c +9 -1
index f756a0d..b46a7e9 100644
@@ -8,7 +8,8 @@
 #include <asm/io.h>
 #include <asm/pci.h>
 #include <asm/post.h>
-#include <asm/arch/tnc.h>
+#include <asm/arch/device.h>
+#include <asm/arch/irq.h>
 #include <asm/fsp/fsp_support.h>
 #include <asm/processor.h>
 
@@ -43,3 +44,10 @@ int arch_cpu_init(void)
 
 	return 0;
 }
+
+int arch_misc_init(void)
+{
+	pirq_init();
+
+	return 0;
+}
arch/x86/include/asm/arch-queensbay/device.h new file +94 -0

94 lines not on this page · raw message

arch/x86/include/asm/arch-queensbay/irq.h new file +55 -0

55 lines not on this page · raw message

arch/x86/include/asm/arch-queensbay/tnc.h +24 -2
index 10ea51d..2535fe8 100644
@@ -7,8 +7,30 @@
 #ifndef _X86_ARCH_TNC_H_
 #define _X86_ARCH_TNC_H_
 
-#include <pci.h>
+/* Memory BAR Enable */
+#define MEM_BAR_EN	0x00000001
 
-#define TNC_LPC		PCI_BDF(0, 31, 0)
+/* LPC PCI Configuration Registers */
+#define LPC_RCBA	0xf0
+
+/* Interupt Pin Configuration (in RCBA) */
+#define D02IP		0x3118
+#define D03IP		0x3130
+#define D23IP		0x312c
+#define D24IP		0x3128
+#define D25IP		0x3124
+#define D26IP		0x3120
+#define D27IP		0x3110
+#define D31IP		0x3100
+
+/* Interupt Route Configuration (in RCBA) */
+#define D02IR		0x3160
+#define D03IR		0x3162
+#define D23IR		0x3150
+#define D24IR		0x314e
+#define D25IR		0x314c
+#define D26IR		0x314a
+#define D27IR		0x3148
+#define D31IR		0x3140
 
 #endif /* _X86_ARCH_TNC_H_ */
arch/x86/include/asm/u-boot-x86.h +2 -0
index c743efd..122e054 100644
@@ -53,6 +53,8 @@ int video_bios_init(void);
 void	board_init_f_r_trampoline(ulong) __attribute__ ((noreturn));
 void	board_init_f_r(void) __attribute__ ((noreturn));
 
+int arch_misc_init(void);
+
 /* Read the time stamp counter */
 static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)
 {
configs/crownbay_defconfig +1 -0
index ce90553..47763f9 100644
@@ -4,3 +4,4 @@ CONFIG_TARGET_CROWNBAY=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_SEPARATE=y
 CONFIG_DEFAULT_DEVICE_TREE="crownbay"
+CONFIG_GENERATE_PIRQ_TABLE=y
include/configs/crownbay.h +1 -0
index 42042d1..4fef433 100644
@@ -15,6 +15,7 @@
 
 #define CONFIG_SYS_MONITOR_LEN		(1 << 20)
 #define CONFIG_BOARD_EARLY_INIT_F
+#define CONFIG_ARCH_MISC_INIT
 
 #define CONFIG_NR_DRAM_BANKS		1
 
Signature · 1 line
1.8.2.1
#8 lore raw

PATCH 4/4 x86: queensbay: Implement PIRQ routing

Hi Bin,

Quoted 2 lines · Bin Meng

Implement Intel Queensbay platform-specific PIRQ routing support. The chipset PIRQ routing setup is called in the arch_mist_init().

arch_misc_init()?

Also how can this be used on other boards? Should part of this code be moved to a generic place?

Quoted 77 lines

---

 arch/x86/cpu/queensbay/Makefile              |   2 +-
 arch/x86/cpu/queensbay/irq.c                 | 236 +++++++++++++++++++++++++++
 arch/x86/cpu/queensbay/tnc.c                 |  10 +-
 arch/x86/include/asm/arch-queensbay/device.h |  94 +++++++++++
 arch/x86/include/asm/arch-queensbay/irq.h    |  55 +++++++
 arch/x86/include/asm/arch-queensbay/tnc.h    |  26 ++-
 arch/x86/include/asm/u-boot-x86.h            |   2 +
 configs/crownbay_defconfig                   |   1 +
 include/configs/crownbay.h                   |   1 +
 9 files changed, 423 insertions(+), 4 deletions(-)
 create mode 100644 arch/x86/cpu/queensbay/irq.c
 create mode 100644 arch/x86/include/asm/arch-queensbay/device.h
 create mode 100644 arch/x86/include/asm/arch-queensbay/irq.h
arch/x86/cpu/queensbay/Makefile +1 -1
index d8761fd..4599a48 100644
@@ -5,5 +5,5 @@
 #
 
 obj-y += fsp_configs.o
-obj-y += tnc.o topcliff.o
+obj-y += irq.o tnc.o topcliff.o
 obj-$(CONFIG_PCI) += tnc_pci.o
arch/x86/cpu/queensbay/irq.c new file +41 -0
new file mode 100644
index 0000000..cf433d3
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2015, Bin Meng <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/post.h>
+#include <asm/processor.h>
+#include <asm/pirq_routing.h>
+#include <asm/arch/device.h>
+#include <asm/arch/tnc.h>
+#include <asm/arch/irq.h>
+
+static struct irq_routing_table *pirq_routing_table;
+
+bool pirq_check_irq_routed(int link, u8 irq)
+{
+       u8 pirq;
+
+       pirq = x86_pci_read_config8(TNC_LPC, LINK_N2V(link));
+       pirq &= 0xf;
+
+       /* IRQ# 0/1/2/8/13 are reserved */
+       if (pirq < 3 || pirq == 8 || pirq == 13)
+               return false;
+
+       return pirq == irq ? true : false;
+}
+
+int pirq_translate_link(int link)
+{
+       return LINK_V2N(link);
+}
+
+void pirq_assign_irq(int link, u8 irq)
+{

arch/x86/cpu/queensbay/irq.c line 51

Quoted 10 lines
arch/x86/cpu/queensbay/irq.c new file +10 -0
+       /* IRQ# 0/1/2/8/13 are reserved */
+       if (irq < 3 || irq == 8 || irq == 13)
+               return;
+
+       x86_pci_write_config8(TNC_LPC, LINK_N2V(link), irq);
+}
+
+static inline void fill_irq_info(struct irq_info **slot, int *entries, u8 bus,
+                                u8 device, u8 func, u8 pin, u8 pirq)
+{

Please declare a local variable

struct irq_info *slot = *slotp;

and rename the param to slotp, to avoid the first four (*slot).

Quoted 123 lines
arch/x86/cpu/queensbay/irq.c new file +123 -0
+       (*slot)->bus = bus;
+       (*slot)->devfn = (device << 3) | func;
+       (*slot)->irq[pin - 1].link = LINK_N2V(pirq);
+       (*slot)->irq[pin - 1].bitmap = PIRQ_BITMAP;
+       (*entries)++;
+       (*slot)++;
+}
+
+/* PCIe port downstream INTx swizzle */
+static inline u8 pin_swizzle(u8 pin, int port)
+{
+       return (pin + port) % 4;
+}
+
+__weak int board_fill_irq_info(struct irq_info *slot)
+{
+       return 0;
+}
+
+static int create_pirq_routing_table(void)
+{
+       struct irq_routing_table *rt;
+       struct irq_info *slot;
+       int irq_entries = 0;
+       pci_dev_t tcf_bdf;
+       u8 tcf_bus, bus;
+       int i;
+
+       rt = malloc(sizeof(struct irq_routing_table));
+       if (!rt)
+               return -ENOMEM;
+       memset((char *)rt, 0, sizeof(struct irq_routing_table));
+
+       /* Populate the PIRQ table fields */
+       rt->signature = PIRQ_SIGNATURE;
+       rt->version = PIRQ_VERSION;
+       rt->rtr_bus = 0;
+       rt->rtr_devfn = (TNC_LPC_DEV << 3) | TNC_LPC_FUNC;
+       rt->rtr_vendor = PCI_VENDOR_ID_INTEL;
+       rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31;
+
+       slot = rt->slots;
+
+       /*
+        * Now fill in the irq_info entries in the PIRQ table
+        *
+        * We start from internal TunnelCreek PCI devices first, then
+        * followed by all the 4 PCIe ports downstream devices, including
+        * the Queensbay platform Topcliff chipset devices.
+        */
+       fill_irq_info(&slot, &irq_entries, 0, TNC_IGD_DEV,
+                     TNC_IGD_FUNC, INTA, PIRQE);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_SDVO_DEV,
+                     TNC_SDVO_FUNC, INTA, PIRQF);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_HDA_DEV,
+                     TNC_HDA_FUNC, INTA, PIRQG);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE0_DEV,
+                     TNC_PCIE0_FUNC, INTA, PIRQE);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE1_DEV,
+                     TNC_PCIE1_FUNC, INTA, PIRQF);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE2_DEV,
+                     TNC_PCIE2_FUNC, INTA, PIRQG);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE3_DEV,
+                     TNC_PCIE3_FUNC, INTA, PIRQH);
+
+       /* Check which PCIe port the Topcliff chipset is connected to */
+       tcf_bdf = pci_find_device(PCI_VENDOR_ID_INTEL, 0x8800, 0);
+       tcf_bus = PCI_BUS(tcf_bdf);
+       for (i = 0; i < 4; i++) {
+               bus = x86_pci_read_config8(PCI_BDF(0, TNC_PCIE0_DEV + i, 0),
+                                          PCI_SECONDARY_BUS);
+               if (bus == tcf_bus)
+                       break;
+       }
+
+       /* Fill in the Topcliff chipset devices' irq info */
+       if (i < 4) {
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_PCIE_PORT_DEV,
+                             TCF_PCIE_PORT_FUNC, INTA, pin_swizzle(PIRQA, i));
+
+               tcf_bus++;
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_0,
+                             TCF_GBE_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_0,
+                             TCF_GPIO_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB1_OHCI0_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB1_OHCI1_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB1_OHCI2_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB1_EHCI_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB_DEVICE_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_4,
+                             TCF_SDIO0_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_4,
+                             TCF_SDIO1_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_6,
+                             TCF_SATA_FUNC, INTD, pin_swizzle(PIRQD, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+                             TCF_USB2_OHCI0_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+                             TCF_USB2_OHCI1_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+                             TCF_USB2_OHCI2_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+                             TCF_USB2_EHCI_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_DMA1_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_UART0_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_UART1_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_UART2_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_UART3_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_DMA2_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_SPI_FUNC, INTC, pin_swizzle(PIRQC, i));

arch/x86/cpu/queensbay/irq.c line 184

Quoted 10 lines
arch/x86/cpu/queensbay/irq.c new file +10 -0
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_I2C_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_CAN_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_1588_FUNC, INTC, pin_swizzle(PIRQC, i));
+       }
+
+       /* Call board-specific routine to fill in add-in card's irq info */
+       irq_entries += board_fill_irq_info(slot);

But isn't this already board-specific code?

Quoted 32 lines
arch/x86/cpu/queensbay/irq.c new file +32 -0
+
+       rt->size = irq_entries * sizeof(struct irq_info) + 32;
+
+       pirq_routing_table = rt;
+
+       return 0;
+}
+
+void pirq_init(void)
+{
+       u32 rcba;
+
+       rcba = x86_pci_read_config32(TNC_LPC, LPC_RCBA);
+       rcba &= ~MEM_BAR_EN;
+
+       /* Make sure all internal PCI devices are using INTA */
+       writel(INTA, rcba + D02IP);
+       writel(INTA, rcba + D03IP);
+       writel(INTA, rcba + D27IP);
+       writel(INTA, rcba + D31IP);
+       writel(INTA, rcba + D23IP);
+       writel(INTA, rcba + D24IP);
+       writel(INTA, rcba + D25IP);
+       writel(INTA, rcba + D26IP);
+
+       /*
+        * Route TunnelCreek PCI device interrupt pin to PIRQ
+        *
+        * Since PCIe downstream ports received INTx are routed to PIRQ
+        * A/B/C/D directly and not configurable, we route internal PCI
+        * device's INTx to PIRQ E/F/G/H.
+        */

arch/x86/cpu/queensbay/irq.c line 226

Quoted 10 lines
arch/x86/cpu/queensbay/irq.c new file +10 -0
+       writew(PIRQE, rcba + D02IR);
+       writew(PIRQF, rcba + D03IR);
+       writew(PIRQG, rcba + D27IR);
+       writew(PIRQH, rcba + D31IR);
+       writew(PIRQE, rcba + D23IR);
+       writew(PIRQF, rcba + D24IR);
+       writew(PIRQG, rcba + D25IR);
+       writew(PIRQH, rcba + D26IR);
+
+       if (!create_pirq_routing_table()) {

Can you add a comment here as to why you do this next bit if create_pirq_routing_table() fails?

Quoted 221 lines
arch/x86/cpu/queensbay/irq.c new file +10 -0
+               /* Route PIRQ */
+               pirq_route_irqs(pirq_routing_table->slots,
+                               get_irq_slot_count(pirq_routing_table));
+       }
+}
+
+u32 write_pirq_routing_table(u32 addr)
+{
+       return copy_pirq_routing_table(addr, pirq_routing_table);
+}
arch/x86/cpu/queensbay/tnc.c +9 -1
index f756a0d..b46a7e9 100644
@@ -8,7 +8,8 @@
 #include <asm/io.h>
 #include <asm/pci.h>
 #include <asm/post.h>
-#include <asm/arch/tnc.h>
+#include <asm/arch/device.h>
+#include <asm/arch/irq.h>
 #include <asm/fsp/fsp_support.h>
 #include <asm/processor.h>
 
@@ -43,3 +44,10 @@ int arch_cpu_init(void)
 
        return 0;
 }
+
+int arch_misc_init(void)
+{
+       pirq_init();
+
+       return 0;
+}
arch/x86/include/asm/arch-queensbay/device.h new file +94 -0
new file mode 100644
index 0000000..953b48f
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015, Bin Meng <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _QUEENSBAY_DEVICE_H_
+#define _QUEENSBAY_DEVICE_H_
+
+#include <pci.h>
+
+/* TunnelCreek PCI Devices */
+#define TNC_HOST_BRIDGE_DEV    0
+#define TNC_HOST_BRIDGE_FUNC   0
+#define TNC_IGD_DEV            2
+#define TNC_IGD_FUNC           0
+#define TNC_SDVO_DEV           3
+#define TNC_SDVO_FUNC          0
+#define TNC_PCIE0_DEV          23
+#define TNC_PCIE0_FUNC         0
+#define TNC_PCIE1_DEV          24
+#define TNC_PCIE1_FUNC         0
+#define TNC_PCIE2_DEV          25
+#define TNC_PCIE2_FUNC         0
+#define TNC_PCIE3_DEV          26
+#define TNC_PCIE3_FUNC         0
+#define TNC_HDA_DEV            27
+#define TNC_HDA_FUNC           0
+#define TNC_LPC_DEV            31
+#define TNC_LPC_FUNC           0
+
+#define TNC_HOST_BRIDGE                \
+       PCI_BDF(0, TNC_HOST_BRIDGE_DEV, TNC_HOST_BRIDGE_FUNC)
+#define TNC_IGD                        \
+       PCI_BDF(0, TNC_IGD_DEV, TNC_IGD_FUNC)
+#define TNC_SDVO               \
+       PCI_BDF(0, TNC_SDVO_DEV, TNC_SDVO_FUNC)
+#define TNC_PCIE0              \
+       PCI_BDF(0, TNC_PCIE0_DEV, TNC_PCIE0_FUNC)
+#define TNC_PCIE1              \
+       PCI_BDF(0, TNC_PCIE1_DEV, TNC_PCIE1_FUNC)
+#define TNC_PCIE2              \
+       PCI_BDF(0, TNC_PCIE2_DEV, TNC_PCIE2_FUNC)
+#define TNC_PCIE3              \
+       PCI_BDF(0, TNC_PCIE3_DEV, TNC_PCIE3_FUNC)
+#define TNC_HDA                        \
+       PCI_BDF(0, TNC_HDA_DEV, TNC_HDA_FUNC)
+#define TNC_LPC                        \
+       PCI_BDF(0, TNC_LPC_DEV, TNC_LPC_FUNC)
+
+/* Topcliff IOH PCI Devices */
+#define TCF_PCIE_PORT_DEV      0
+#define TCF_PCIE_PORT_FUNC     0
+
+#define TCF_DEV_0              0
+#define TCF_PKT_HUB_FUNC       0
+#define TCF_GBE_FUNC           1
+#define TCF_GPIO_FUNC          2
+
+#define TCF_DEV_2              2
+#define TCF_USB1_OHCI0_FUNC    0
+#define TCF_USB1_OHCI1_FUNC    1
+#define TCF_USB1_OHCI2_FUNC    2
+#define TCF_USB1_EHCI_FUNC     3
+#define TCF_USB_DEVICE_FUNC    4
+
+#define TCF_DEV_4              4
+#define TCF_SDIO0_FUNC         0
+#define TCF_SDIO1_FUNC         1
+
+#define TCF_DEV_6              6
+#define TCF_SATA_FUNC          0
+
+#define TCF_DEV_8              8
+#define TCF_USB2_OHCI0_FUNC    0
+#define TCF_USB2_OHCI1_FUNC    1
+#define TCF_USB2_OHCI2_FUNC    2
+#define TCF_USB2_EHCI_FUNC     3
+
+#define TCF_DEV_10             10
+#define TCF_DMA1_FUNC          0
+#define TCF_UART0_FUNC         1
+#define TCF_UART1_FUNC         2
+#define TCF_UART2_FUNC         3
+#define TCF_UART3_FUNC         4
+
+#define TCF_DEV_12             12
+#define TCF_DMA2_FUNC          0
+#define TCF_SPI_FUNC           1
+#define TCF_I2C_FUNC           2
+#define TCF_CAN_FUNC           3
+#define TCF_1588_FUNC          4
+
+#endif /* _QUEENSBAY_DEVICE_H_ */
arch/x86/include/asm/arch-queensbay/irq.h new file +55 -0
new file mode 100644
index 0000000..e7f8616
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015, Bin Meng <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ARCH_IRQ_H_
+#define _ARCH_IRQ_H_
+
+enum pci_int_pin {
+       INTX,
+       INTA,
+       INTB,
+       INTC,
+       INTD
+};
+
+enum pirq_pin {
+       PIRQA,
+       PIRQB,
+       PIRQC,
+       PIRQD,
+       PIRQE,
+       PIRQF,
+       PIRQG,
+       PIRQH
+};
+
+/* PIRQ link number and value conversion */
+#define LINK_V2N(link) (link - 0x60)
+#define LINK_N2V(link) (link + 0x60)
+
+#define PIRQ_BITMAP    0xdee0
+
+struct irq_info;
+
+/**
+ * board_fill_irq_info() - Board-specific irq_info fill routine
+ *
+ * This fills the irq_info table for any board-specific add-in cards.
+ *
+ * @slot:      pointer to the struct irq_info that is to be filled in
+ * @return:    number of entries were written to the struct irq_info
+ */
+int board_fill_irq_info(struct irq_info *slot);
+
+/**
+ * pirq_init() - Initialize platform PIRQ routing
+ *
+ * This initializes the PIRQ routing on the platform and configures all PCI
+ * devices' interrupt line register to a working IRQ number on the 8259 PIC.
+ */
+void pirq_init(void);
+
+#endif /* _ARCH_IRQ_H_ */
arch/x86/include/asm/arch-queensbay/tnc.h +14 -2
index 10ea51d..2535fe8 100644
@@ -7,8 +7,30 @@
 #ifndef _X86_ARCH_TNC_H_
 #define _X86_ARCH_TNC_H_
 
-#include <pci.h>
+/* Memory BAR Enable */
+#define MEM_BAR_EN     0x00000001
 
-#define TNC_LPC                PCI_BDF(0, 31, 0)
+/* LPC PCI Configuration Registers */
+#define LPC_RCBA       0xf0
+
+/* Interupt Pin Configuration (in RCBA) */
+#define D02IP          0x3118
+#define D03IP          0x3130
+#define D23IP          0x312c
+#define D24IP          0x3128
+#define D25IP          0x3124
+#define D26IP          0x3120
+#define D27IP          0x3110
+#define D31IP          0x3100

arch/x86/include/asm/arch-queensbay/tnc.h line 34

Quoted 10 lines
arch/x86/include/asm/arch-queensbay/tnc.h +10 -0
+
+/* Interupt Route Configuration (in RCBA) */
+#define D02IR          0x3160
+#define D03IR          0x3162
+#define D23IR          0x3150
+#define D24IR          0x314e
+#define D25IR          0x314c
+#define D26IR          0x314a
+#define D27IR          0x3148
+#define D31IR          0x3140

Can we use a C structure for the RCBA, or part of it?

Quoted 37 lines
arch/x86/include/asm/arch-queensbay/tnc.h +0 -0
 #endif /* _X86_ARCH_TNC_H_ */
arch/x86/include/asm/u-boot-x86.h +2 -0
index c743efd..122e054 100644
@@ -53,6 +53,8 @@ int video_bios_init(void);
 void   board_init_f_r_trampoline(ulong) __attribute__ ((noreturn));
 void   board_init_f_r(void) __attribute__ ((noreturn));
 
+int arch_misc_init(void);
+
 /* Read the time stamp counter */
 static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)
 {
configs/crownbay_defconfig +1 -0
index ce90553..47763f9 100644
@@ -4,3 +4,4 @@ CONFIG_TARGET_CROWNBAY=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_SEPARATE=y
 CONFIG_DEFAULT_DEVICE_TREE="crownbay"
+CONFIG_GENERATE_PIRQ_TABLE=y
include/configs/crownbay.h +1 -1
index 42042d1..4fef433 100644
@@ -15,6 +15,7 @@
 
 #define CONFIG_SYS_MONITOR_LEN         (1 << 20)
 #define CONFIG_BOARD_EARLY_INIT_F
+#define CONFIG_ARCH_MISC_INIT
 
 #define CONFIG_NR_DRAM_BANKS           1
 
--
Quoted 2 lines

1.8.2.1

Regards,
Simon

author
#9 lore raw

PATCH 4/4 x86: queensbay: Implement PIRQ routing

Hi Simon,

Quoted 7 lines · Simon Glass

Hi Bin,

Quoted 2 lines · Bin Meng

Implement Intel Queensbay platform-specific PIRQ routing support. The chipset PIRQ routing setup is called in the arch_mist_init().

arch_misc_init()?

Will fix.

Quoted 2 lines

Also how can this be used on other boards? Should part of this code be moved to a generic place?

Generally Intel interrupt router should be compatible, but the offsets of these interrupt routing registers might be different from platform to platform. The platform-specific part is the internal PCI devices' interrupt pin to PIRQ map.

Quoted 90 lines
Quoted 77 lines

---

 arch/x86/cpu/queensbay/Makefile              |   2 +-
 arch/x86/cpu/queensbay/irq.c                 | 236 +++++++++++++++++++++++++++
 arch/x86/cpu/queensbay/tnc.c                 |  10 +-
 arch/x86/include/asm/arch-queensbay/device.h |  94 +++++++++++
 arch/x86/include/asm/arch-queensbay/irq.h    |  55 +++++++
 arch/x86/include/asm/arch-queensbay/tnc.h    |  26 ++-
 arch/x86/include/asm/u-boot-x86.h            |   2 +
 configs/crownbay_defconfig                   |   1 +
 include/configs/crownbay.h                   |   1 +
 9 files changed, 423 insertions(+), 4 deletions(-)
 create mode 100644 arch/x86/cpu/queensbay/irq.c
 create mode 100644 arch/x86/include/asm/arch-queensbay/device.h
 create mode 100644 arch/x86/include/asm/arch-queensbay/irq.h
arch/x86/cpu/queensbay/Makefile +1 -1
index d8761fd..4599a48 100644
@@ -5,5 +5,5 @@
 #
 
 obj-y += fsp_configs.o
-obj-y += tnc.o topcliff.o
+obj-y += irq.o tnc.o topcliff.o
 obj-$(CONFIG_PCI) += tnc_pci.o
arch/x86/cpu/queensbay/irq.c new file +41 -0
new file mode 100644
index 0000000..cf433d3
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2015, Bin Meng <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <asm/post.h>
+#include <asm/processor.h>
+#include <asm/pirq_routing.h>
+#include <asm/arch/device.h>
+#include <asm/arch/tnc.h>
+#include <asm/arch/irq.h>
+
+static struct irq_routing_table *pirq_routing_table;
+
+bool pirq_check_irq_routed(int link, u8 irq)
+{
+       u8 pirq;
+
+       pirq = x86_pci_read_config8(TNC_LPC, LINK_N2V(link));
+       pirq &= 0xf;
+
+       /* IRQ# 0/1/2/8/13 are reserved */
+       if (pirq < 3 || pirq == 8 || pirq == 13)
+               return false;
+
+       return pirq == irq ? true : false;
+}
+
+int pirq_translate_link(int link)
+{
+       return LINK_V2N(link);
+}
+
+void pirq_assign_irq(int link, u8 irq)
+{

arch/x86/cpu/queensbay/irq.c line 51

Quoted 10 lines
arch/x86/cpu/queensbay/irq.c new file +10 -0
+       /* IRQ# 0/1/2/8/13 are reserved */
+       if (irq < 3 || irq == 8 || irq == 13)
+               return;
+
+       x86_pci_write_config8(TNC_LPC, LINK_N2V(link), irq);
+}
+
+static inline void fill_irq_info(struct irq_info **slot, int *entries, u8 bus,
+                                u8 device, u8 func, u8 pin, u8 pirq)
+{

Please declare a local variable

Quoted 3 lines

struct irq_info *slot = *slotp;

and rename the param to slotp, to avoid the first four (*slot).

Will fix.

Quoted 127 lines
Quoted 127 lines
arch/x86/cpu/queensbay/irq.c new file +127 -0
+       (*slot)->bus = bus;
+       (*slot)->devfn = (device << 3) | func;
+       (*slot)->irq[pin - 1].link = LINK_N2V(pirq);
+       (*slot)->irq[pin - 1].bitmap = PIRQ_BITMAP;
+       (*entries)++;
+       (*slot)++;
+}
+
+/* PCIe port downstream INTx swizzle */
+static inline u8 pin_swizzle(u8 pin, int port)
+{
+       return (pin + port) % 4;
+}
+
+__weak int board_fill_irq_info(struct irq_info *slot)
+{
+       return 0;
+}
+
+static int create_pirq_routing_table(void)
+{
+       struct irq_routing_table *rt;
+       struct irq_info *slot;
+       int irq_entries = 0;
+       pci_dev_t tcf_bdf;
+       u8 tcf_bus, bus;
+       int i;
+
+       rt = malloc(sizeof(struct irq_routing_table));
+       if (!rt)
+               return -ENOMEM;
+       memset((char *)rt, 0, sizeof(struct irq_routing_table));
+
+       /* Populate the PIRQ table fields */
+       rt->signature = PIRQ_SIGNATURE;
+       rt->version = PIRQ_VERSION;
+       rt->rtr_bus = 0;
+       rt->rtr_devfn = (TNC_LPC_DEV << 3) | TNC_LPC_FUNC;
+       rt->rtr_vendor = PCI_VENDOR_ID_INTEL;
+       rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31;
+
+       slot = rt->slots;
+
+       /*
+        * Now fill in the irq_info entries in the PIRQ table
+        *
+        * We start from internal TunnelCreek PCI devices first, then
+        * followed by all the 4 PCIe ports downstream devices, including
+        * the Queensbay platform Topcliff chipset devices.
+        */
+       fill_irq_info(&slot, &irq_entries, 0, TNC_IGD_DEV,
+                     TNC_IGD_FUNC, INTA, PIRQE);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_SDVO_DEV,
+                     TNC_SDVO_FUNC, INTA, PIRQF);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_HDA_DEV,
+                     TNC_HDA_FUNC, INTA, PIRQG);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE0_DEV,
+                     TNC_PCIE0_FUNC, INTA, PIRQE);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE1_DEV,
+                     TNC_PCIE1_FUNC, INTA, PIRQF);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE2_DEV,
+                     TNC_PCIE2_FUNC, INTA, PIRQG);
+       fill_irq_info(&slot, &irq_entries, 0, TNC_PCIE3_DEV,
+                     TNC_PCIE3_FUNC, INTA, PIRQH);
+
+       /* Check which PCIe port the Topcliff chipset is connected to */
+       tcf_bdf = pci_find_device(PCI_VENDOR_ID_INTEL, 0x8800, 0);
+       tcf_bus = PCI_BUS(tcf_bdf);
+       for (i = 0; i < 4; i++) {
+               bus = x86_pci_read_config8(PCI_BDF(0, TNC_PCIE0_DEV + i, 0),
+                                          PCI_SECONDARY_BUS);
+               if (bus == tcf_bus)
+                       break;
+       }
+
+       /* Fill in the Topcliff chipset devices' irq info */
+       if (i < 4) {
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_PCIE_PORT_DEV,
+                             TCF_PCIE_PORT_FUNC, INTA, pin_swizzle(PIRQA, i));
+
+               tcf_bus++;
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_0,
+                             TCF_GBE_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_0,
+                             TCF_GPIO_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB1_OHCI0_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB1_OHCI1_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB1_OHCI2_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB1_EHCI_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_2,
+                             TCF_USB_DEVICE_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_4,
+                             TCF_SDIO0_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_4,
+                             TCF_SDIO1_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_6,
+                             TCF_SATA_FUNC, INTD, pin_swizzle(PIRQD, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+                             TCF_USB2_OHCI0_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+                             TCF_USB2_OHCI1_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+                             TCF_USB2_OHCI2_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_8,
+                             TCF_USB2_EHCI_FUNC, INTA, pin_swizzle(PIRQA, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_DMA1_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_UART0_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_UART1_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_UART2_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_10,
+                             TCF_UART3_FUNC, INTB, pin_swizzle(PIRQB, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_DMA2_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_SPI_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_I2C_FUNC, INTC, pin_swizzle(PIRQC, i));
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_CAN_FUNC, INTC, pin_swizzle(PIRQC, i));
Quoted 8 lines

arch/x86/cpu/queensbay/irq.c line 184

Quoted 6 lines
arch/x86/cpu/queensbay/irq.c new file +6 -0
+               fill_irq_info(&slot, &irq_entries, tcf_bus, TCF_DEV_12,
+                             TCF_1588_FUNC, INTC, pin_swizzle(PIRQC, i));
+       }
+
+       /* Call board-specific routine to fill in add-in card's irq info */
+       irq_entries += board_fill_irq_info(slot);

But isn't this already board-specific code?

This codes are put in the platform directory (arch/cpu/queensbay). We should implement board_fill_irq_info() in board directory (board/intel/crownbay) for any add-in cards.

Quoted 37 lines
Quoted 37 lines
arch/x86/cpu/queensbay/irq.c new file +37 -0
+
+       rt->size = irq_entries * sizeof(struct irq_info) + 32;
+
+       pirq_routing_table = rt;
+
+       return 0;
+}
+
+void pirq_init(void)
+{
+       u32 rcba;
+
+       rcba = x86_pci_read_config32(TNC_LPC, LPC_RCBA);
+       rcba &= ~MEM_BAR_EN;
+
+       /* Make sure all internal PCI devices are using INTA */
+       writel(INTA, rcba + D02IP);
+       writel(INTA, rcba + D03IP);
+       writel(INTA, rcba + D27IP);
+       writel(INTA, rcba + D31IP);
+       writel(INTA, rcba + D23IP);
+       writel(INTA, rcba + D24IP);
+       writel(INTA, rcba + D25IP);
+       writel(INTA, rcba + D26IP);
+
+       /*
+        * Route TunnelCreek PCI device interrupt pin to PIRQ
+        *
+        * Since PCIe downstream ports received INTx are routed to PIRQ
+        * A/B/C/D directly and not configurable, we route internal PCI
+        * device's INTx to PIRQ E/F/G/H.
+        */
+       writew(PIRQE, rcba + D02IR);
+       writew(PIRQF, rcba + D03IR);
+       writew(PIRQG, rcba + D27IR);
+       writew(PIRQH, rcba + D31IR);
+       writew(PIRQE, rcba + D23IR);
Quoted 8 lines

arch/x86/cpu/queensbay/irq.c line 226

Quoted 5 lines
arch/x86/cpu/queensbay/irq.c new file +5 -0
+       writew(PIRQF, rcba + D24IR);
+       writew(PIRQG, rcba + D25IR);
+       writew(PIRQH, rcba + D26IR);
+
+       if (!create_pirq_routing_table()) {

Can you add a comment here as to why you do this next bit if create_pirq_routing_table() fails?

I am not sure if you misread the codes? If create_pirq_routing_table() fails, it returns non-zero value and the following pirq_route_irqs() will not be called.

Quoted 225 lines
Quoted 225 lines
arch/x86/cpu/queensbay/irq.c new file +10 -0
+               /* Route PIRQ */
+               pirq_route_irqs(pirq_routing_table->slots,
+                               get_irq_slot_count(pirq_routing_table));
+       }
+}
+
+u32 write_pirq_routing_table(u32 addr)
+{
+       return copy_pirq_routing_table(addr, pirq_routing_table);
+}
arch/x86/cpu/queensbay/tnc.c +9 -1
index f756a0d..b46a7e9 100644
@@ -8,7 +8,8 @@
 #include <asm/io.h>
 #include <asm/pci.h>
 #include <asm/post.h>
-#include <asm/arch/tnc.h>
+#include <asm/arch/device.h>
+#include <asm/arch/irq.h>
 #include <asm/fsp/fsp_support.h>
 #include <asm/processor.h>
 
@@ -43,3 +44,10 @@ int arch_cpu_init(void)
 
        return 0;
 }
+
+int arch_misc_init(void)
+{
+       pirq_init();
+
+       return 0;
+}
arch/x86/include/asm/arch-queensbay/device.h new file +94 -0
new file mode 100644
index 0000000..953b48f
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015, Bin Meng <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _QUEENSBAY_DEVICE_H_
+#define _QUEENSBAY_DEVICE_H_
+
+#include <pci.h>
+
+/* TunnelCreek PCI Devices */
+#define TNC_HOST_BRIDGE_DEV    0
+#define TNC_HOST_BRIDGE_FUNC   0
+#define TNC_IGD_DEV            2
+#define TNC_IGD_FUNC           0
+#define TNC_SDVO_DEV           3
+#define TNC_SDVO_FUNC          0
+#define TNC_PCIE0_DEV          23
+#define TNC_PCIE0_FUNC         0
+#define TNC_PCIE1_DEV          24
+#define TNC_PCIE1_FUNC         0
+#define TNC_PCIE2_DEV          25
+#define TNC_PCIE2_FUNC         0
+#define TNC_PCIE3_DEV          26
+#define TNC_PCIE3_FUNC         0
+#define TNC_HDA_DEV            27
+#define TNC_HDA_FUNC           0
+#define TNC_LPC_DEV            31
+#define TNC_LPC_FUNC           0
+
+#define TNC_HOST_BRIDGE                \
+       PCI_BDF(0, TNC_HOST_BRIDGE_DEV, TNC_HOST_BRIDGE_FUNC)
+#define TNC_IGD                        \
+       PCI_BDF(0, TNC_IGD_DEV, TNC_IGD_FUNC)
+#define TNC_SDVO               \
+       PCI_BDF(0, TNC_SDVO_DEV, TNC_SDVO_FUNC)
+#define TNC_PCIE0              \
+       PCI_BDF(0, TNC_PCIE0_DEV, TNC_PCIE0_FUNC)
+#define TNC_PCIE1              \
+       PCI_BDF(0, TNC_PCIE1_DEV, TNC_PCIE1_FUNC)
+#define TNC_PCIE2              \
+       PCI_BDF(0, TNC_PCIE2_DEV, TNC_PCIE2_FUNC)
+#define TNC_PCIE3              \
+       PCI_BDF(0, TNC_PCIE3_DEV, TNC_PCIE3_FUNC)
+#define TNC_HDA                        \
+       PCI_BDF(0, TNC_HDA_DEV, TNC_HDA_FUNC)
+#define TNC_LPC                        \
+       PCI_BDF(0, TNC_LPC_DEV, TNC_LPC_FUNC)
+
+/* Topcliff IOH PCI Devices */
+#define TCF_PCIE_PORT_DEV      0
+#define TCF_PCIE_PORT_FUNC     0
+
+#define TCF_DEV_0              0
+#define TCF_PKT_HUB_FUNC       0
+#define TCF_GBE_FUNC           1
+#define TCF_GPIO_FUNC          2
+
+#define TCF_DEV_2              2
+#define TCF_USB1_OHCI0_FUNC    0
+#define TCF_USB1_OHCI1_FUNC    1
+#define TCF_USB1_OHCI2_FUNC    2
+#define TCF_USB1_EHCI_FUNC     3
+#define TCF_USB_DEVICE_FUNC    4
+
+#define TCF_DEV_4              4
+#define TCF_SDIO0_FUNC         0
+#define TCF_SDIO1_FUNC         1
+
+#define TCF_DEV_6              6
+#define TCF_SATA_FUNC          0
+
+#define TCF_DEV_8              8
+#define TCF_USB2_OHCI0_FUNC    0
+#define TCF_USB2_OHCI1_FUNC    1
+#define TCF_USB2_OHCI2_FUNC    2
+#define TCF_USB2_EHCI_FUNC     3
+
+#define TCF_DEV_10             10
+#define TCF_DMA1_FUNC          0
+#define TCF_UART0_FUNC         1
+#define TCF_UART1_FUNC         2
+#define TCF_UART2_FUNC         3
+#define TCF_UART3_FUNC         4
+
+#define TCF_DEV_12             12
+#define TCF_DMA2_FUNC          0
+#define TCF_SPI_FUNC           1
+#define TCF_I2C_FUNC           2
+#define TCF_CAN_FUNC           3
+#define TCF_1588_FUNC          4
+
+#endif /* _QUEENSBAY_DEVICE_H_ */
arch/x86/include/asm/arch-queensbay/irq.h new file +55 -0
new file mode 100644
index 0000000..e7f8616
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015, Bin Meng <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ARCH_IRQ_H_
+#define _ARCH_IRQ_H_
+
+enum pci_int_pin {
+       INTX,
+       INTA,
+       INTB,
+       INTC,
+       INTD
+};
+
+enum pirq_pin {
+       PIRQA,
+       PIRQB,
+       PIRQC,
+       PIRQD,
+       PIRQE,
+       PIRQF,
+       PIRQG,
+       PIRQH
+};
+
+/* PIRQ link number and value conversion */
+#define LINK_V2N(link) (link - 0x60)
+#define LINK_N2V(link) (link + 0x60)
+
+#define PIRQ_BITMAP    0xdee0
+
+struct irq_info;
+
+/**
+ * board_fill_irq_info() - Board-specific irq_info fill routine
+ *
+ * This fills the irq_info table for any board-specific add-in cards.
+ *
+ * @slot:      pointer to the struct irq_info that is to be filled in
+ * @return:    number of entries were written to the struct irq_info
+ */
+int board_fill_irq_info(struct irq_info *slot);
+
+/**
+ * pirq_init() - Initialize platform PIRQ routing
+ *
+ * This initializes the PIRQ routing on the platform and configures all PCI
+ * devices' interrupt line register to a working IRQ number on the 8259 PIC.
+ */
+void pirq_init(void);
+
+#endif /* _ARCH_IRQ_H_ */
arch/x86/include/asm/arch-queensbay/tnc.h +18 -2
index 10ea51d..2535fe8 100644
@@ -7,8 +7,30 @@
 #ifndef _X86_ARCH_TNC_H_
 #define _X86_ARCH_TNC_H_
 
-#include <pci.h>
+/* Memory BAR Enable */
+#define MEM_BAR_EN     0x00000001
 
-#define TNC_LPC                PCI_BDF(0, 31, 0)
+/* LPC PCI Configuration Registers */
+#define LPC_RCBA       0xf0
+
+/* Interupt Pin Configuration (in RCBA) */
+#define D02IP          0x3118
+#define D03IP          0x3130
+#define D23IP          0x312c
+#define D24IP          0x3128
+#define D25IP          0x3124
+#define D26IP          0x3120
+#define D27IP          0x3110
+#define D31IP          0x3100
+
+/* Interupt Route Configuration (in RCBA) */
+#define D02IR          0x3160
+#define D03IR          0x3162
Quoted 8 lines

arch/x86/include/asm/arch-queensbay/tnc.h line 34

Quoted 6 lines
arch/x86/include/asm/arch-queensbay/tnc.h +6 -0
+#define D23IR          0x3150
+#define D24IR          0x314e
+#define D25IR          0x314c
+#define D26IR          0x314a
+#define D27IR          0x3148
+#define D31IR          0x3140

Can we use a C structure for the RCBA, or part of it?

Yes, we can.

Quoted 30 lines
Quoted 30 lines
arch/x86/include/asm/arch-queensbay/tnc.h +0 -0
 #endif /* _X86_ARCH_TNC_H_ */
arch/x86/include/asm/u-boot-x86.h +2 -0
index c743efd..122e054 100644
@@ -53,6 +53,8 @@ int video_bios_init(void);
 void   board_init_f_r_trampoline(ulong) __attribute__ ((noreturn));
 void   board_init_f_r(void) __attribute__ ((noreturn));
 
+int arch_misc_init(void);
+
 /* Read the time stamp counter */
 static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)
 {
configs/crownbay_defconfig +1 -0
index ce90553..47763f9 100644
@@ -4,3 +4,4 @@ CONFIG_TARGET_CROWNBAY=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_SEPARATE=y
 CONFIG_DEFAULT_DEVICE_TREE="crownbay"
+CONFIG_GENERATE_PIRQ_TABLE=y
include/configs/crownbay.h +0 -0
index 42042d1..4fef433 100644
@@ -15,6 +15,7 @@
 
Quoted 7 lines

include/configs/crownbay.h

Quoted 7 lines
include/configs/crownbay.h +1 -1
 #define CONFIG_SYS_MONITOR_LEN         (1 << 20)
 #define CONFIG_BOARD_EARLY_INIT_F
+#define CONFIG_ARCH_MISC_INIT
 
 #define CONFIG_NR_DRAM_BANKS           1
 
--

Regards,
Bin

#10 lore raw

PATCH 4/4 x86: queensbay: Implement PIRQ routing

Hi Bin,

Quoted 40 lines · Bin Meng

Hi Simon,

Quoted 7 lines · Simon Glass

Hi Bin,

Quoted 2 lines · Bin Meng

Implement Intel Queensbay platform-specific PIRQ routing support. The chipset PIRQ routing setup is called in the arch_mist_init().

arch_misc_init()?

Will fix.

Quoted 2 lines

Also how can this be used on other boards? Should part of this code be moved to a generic place?

Generally Intel interrupt router should be compatible, but the offsets of these interrupt routing registers might be different from platform to platform. The platform-specific part is the internal PCI devices' interrupt pin to PIRQ map.

Quoted 19 lines
Quoted 19 lines

---

 arch/x86/cpu/queensbay/Makefile              |   2 +-
 arch/x86/cpu/queensbay/irq.c                 | 236 +++++++++++++++++++++++++++
 arch/x86/cpu/queensbay/tnc.c                 |  10 +-
 arch/x86/include/asm/arch-queensbay/device.h |  94 +++++++++++
 arch/x86/include/asm/arch-queensbay/irq.h    |  55 +++++++
 arch/x86/include/asm/arch-queensbay/tnc.h    |  26 ++-
 arch/x86/include/asm/u-boot-x86.h            |   2 +
 configs/crownbay_defconfig                   |   1 +
 include/configs/crownbay.h                   |   1 +
 9 files changed, 423 insertions(+), 4 deletions(-)
 create mode 100644 arch/x86/cpu/queensbay/irq.c
 create mode 100644 arch/x86/include/asm/arch-queensbay/device.h
 create mode 100644 arch/x86/include/asm/arch-queensbay/irq.h

[snip]

Quoted 11 lines
Quoted 11 lines
Quoted 10 lines
arch/x86/cpu/queensbay/irq.c new file +10 -0
+       writew(PIRQE, rcba + D02IR);
+       writew(PIRQF, rcba + D03IR);
+       writew(PIRQG, rcba + D27IR);
+       writew(PIRQH, rcba + D31IR);
+       writew(PIRQE, rcba + D23IR);
+       writew(PIRQF, rcba + D24IR);
+       writew(PIRQG, rcba + D25IR);
+       writew(PIRQH, rcba + D26IR);
+
+       if (!create_pirq_routing_table()) {
Quoted 6 lines
Quoted 2 lines

Can you add a comment here as to why you do this next bit if create_pirq_routing_table() fails?

I am not sure if you misread the codes? If create_pirq_routing_table() fails, it returns non-zero value and the following pirq_route_irqs() will not be called.

Yes I misread it. So should this function return the error code it gets? Or maybe add debug()?

Quoted 7 lines
Quoted 7 lines

arch/x86/cpu/queensbay/irq.c line 232

Quoted 7 lines
arch/x86/cpu/queensbay/irq.c new file +6 -0
+               /* Route PIRQ */
+               pirq_route_irqs(pirq_routing_table->slots,
+                               get_irq_slot_count(pirq_routing_table));
+       }
+}
+

Regards,
Simon

author
#11 lore raw

PATCH 4/4 x86: queensbay: Implement PIRQ routing

Hi Simon,

Quoted 59 lines · Simon Glass

Hi Bin,

Quoted 40 lines · Bin Meng

Hi Simon,

Quoted 7 lines · Simon Glass

Hi Bin,

Quoted 2 lines · Bin Meng

Implement Intel Queensbay platform-specific PIRQ routing support. The chipset PIRQ routing setup is called in the arch_mist_init().

arch_misc_init()?

Will fix.

Quoted 2 lines

Also how can this be used on other boards? Should part of this code be moved to a generic place?

Generally Intel interrupt router should be compatible, but the offsets of these interrupt routing registers might be different from platform to platform. The platform-specific part is the internal PCI devices' interrupt pin to PIRQ map.

Quoted 19 lines
Quoted 19 lines

---

 arch/x86/cpu/queensbay/Makefile              |   2 +-
 arch/x86/cpu/queensbay/irq.c                 | 236 +++++++++++++++++++++++++++
 arch/x86/cpu/queensbay/tnc.c                 |  10 +-
 arch/x86/include/asm/arch-queensbay/device.h |  94 +++++++++++
 arch/x86/include/asm/arch-queensbay/irq.h    |  55 +++++++
 arch/x86/include/asm/arch-queensbay/tnc.h    |  26 ++-
 arch/x86/include/asm/u-boot-x86.h            |   2 +
 configs/crownbay_defconfig                   |   1 +
 include/configs/crownbay.h                   |   1 +
 9 files changed, 423 insertions(+), 4 deletions(-)
 create mode 100644 arch/x86/cpu/queensbay/irq.c
 create mode 100644 arch/x86/include/asm/arch-queensbay/device.h
 create mode 100644 arch/x86/include/asm/arch-queensbay/irq.h

[snip]

Quoted 14 lines
Quoted 13 lines

arch/x86/cpu/queensbay/irq.c line 226

Quoted 10 lines
arch/x86/cpu/queensbay/irq.c new file +10 -0
+       writew(PIRQE, rcba + D02IR);
+       writew(PIRQF, rcba + D03IR);
+       writew(PIRQG, rcba + D27IR);
+       writew(PIRQH, rcba + D31IR);
+       writew(PIRQE, rcba + D23IR);
+       writew(PIRQF, rcba + D24IR);
+       writew(PIRQG, rcba + D25IR);
+       writew(PIRQH, rcba + D26IR);
+
+       if (!create_pirq_routing_table()) {

Can you add a comment here as to why you do this next bit if create_pirq_routing_table() fails?

Quoted 6 lines
Quoted 3 lines

I am not sure if you misread the codes? If create_pirq_routing_table() fails, it returns non-zero value and the following pirq_route_irqs() will not be called.

Yes I misread it. So should this function return the error code it gets? Or maybe add debug()?

Yep, adding one debug() is nice. Will do that in v2.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

arch/x86/cpu/queensbay/irq.c line 232

Quoted 7 lines
arch/x86/cpu/queensbay/irq.c new file +6 -0
+               /* Route PIRQ */
+               pirq_route_irqs(pirq_routing_table->slots,
+                               get_irq_slot_count(pirq_routing_table));
+       }
+}
+

Regards,
Bin