All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bjorn Helgaas <bjorn_helgaas@hp.com>
To: linux-ia64@vger.kernel.org
Subject: [Linux-ia64] [PATCH] 2.5.18 early printk, PCI segment, multi-IOMMU support
Date: Mon, 22 Jul 2002 22:22:30 +0000	[thread overview]
Message-ID: <marc-linux-ia64-105590701905804@msgid-missing> (raw)

[-- 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 */

             reply	other threads:[~2002-07-22 22:22 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-07-22 22:22 Bjorn Helgaas [this message]
2002-07-23  5:43 ` [Linux-ia64] [PATCH] 2.5.18 early printk, PCI segment, multi-IOMMU support David Mosberger
2002-07-23 15:22 ` Bjorn Helgaas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=marc-linux-ia64-105590701905804@msgid-missing \
    --to=bjorn_helgaas@hp.com \
    --cc=linux-ia64@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.