* [Linux-ia64] [PATCH] 2.5.18 early printk, PCI segment, multi-IOMMU support
@ 2002-07-22 22:22 Bjorn Helgaas
2002-07-23 5:43 ` David Mosberger
2002-07-23 15:22 ` Bjorn Helgaas
0 siblings, 2 replies; 3+ messages in thread
From: Bjorn Helgaas @ 2002-07-22 22:22 UTC (permalink / raw)
To: linux-ia64
[-- Attachment #1: Type: text/plain, Size: 1515 bytes --]
The attached patches are for 2.5.18-ia64-020530. They add support for
early printk on a UART, multiple PCI segments, PCI root bridge
translation offsets, and multiple HP ZX1 IOMMUs.
These have the same content as the ones I just posted for 2.4.18,
except that 2.5.18 has slightly older ACPI, has a different ZX1 "fake
device" strategy (doesn't use sysdata) and doesn't have a working ZX1
IOMMU yet.
The early printk diff includes a diff to hcdp_serial.c, which was not
in the 020530 patch. If you have since pulled hcdp_serial.c into
2.5, that hunk will be useful, otherwise you can just ignore it.
(Without HCDP, you have to specify the UART address with
CONFIG_IA64_EARLY_PRINTK_UART_BASE.)
Tested on HP ZX1 and i2000.
10_early_printk.diff
Early printk for MMIO UARTs. UART address from HCDP or specified
in config.
30_sci.diff
Add acpi_irq_to_vector() to handle both legacy ISA and new GSI
interrupt numbers. Add support for SCI on GSI interrupt.
40_pcibios_segment.diff
Add struct pci_controller for IA64 sysdata. Stash the PCI segment
there and add support in config accessors.
50_iosapic_segment.diff
Add segment support for PCI interrupts.
60_pci_tra.diff
Add support for PCI root bridges with non-zero translation
offsets.
70_enable_device.diff
Add a platform vector for pci_enable_device(). ZX1 needs this to
associate a device with the correct IOMMU.
--
Bjorn Helgaas - bjorn_helgaas at hp.com
Linux Systems Operation R&D
Hewlett-Packard Company
[-- Attachment #2: 10_early_printk.diff --]
[-- Type: text/x-diff, Size: 5515 bytes --]
diff -u -r linux-2.5.18-ia64-020530/arch/ia64/Config.help 10_early_printk/arch/ia64/Config.help
--- linux-2.5.18-ia64-020530/arch/ia64/Config.help Sun Jul 21 03:03:05 2002
+++ 10_early_printk/arch/ia64/Config.help Mon Jul 22 06:27:45 2002
@@ -502,10 +502,24 @@
problems, but slow! If you're unsure, select N.
CONFIG_IA64_EARLY_PRINTK
- Selecting this option uses the VGA screen for printk() output before
- the consoles are initialised. It is useful for debugging problems
- early in the boot process, but only if you have a VGA screen
- attached. If you're unsure, select N.
+ Selecting this option uses a UART or VGA screen (or both) for
+ printk() output before the consoles are initialised. It is useful
+ for debugging problems early in the boot process, but only if you
+ have a serial terminal or a VGA screen attached. If you're unsure,
+ select N.
+
+CONFIG_IA64_EARLY_PRINTK_UART
+ Select this option to use a serial port for early printk() output.
+ You must either select CONFIG_SERIAL_HCDP (to locate the UART
+ using the EFI HCDP table) or set the UART address explicitly
+ with CONFIG_IA64_EARLY_PRINTK_UART_BASE.
+
+CONFIG_IA64_EARLY_PRINTK_UART_BASE
+ The physical MMIO address of the UART to use for early printk().
+ This overrides any UART located using the EFI HCDP table.
+
+CONFIG_IA64_EARLY_PRINTK_VGA
+ Select this option to use VGA for early printk() output.
CONFIG_IA64_PRINT_HAZARDS
Selecting this option prints more information for Illegal Dependency
diff -u -r linux-2.5.18-ia64-020530/arch/ia64/config.in 10_early_printk/arch/ia64/config.in
--- linux-2.5.18-ia64-020530/arch/ia64/config.in Sun Jul 21 03:03:05 2002
+++ 10_early_printk/arch/ia64/config.in Mon Jul 22 06:27:45 2002
@@ -255,7 +255,14 @@
bool ' Disable VHPT' CONFIG_DISABLE_VHPT
bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
- bool ' Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK
+ bool ' Early printk support' CONFIG_IA64_EARLY_PRINTK
+ if [ "$CONFIG_IA64_EARLY_PRINTK" != "n" ]; then
+ bool ' Early printk on MMIO serial port' CONFIG_IA64_EARLY_PRINTK_UART
+ if [ "$CONFIG_IA64_EARLY_PRINTK_UART" != "n" ]; then
+ hex ' UART MMIO base address' CONFIG_IA64_EARLY_PRINTK_UART_BASE 0
+ fi
+ bool ' Early printk on VGA' CONFIG_IA64_EARLY_PRINTK_VGA
+ fi
bool ' Debug memory allocations' CONFIG_DEBUG_SLAB
bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
bool ' Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
diff -u -r linux-2.5.18-ia64-020530/kernel/printk.c 10_early_printk/kernel/printk.c
--- linux-2.5.18-ia64-020530/kernel/printk.c Sun Jul 21 03:03:06 2002
+++ 10_early_printk/kernel/printk.c Mon Jul 22 07:10:19 2002
@@ -693,6 +693,47 @@
#ifdef CONFIG_IA64_EARLY_PRINTK
+#ifdef CONFIG_IA64_EARLY_PRINTK_UART
+
+#include <linux/serial_reg.h>
+#include <asm/system.h>
+
+static void early_printk_uart(const char *str, size_t len)
+{
+ static char *uart = 0;
+ unsigned long uart_base;
+ char c;
+
+ if (!uart) {
+#ifdef CONFIG_SERIAL_HCDP
+ extern unsigned long hcdp_early_uart(void);
+ uart_base = hcdp_early_uart();
+#endif
+#if CONFIG_IA64_EARLY_PRINTK_UART_BASE
+ uart_base = CONFIG_IA64_EARLY_PRINTK_UART_BASE;
+#endif
+ if (uart_base)
+ uart = ioremap(uart_base, 64);
+ }
+
+ if (!uart)
+ return;
+
+ while (len-- > 0) {
+ c = *str++;
+ while (!(UART_LSR_TEMT & readb(uart + UART_LSR)))
+ ; /* spin */
+
+ writeb(c, uart + UART_TX);
+
+ if (c == '\n')
+ writeb('\r', uart + UART_TX);
+ }
+}
+#endif /* CONFIG_IA64_EARLY_PRINTK_UART */
+
+#ifdef CONFIG_IA64_EARLY_PRINTK_VGA
+
#include <asm/io.h>
#define VGABASE ((char *)0xc0000000000b8000)
@@ -701,8 +742,7 @@
static int current_ypos = VGALINES, current_xpos = 0;
-void
-early_printk (const char *str, size_t len)
+static void early_printk_vga(const char *str, size_t len)
{
char c;
int i, k, j;
@@ -734,6 +774,17 @@
}
}
}
+}
+#endif /* CONFIG_IA64_EARLY_PRINTK_VGA */
+
+void early_printk(const char *str, size_t len)
+{
+#ifdef CONFIG_IA64_EARLY_PRINTK_UART
+ early_printk_uart(str, len);
+#endif
+#ifdef CONFIG_IA64_EARLY_PRINTK_VGA
+ early_printk_vga(str, len);
+#endif
}
#endif /* CONFIG_IA64_EARLY_PRINTK */
diff -u -r -X /home/helgaas/exclude linux-2.4.18-ia64-020719/drivers/char/hcdp_serial.c 10_early_printk/drivers/char/hcdp_serial.c
--- linux-2.4.18-ia64-020719/drivers/char/hcdp_serial.c Sun Jul 21 03:03:29 2002
+++ 10_early_printk/drivers/char/hcdp_serial.c Mon Jul 22 05:07:15 2002
@@ -219,3 +219,41 @@
printk("Leaving setup_serial_hcdp()\n");
#endif
}
+
+#ifdef CONFIG_IA64_EARLY_PRINTK_UART
+unsigned long hcdp_early_uart(void)
+{
+ efi_system_table_t *systab;
+ efi_config_table_t *config_tables;
+ hcdp_t *hcdp = 0;
+ hcdp_dev_t *dev;
+ int i;
+
+ systab = (efi_system_table_t *) ia64_boot_param->efi_systab;
+ if (!systab)
+ return 0;
+ systab = __va(systab);
+
+ config_tables = (efi_config_table_t *) systab->tables;
+ if (!config_tables)
+ return 0;
+ config_tables = __va(config_tables);
+
+ for (i = 0; i < systab->nr_tables; i++) {
+ if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
+ hcdp = (hcdp_t *) config_tables[i].table;
+ break;
+ }
+ }
+ if (!hcdp)
+ return 0;
+ hcdp = __va(hcdp);
+
+ for (i = 0, dev = hcdp->hcdp_dev; i < hcdp->num_entries; i++, dev++) {
+ if (dev->type == HCDP_DEV_CONSOLE)
+ return (u64) dev->base_addr.addrhi << 32
+ | dev->base_addr.addrlo;
+ }
+ return 0;
+}
+#endif
[-- Attachment #3: 30_sci.diff --]
[-- Type: text/x-diff, Size: 5102 bytes --]
diff -u -r 10_early_printk/arch/ia64/kernel/acpi.c 30_sci/arch/ia64/kernel/acpi.c
--- 10_early_printk/arch/ia64/kernel/acpi.c Sun Jul 21 03:03:05 2002
+++ 30_sci/arch/ia64/kernel/acpi.c Mon Jul 22 07:19:46 2002
@@ -201,6 +201,7 @@
static int total_cpus __initdata;
static int available_cpus __initdata;
struct acpi_table_madt * acpi_madt __initdata;
+u8 has_8259;
static int __init
@@ -323,9 +324,8 @@
if (iosapic_init) {
#ifndef CONFIG_ITANIUM
- /* PCAT_COMPAT flag indicates dual-8259 setup */
iosapic_init(iosapic->address, iosapic->global_irq_base,
- acpi_madt->flags.pcat_compat);
+ has_8259);
#else
/* Firmware on old Itanium systems is broken */
iosapic_init(iosapic->address, iosapic->global_irq_base, 1);
@@ -430,6 +430,8 @@
return -ENODEV;
}
+ has_8259 = acpi_madt->flags.pcat_compat;
+
/* Get base address of IPI Message Block */
if (acpi_madt->lapic_address)
@@ -442,6 +444,39 @@
}
+static int __init
+acpi_parse_facp (unsigned long phys_addr, unsigned long size)
+{
+ struct acpi_table_header *facp_header;
+ fadt_descriptor_rev2 *facp;
+ u32 irq, irq_base = 0;
+ char *iosapic_address = NULL;
+
+ if (!phys_addr || !size)
+ return -EINVAL;
+
+ if (!iosapic_register_irq)
+ return -ENODEV;
+
+ facp_header = (struct acpi_table_header *) __va(phys_addr);
+
+ /* Only deal with ACPI 2.0 FACP */
+ if (facp_header->revision != 3)
+ return -ENODEV;
+
+ facp = (fadt_descriptor_rev2 *)facp_header;
+ irq = facp->sci_int;
+
+ if (has_8259 && irq < 16)
+ return 0; /* legacy, no setup required */
+
+ if (!acpi_find_iosapic(irq, &irq_base, &iosapic_address))
+ iosapic_register_irq(irq, 0, 0, irq_base, iosapic_address);
+
+ return 0;
+}
+
+
int __init
acpi_find_rsdp (unsigned long *rsdp_phys)
{
@@ -594,6 +629,13 @@
return result;
}
+ /*
+ * The FADT table contains an SCI_INT line, by which the system
+ * gets interrupts such as power and sleep buttons. If it's not
+ * on a Legacy interrupt, it needs to be setup.
+ */
+ acpi_table_parse(ACPI_FACP, acpi_parse_facp);
+
#ifdef CONFIG_SERIAL_ACPI
/*
* TBD: Need phased approach to table parsing (only do those absolutely
@@ -674,6 +716,15 @@
*type = ACPI_INT_MODEL_IOSAPIC;
return 0;
+}
+
+int
+acpi_irq_to_vector(u32 irq)
+{
+ if (has_8259 && irq < 16)
+ return isa_irq_to_vector(irq);
+
+ return iosapic_irq_to_vector(irq);
}
#endif /* CONFIG_ACPI_BOOT */
diff -u -r 10_early_printk/arch/ia64/kernel/iosapic.c 30_sci/arch/ia64/kernel/iosapic.c
--- 10_early_printk/arch/ia64/kernel/iosapic.c Sun Jul 21 03:03:05 2002
+++ 30_sci/arch/ia64/kernel/iosapic.c Sun Jul 21 03:03:07 2002
@@ -125,8 +125,8 @@
* Translate IOSAPIC irq number to the corresponding IA-64 interrupt vector. If no
* entry exists, return -1.
*/
-static int
-iosapic_irq_to_vector (int irq)
+int
+iosapic_irq_to_vector (unsigned int irq)
{
int vector;
diff -u -r 10_early_printk/drivers/acpi/acpi_osl.c 30_sci/drivers/acpi/acpi_osl.c
--- 10_early_printk/drivers/acpi/acpi_osl.c Sun Jul 21 03:03:05 2002
+++ 30_sci/drivers/acpi/acpi_osl.c Mon Jul 22 07:20:46 2002
@@ -33,6 +33,7 @@
#include <linux/interrupt.h>
#include <linux/kmod.h>
#include <linux/delay.h>
+#include <linux/acpi.h>
#include <asm/io.h>
#include "acpi.h"
@@ -40,11 +41,6 @@
#include <asm/efi.h>
#endif
-#ifdef _IA64
-#include <asm/hw_irq.h>
-#include <asm/delay.h>
-#endif
-
#define _COMPONENT ACPI_OS_SERVICES
ACPI_MODULE_NAME ("osl")
@@ -225,8 +221,15 @@
acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context)
{
#ifdef _IA64
- irq = isa_irq_to_vector(irq);
-#endif /*_IA64*/
+ int vector;
+
+ vector = acpi_irq_to_vector(irq);
+ if (vector < 0) {
+ printk(KERN_ERR PREFIX "SCI (IRQ%d) not registered\n", irq);
+ return AE_OK;
+ }
+ irq = vector;
+#endif
acpi_irq_irq = irq;
acpi_irq_handler = handler;
acpi_irq_context = context;
@@ -243,8 +246,8 @@
{
if (acpi_irq_handler) {
#ifdef _IA64
- irq = isa_irq_to_vector(irq);
-#endif /*_IA64*/
+ irq = acpi_irq_to_vector(irq);
+#endif
free_irq(irq, acpi_irq);
acpi_irq_handler = NULL;
}
diff -u -r 10_early_printk/include/asm-ia64/iosapic.h 30_sci/include/asm-ia64/iosapic.h
--- 10_early_printk/include/asm-ia64/iosapic.h Fri May 24 19:55:28 2002
+++ 30_sci/include/asm-ia64/iosapic.h Sun Jul 21 03:03:07 2002
@@ -53,6 +53,7 @@
extern void __init iosapic_init (unsigned long address, unsigned int base_irq,
int pcat_compat);
+extern int iosapic_irq_to_vector (unsigned int irq);
extern int iosapic_register_irq (u32 global_vector, unsigned long polarity,
unsigned long edge_triggered, u32 base_irq,
char *iosapic_address);
diff -u -r 10_early_printk/include/linux/acpi.h 30_sci/include/linux/acpi.h
--- 10_early_printk/include/linux/acpi.h Sun Jul 21 03:05:25 2002
+++ 30_sci/include/linux/acpi.h Sun Jul 21 03:21:51 2002
@@ -389,6 +389,7 @@
#ifdef CONFIG_ACPI_INTERPRETER
int acpi_init(void);
+int acpi_irq_to_vector(u32 irq);
#endif /*CONFIG_ACPI_INTERPRETER*/
[-- Attachment #4: 40_pcibios_segment.diff --]
[-- Type: text/x-diff, Size: 7588 bytes --]
diff -u -r 30_sci/arch/ia64/kernel/pci.c 40_pcibios_segment/arch/ia64/kernel/pci.c
--- 30_sci/arch/ia64/kernel/pci.c Mon Jul 22 07:25:09 2002
+++ 40_pcibios_segment/arch/ia64/kernel/pci.c Mon Jul 22 09:55:40 2002
@@ -53,11 +53,12 @@
/*
* Low-level SAL-based PCI configuration access functions. Note that SAL
* calls are already serialized (via sal_lock), so we don't need another
- * synchronization mechanism here. Not using segment number (yet).
+ * synchronization mechanism here.
*/
-#define PCI_SAL_ADDRESS(bus, dev, fn, reg) \
- ((u64)(bus << 16) | (u64)(dev << 11) | (u64)(fn << 8) | (u64)(reg))
+#define PCI_SAL_ADDRESS(seg, bus, dev, fn, reg) \
+ ((u64)(seg << 24) | (u64)(bus << 16) | \
+ (u64)(dev << 11) | (u64)(fn << 8) | (u64)(reg))
static int
pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
@@ -65,10 +66,10 @@
int result = 0;
u64 data = 0;
- if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+ if (!value || (seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
return -EINVAL;
- result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(bus, dev, fn, reg), len, &data);
+ result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, &data);
*value = (u32) data;
@@ -78,10 +79,10 @@
static int
pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
{
- if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+ if ((seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
return -EINVAL;
- return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(bus, dev, fn, reg), len, value);
+ return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, value);
}
@@ -94,7 +95,7 @@
if (!value)
return -EINVAL;
- result = pci_sal_read(0, dev->bus->number, PCI_SLOT(dev->devfn),
+ result = pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), where, 1, &data);
*value = (u8) data;
@@ -111,7 +112,7 @@
if (!value)
return -EINVAL;
- result = pci_sal_read(0, dev->bus->number, PCI_SLOT(dev->devfn),
+ result = pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), where, 2, &data);
*value = (u16) data;
@@ -125,28 +126,28 @@
if (!value)
return -EINVAL;
- return pci_sal_read(0, dev->bus->number, PCI_SLOT(dev->devfn),
+ return pci_sal_read(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), where, 4, value);
}
static int
pci_sal_write_config_byte (struct pci_dev *dev, int where, u8 value)
{
- return pci_sal_write(0, dev->bus->number, PCI_SLOT(dev->devfn),
+ return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), where, 1, value);
}
static int
pci_sal_write_config_word (struct pci_dev *dev, int where, u16 value)
{
- return pci_sal_write(0, dev->bus->number, PCI_SLOT(dev->devfn),
+ return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), where, 2, value);
}
static int
pci_sal_write_config_dword (struct pci_dev *dev, int where, u32 value)
{
- return pci_sal_write(0, dev->bus->number, PCI_SLOT(dev->devfn),
+ return pci_sal_write(PCI_SEGMENT(dev), dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), where, 4, value);
}
@@ -164,24 +165,64 @@
* Initialization. Uses the SAL interface
*/
-struct pci_bus *
-pcibios_scan_root(int seg, int bus)
+static struct pci_controller *
+alloc_pci_controller(int seg)
+{
+ struct pci_controller *controller;
+
+ controller = kmalloc(sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ return NULL;
+
+ memset(controller, 0, sizeof(*controller));
+ controller->segment = seg;
+ return controller;
+}
+
+static struct pci_bus *
+scan_root_bus(int bus, struct pci_ops *ops, void *sysdata)
{
- struct list_head *list = NULL;
- struct pci_bus *pci_bus = NULL;
+ struct pci_bus *b;
+
+ /*
+ * We know this is a new root bus we haven't seen before, so
+ * scan it, even if we've seen the same bus number in a different
+ * segment.
+ */
+ b = kmalloc(sizeof(*b), GFP_KERNEL);
+ if (!b)
+ return NULL;
+
+ memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->children);
+ INIT_LIST_HEAD(&b->devices);
- list_for_each(list, &pci_root_buses) {
- pci_bus = pci_bus_b(list);
- if (pci_bus->number == bus) {
- /* Already scanned */
- printk("PCI: Bus (%02x:%02x) already probed\n", seg, bus);
- return pci_bus;
- }
- }
+ list_add_tail(&b->node, &pci_root_buses);
+
+ b->number = b->secondary = bus;
+ b->resource[0] = &ioport_resource;
+ b->resource[1] = &iomem_resource;
+
+ b->sysdata = sysdata;
+ b->ops = ops;
+ b->subordinate = pci_do_scan_bus(b);
+
+ return b;
+}
+
+struct pci_bus *
+pcibios_scan_root(void *handle, int seg, int bus)
+{
+ struct pci_controller *controller;
printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
- return pci_scan_bus(bus, pci_root_ops, NULL);
+ controller = alloc_pci_controller(seg);
+ if (!controller)
+ return NULL;
+
+ controller->acpi_handle = handle;
+ return scan_root_bus(bus, pci_root_ops, controller);
}
void __init
@@ -204,6 +245,7 @@
{
# define PCI_BUSES_TO_SCAN 255
int i = 0;
+ struct pci_controller *controller;
#ifdef CONFIG_IA64_MCA
ia64_mca_check_errors(); /* For post-failure MCA error logging */
@@ -214,8 +256,10 @@
platform_pci_fixup(0); /* phase 0 fixups (before buses scanned) */
printk("PCI: Probing PCI hardware\n");
- for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
- pci_scan_bus(i, pci_root_ops, NULL);
+ controller = alloc_pci_controller(0);
+ if (controller)
+ for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+ pci_scan_bus(i, pci_root_ops, controller);
platform_pci_fixup(1); /* phase 1 fixups (after buses scanned) */
return 0;
diff -u -r 30_sci/drivers/acpi/acpi_pci_root.c 40_pcibios_segment/drivers/acpi/acpi_pci_root.c
--- 30_sci/drivers/acpi/acpi_pci_root.c Mon Jul 22 07:25:09 2002
+++ 40_pcibios_segment/drivers/acpi/acpi_pci_root.c Mon Jul 22 09:55:40 2002
@@ -653,7 +653,7 @@
* PCI namespace does not get created until this call is made (and
* thus the root bridge's pci_dev does not exist).
*/
- root->data.bus = pcibios_scan_root(root->data.id.segment, root->data.id.bus);
+ root->data.bus = pcibios_scan_root(root->handle, root->data.id.segment, root->data.id.bus);
if (!root->data.bus) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Bus %02x:%02x not present in PCI namespace\n",
diff -u -r 30_sci/include/asm-ia64/pci.h 40_pcibios_segment/include/asm-ia64/pci.h
--- 30_sci/include/asm-ia64/pci.h Mon Jul 22 07:35:12 2002
+++ 40_pcibios_segment/include/asm-ia64/pci.h Mon Jul 22 09:55:40 2002
@@ -21,7 +21,7 @@
#define PCIBIOS_MIN_MEM 0x10000000
void pcibios_config_init(void);
-struct pci_bus * pcibios_scan_root(int seg, int bus);
+struct pci_bus *pcibios_scan_root(void *acpi_handle, int segment, int bus);
extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
@@ -95,5 +95,13 @@
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
+
+struct pci_controller {
+ void *acpi_handle;
+ int segment;
+};
+
+#define PCI_CONTROLLER(dev) ((struct pci_controller *) dev->sysdata)
+#define PCI_SEGMENT(dev) (PCI_CONTROLLER(dev)->segment)
#endif /* _ASM_IA64_PCI_H */
[-- Attachment #5: 50_iosapic_segment.diff --]
[-- Type: text/x-diff, Size: 3491 bytes --]
diff -u -r 40_pcibios_segment/arch/ia64/kernel/acpi.c 50_iosapic_segment/arch/ia64/kernel/acpi.c
--- 40_pcibios_segment/arch/ia64/kernel/acpi.c Mon Jul 22 09:52:13 2002
+++ 50_iosapic_segment/arch/ia64/kernel/acpi.c Mon Jul 22 09:54:02 2002
@@ -695,6 +695,7 @@
list_for_each(node, &acpi_prts.entries) {
entry = (struct acpi_prt_entry *)node;
+ vector[i].segment = entry->id.seg;
vector[i].bus = entry->id.bus;
vector[i].pci_id = ((u32) entry->id.dev << 16) | 0xffff;
vector[i].pin = entry->id.pin;
diff -u -r 40_pcibios_segment/arch/ia64/kernel/iosapic.c 50_iosapic_segment/arch/ia64/kernel/iosapic.c
--- 40_pcibios_segment/arch/ia64/kernel/iosapic.c Mon Jul 22 09:52:13 2002
+++ 50_iosapic_segment/arch/ia64/kernel/iosapic.c Mon Jul 22 09:54:02 2002
@@ -26,12 +26,13 @@
* 02/04/18 J.I. Lee bug fix in iosapic_init_pci_irq
* 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping
* error
+ * 02/07/11 B. Helgaas Support PCI segments
*/
/*
* Here is what the interrupt logic between a PCI device and the CPU looks like:
*
* (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The
- * device is uniquely identified by its bus--, and slot-number (the function
+ * device is uniquely identified by its segment--, bus--, and slot-number (the function
* number does not matter here because all functions share the same interrupt
* lines).
*
@@ -141,12 +142,13 @@
* return -1.
*/
int
-pci_pin_to_vector (int bus, int slot, int pci_pin)
+pci_pin_to_vector (int segment, int bus, int slot, int pci_pin)
{
struct pci_vector_struct *r;
for (r = pci_irq.route; r < pci_irq.route + pci_irq.num_routes; ++r)
- if (r->bus == bus && (r->pci_id >> 16) == slot && r->pin == pci_pin)
+ if (r->segment == segment && r->bus == bus &&
+ (r->pci_id >> 16) == slot && r->pin == pci_pin)
return iosapic_irq_to_vector(r->irq);
return -1;
}
@@ -691,6 +693,7 @@
iosapic_pci_fixup (int phase)
{
struct pci_dev *dev;
+ int segment;
unsigned char pin;
int vector;
struct hw_interrupt_type *irq_type;
@@ -708,7 +711,8 @@
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) {
pin--; /* interrupt pins are numbered starting from 1 */
- vector = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+ segment = PCI_SEGMENT(dev);
+ vector = pci_pin_to_vector(segment, dev->bus->number, PCI_SLOT(dev->devfn), pin);
if (vector < 0 && dev->bus->parent) {
/* go back to the bridge */
struct pci_dev *bridge = dev->bus->self;
@@ -718,7 +722,7 @@
do {
/* do the bridge swizzle... */
pin = (pin + PCI_SLOT(dev->devfn)) % 4;
- vector = pci_pin_to_vector(bridge->bus->number,
+ vector = pci_pin_to_vector(segment, bridge->bus->number,
PCI_SLOT(bridge->devfn),
pin);
} while (vector < 0 && (bridge = bridge->bus->self));
diff -u -r 40_pcibios_segment/include/asm-ia64/system.h 50_iosapic_segment/include/asm-ia64/system.h
--- 40_pcibios_segment/include/asm-ia64/system.h Mon Jul 22 07:43:12 2002
+++ 50_iosapic_segment/include/asm-ia64/system.h Mon Jul 22 09:54:02 2002
@@ -29,6 +29,7 @@
#include <linux/types.h>
struct pci_vector_struct {
+ __u16 segment; /* PCI Segment number */
__u16 bus; /* PCI Bus number */
__u32 pci_id; /* ACPI split 16 bits device, 16 bits function (see section 6.1.1) */
__u8 pin; /* PCI PIN (0 = A, 1 = B, 2 = C, 3 = D) */
[-- Attachment #6: 60_pci_tra.diff --]
[-- Type: text/x-diff, Size: 4513 bytes --]
diff -u -r 50_iosapic_segment/arch/ia64/kernel/acpi.c 60_pci_tra/arch/ia64/kernel/acpi.c
--- 50_iosapic_segment/arch/ia64/kernel/acpi.c Fri Jul 19 17:24:49 2002
+++ 60_pci_tra/arch/ia64/kernel/acpi.c Fri Jul 19 17:24:50 2002
@@ -166,6 +166,73 @@
kfree(buf->pointer);
}
+static void
+acpi_get_crs_addr (acpi_buffer *buf, int type, u64 *base, u64 *size, u64 *tra)
+{
+ int offset = 0;
+ acpi_resource_address16 *addr16;
+ acpi_resource_address32 *addr32;
+ acpi_resource_address64 *addr64;
+
+ for (;;) {
+ acpi_resource *res = acpi_get_crs_next(buf, &offset);
+ if (!res)
+ return;
+ switch (res->id) {
+ case ACPI_RSTYPE_ADDRESS16:
+ addr16 = (acpi_resource_address16 *) &res->data;
+
+ if (type == addr16->resource_type) {
+ *base = addr16->min_address_range;
+ *size = addr16->address_length;
+ *tra = addr16->address_translation_offset;
+ return;
+ }
+ break;
+ case ACPI_RSTYPE_ADDRESS32:
+ addr32 = (acpi_resource_address32 *) &res->data;
+ if (type == addr32->resource_type) {
+ *base = addr32->min_address_range;
+ *size = addr32->address_length;
+ *tra = addr32->address_translation_offset;
+ return;
+ }
+ break;
+ case ACPI_RSTYPE_ADDRESS64:
+ addr64 = (acpi_resource_address64 *) &res->data;
+ if (type == addr64->resource_type) {
+ *base = addr64->min_address_range;
+ *size = addr64->address_length;
+ *tra = addr64->address_translation_offset;
+ return;
+ }
+ break;
+ }
+ }
+}
+
+acpi_status
+acpi_get_addr_space(acpi_handle obj, u8 type, u64 *base, u64 *length, u64 *tra)
+{
+ acpi_status status;
+ acpi_buffer buf;
+
+ *base = 0;
+ *length = 0;
+ *tra = 0;
+
+ status = acpi_get_crs(obj, &buf);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
+ return status;
+ }
+
+ acpi_get_crs_addr(&buf, type, base, length, tra);
+
+ acpi_dispose_crs(&buf);
+
+ return AE_OK;
+}
#endif /* CONFIG_ACPI */
#ifdef CONFIG_ACPI_BOOT
diff -u -r 50_iosapic_segment/arch/ia64/kernel/pci.c 60_pci_tra/arch/ia64/kernel/pci.c
--- 50_iosapic_segment/arch/ia64/kernel/pci.c Fri Jul 19 17:24:49 2002
+++ 60_pci_tra/arch/ia64/kernel/pci.c Fri Jul 19 17:24:50 2002
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
+#include <linux/acpi.h>
#include <asm/machvec.h>
#include <asm/page.h>
@@ -214,6 +215,7 @@
pcibios_scan_root(void *handle, int seg, int bus)
{
struct pci_controller *controller;
+ u64 base, size, offset;
printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
@@ -222,6 +224,10 @@
return NULL;
controller->acpi_handle = handle;
+
+ acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset);
+ controller->mem_offset = offset;
+
return scan_root_bus(bus, pci_root_ops, controller);
}
@@ -267,6 +273,27 @@
subsys_initcall(pcibios_init);
+static void __init
+pcibios_fixup_resource(struct resource *res, u64 offset)
+{
+ res->start += offset;
+ res->end += offset;
+}
+
+void __init
+pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (!dev->resource[i].start)
+ continue;
+ if (dev->resource[i].flags & IORESOURCE_MEM)
+ pcibios_fixup_resource(&dev->resource[i],
+ PCI_CONTROLLER(dev)->mem_offset);
+ }
+}
+
/*
* Called after each bus is probed, but before its children
* are examined.
@@ -274,7 +301,10 @@
void __init
pcibios_fixup_bus (struct pci_bus *b)
{
- return;
+ struct list_head *ln;
+
+ for (ln = b->devices.next; ln != &b->devices; ln = ln->next)
+ pcibios_fixup_device_resources(pci_dev_b(ln), b);
}
void __init
diff -u -r 50_iosapic_segment/include/asm-ia64/pci.h 60_pci_tra/include/asm-ia64/pci.h
--- 50_iosapic_segment/include/asm-ia64/pci.h Fri Jul 19 17:24:49 2002
+++ 60_pci_tra/include/asm-ia64/pci.h Fri Jul 19 17:24:50 2002
@@ -99,6 +99,8 @@
struct pci_controller {
void *acpi_handle;
int segment;
+
+ u64 mem_offset;
};
#define PCI_CONTROLLER(dev) ((struct pci_controller *) dev->sysdata)
diff -u -r 50_iosapic_segment/include/linux/acpi.h 60_pci_tra/include/linux/acpi.h
--- 50_iosapic_segment/include/linux/acpi.h Fri Jul 19 17:24:49 2002
+++ 60_pci_tra/include/linux/acpi.h Fri Jul 19 17:30:06 2002
@@ -390,6 +390,7 @@
int acpi_init(void);
int acpi_irq_to_vector(u32 irq);
+acpi_status acpi_get_addr_space(acpi_handle, u8 type, u64 *base, u64 *length, u64 *tra);
#endif /*CONFIG_ACPI_INTERPRETER*/
[-- Attachment #7: 70_enable_device.diff --]
[-- Type: text/x-diff, Size: 2385 bytes --]
diff -u -r 60_pci_tra/arch/ia64/kernel/pci.c 70_enable_device/arch/ia64/kernel/pci.c
--- 60_pci_tra/arch/ia64/kernel/pci.c Mon Jul 22 09:57:07 2002
+++ 70_enable_device/arch/ia64/kernel/pci.c Mon Jul 22 09:59:09 2002
@@ -342,8 +342,7 @@
if (!dev)
return -EINVAL;
- /* Not needed, since we enable all devices at startup. */
-
+ platform_pci_enable_device(dev);
printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
return 0;
}
diff -u -r 60_pci_tra/include/asm-ia64/machvec.h 70_enable_device/include/asm-ia64/machvec.h
--- 60_pci_tra/include/asm-ia64/machvec.h Mon Jul 22 07:59:47 2002
+++ 70_enable_device/include/asm-ia64/machvec.h Mon Jul 22 09:59:09 2002
@@ -24,6 +24,7 @@
typedef void ia64_mv_cpu_init_t(void);
typedef void ia64_mv_irq_init_t (void);
typedef void ia64_mv_pci_fixup_t (int);
+typedef void ia64_mv_pci_enable_device_t (struct pci_dev *);
typedef unsigned long ia64_mv_map_nr_t (unsigned long);
typedef void ia64_mv_mca_init_t (void);
typedef void ia64_mv_mca_handler_t (void);
@@ -92,7 +93,8 @@
# define platform_cmci_handler ia64_mv.cmci_handler
# define platform_log_print ia64_mv.log_print
# define platform_pci_fixup ia64_mv.pci_fixup
-# define platform_send_ipi ia64_mv.send_ipi
+# define platform_pci_enable_device ia64_mv.pci_enable_device
+# define platform_send_ipi ia64_mv.send_ipi
# define platform_global_tlb_purge ia64_mv.global_tlb_purge
# define platform_pci_dma_init ia64_mv.dma_init
# define platform_pci_alloc_consistent ia64_mv.alloc_consistent
@@ -123,6 +125,7 @@
ia64_mv_cpu_init_t *cpu_init;
ia64_mv_irq_init_t *irq_init;
ia64_mv_pci_fixup_t *pci_fixup;
+ ia64_mv_pci_enable_device_t *pci_enable_device;
ia64_mv_map_nr_t *map_nr;
ia64_mv_mca_init_t *mca_init;
ia64_mv_mca_handler_t *mca_handler;
@@ -160,6 +163,7 @@
platform_cpu_init, \
platform_irq_init, \
platform_pci_fixup, \
+ platform_pci_enable_device, \
platform_map_nr, \
platform_mca_init, \
platform_mca_handler, \
@@ -238,6 +242,9 @@
#endif
#ifndef platform_pci_fixup
# define platform_pci_fixup ((ia64_mv_pci_fixup_t *) machvec_noop)
+#endif
+#ifndef platform_pci_enable_device
+# define platform_pci_enable_device ((ia64_mv_pci_enable_device_t *) machvec_noop)
#endif
#ifndef platform_send_ipi
# define platform_send_ipi ia64_send_ipi /* default to architected version */
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [Linux-ia64] [PATCH] 2.5.18 early printk, PCI segment, multi-IOMMU support
2002-07-22 22:22 [Linux-ia64] [PATCH] 2.5.18 early printk, PCI segment, multi-IOMMU support Bjorn Helgaas
@ 2002-07-23 5:43 ` David Mosberger
2002-07-23 15:22 ` Bjorn Helgaas
1 sibling, 0 replies; 3+ messages in thread
From: David Mosberger @ 2002-07-23 5:43 UTC (permalink / raw)
To: linux-ia64
>>>>> On Mon, 22 Jul 2002 16:22:30 -0600, Bjorn Helgaas <bjorn_helgaas@hp.com> said:
Bjorn> Tested on HP ZX1 and i2000.
Bjorn> 10_early_printk.diff Early printk for MMIO UARTs. UART
Bjorn> address from HCDP or specified in config.
Bjorn> 30_sci.diff Add acpi_irq_to_vector() to handle both legacy
Bjorn> ISA and new GSI interrupt numbers. Add support for SCI on
Bjorn> GSI interrupt.
Bjorn> 40_pcibios_segment.diff Add struct pci_controller for IA64
Bjorn> sysdata. Stash the PCI segment there and add support in
Bjorn> config accessors.
Bjorn> 50_iosapic_segment.diff Add segment support for PCI
Bjorn> interrupts.
The above look fine to me. I'm not really an ACPI expert so if
anybody has an issue with these (particularly the latter three), speak
up.
Bjorn> 60_pci_tra.diff Add support for PCI root bridges with
Bjorn> non-zero translation offsets.
This one handles only memory offsets. Any particular reason for this?
Perhaps there should be at least a check which will warn/panic if a
non-zero I/O offset is found?
Bjorn> 70_enable_device.diff Add a platform vector for
Bjorn> pci_enable_device(). ZX1 needs this to associate a device
Bjorn> with the correct IOMMU.
Hmmh, are you expecting other platform-specific work will have to be
done in pci_enable_device() in the future? If all we really need here
is a platform-specific PCI-device -> IOMMU mapping, perhaps we should
call it just that. OTOH, I can see that this is a natural callback
point. Any comments by folks doing the hw support for other
(hotplug-capable) machines?
--david
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Linux-ia64] [PATCH] 2.5.18 early printk, PCI segment, multi-IOMMU support
2002-07-22 22:22 [Linux-ia64] [PATCH] 2.5.18 early printk, PCI segment, multi-IOMMU support Bjorn Helgaas
2002-07-23 5:43 ` David Mosberger
@ 2002-07-23 15:22 ` Bjorn Helgaas
1 sibling, 0 replies; 3+ messages in thread
From: Bjorn Helgaas @ 2002-07-23 15:22 UTC (permalink / raw)
To: linux-ia64
> Bjorn> 60_pci_tra.diff Add support for PCI root bridges with
> Bjorn> non-zero translation offsets.
>
> This one handles only memory offsets. Any particular reason for this?
> Perhaps there should be at least a check which will warn/panic if a
> non-zero I/O offset is found?
Yup, there's a reason, but it's kind of lame: I haven't figured
out how to deal with I/O offsets yet :-) That gets into how
I/O spaces other than the legacy 64Kb space are described in
ACPI, and how the kernel accesses them. So handling I/O
offsets will (I think) involve more extensive changes to I/O
port addressing.
--
Bjorn Helgaas - bjorn_helgaas at hp.com
Linux Systems Operation R&D
Hewlett-Packard Company
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2002-07-23 15:22 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-07-22 22:22 [Linux-ia64] [PATCH] 2.5.18 early printk, PCI segment, multi-IOMMU support Bjorn Helgaas
2002-07-23 5:43 ` David Mosberger
2002-07-23 15:22 ` Bjorn Helgaas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox