code-duplication that existed between ACPI and the ia64 IOSAPIC code.
To make this work, the Makefiles had to be re-organized to ensure that
the ACPI subsystem is initialized before PCI (even though both are called
via subsys-initcalls).
HEAD := arch/$(ARCH)/kernel/head.o arch/ia64/kernel/init_task.o
-SUBDIRS := arch/$(ARCH)/tools arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/lib $(SUBDIRS)
-CORE_FILES := arch/$(ARCH)/kernel/kernel.o arch/$(ARCH)/mm/mm.o $(CORE_FILES)
-
-LIBS := $(TOPDIR)/arch/$(ARCH)/lib/lib.a $(LIBS) \
- $(TOPDIR)/arch/$(ARCH)/lib/lib.a
+libs-y += arch/$(ARCH)/lib/
+core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/
+drivers-$(CONFIG_PCI) += arch/$(ARCH)/pci/
+drivers-$(CONFIG_IA64_HP_ZX1) += arch/$(ARCH)/hp/common/ arch/$(ARCH)/hp/zx1/
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
then
bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA
define_bool CONFIG_PM y
+ define_bool CONFIG_IOSAPIC y
fi
if [ "$CONFIG_IA64_SGI_SN1" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ]; then
subdir-$(CONFIG_IA64_GENERIC) += $(ALL_SUB_DIRS)
subdir-$(CONFIG_IA64_HP_SIM) += sim
-subdir-$(CONFIG_IA64_HP_ZX1) += zx1 common
SUB_DIRS := $(subdir-y)
obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
# Copyright (C) Alex Williamson (alex_williamson@hp.com)
#
-O_TARGET := common.o
-
export-objs := sba_iommu.o
obj-y := sba_iommu.o
#
-# ia64/platform/hp/zx1/Makefile
+# ia64/hp/zx1/Makefile
#
# Copyright (C) 2002 Hewlett Packard
# Copyright (C) Alex Williamson (alex_williamson@hp.com)
#
-O_TARGET := zx1.o
-
obj-y := hpzx1_misc.o
obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o
extern void sba_init(void);
-void
-hpzx1_pci_fixup (int phase)
+static void
+hpzx1_init (void)
{
- iosapic_pci_fixup(phase);
- switch (phase) {
- case 0:
- /* zx1 has a hardware I/O TLB which lets us DMA from any device to any address */
- MAX_DMA_ADDRESS = ~0UL;
- break;
+ /* zx1 has a hardware I/O TLB which lets us DMA from any device to any address */
+ MAX_DMA_ADDRESS = ~0UL;
- case 1:
- hpzx1_acpi_dev_init();
- sba_init();
- break;
- }
+ hpzx1_acpi_dev_init();
+ sba_init();
}
+
+subsys_initcall(hpzx1_init);
# Makefile for the linux kernel.
#
-O_TARGET := kernel.o
EXTRA_TARGETS := head.o init_task.o
export-objs := ia64_ksyms.o
obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o ivt.o \
machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \
signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o
-obj-$(CONFIG_IA64_GENERIC) += iosapic.o
-obj-$(CONFIG_IA64_HP_ZX1) += iosapic.o
-obj-$(CONFIG_IA64_DIG) += iosapic.o
+obj-$(CONFIG_IOSAPIC) += iosapic.o
obj-$(CONFIG_IA64_PALINFO) += palinfo.o
obj-$(CONFIG_EFI_VARS) += efivars.o
-obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_SMP) += smp.o smpboot.o
obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o
obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
* 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping
* error
* 02/07/29 T. Kochi Allocate interrupt vectors dynamically
- * 02/08/04 T. Kochi Cleaned up terminology (irq, global system interrupt, vector,
- * etc.)
+ * 02/08/04 T. Kochi Cleaned up terminology (irq, global system interrupt, vector, etc.)
+ * 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's pci_irq code.
*/
/*
* Here is what the interrupt logic between a PCI device and the kernel looks like:
* architecture-independent interrupt handling mechanism in Linux. As an
* IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number
* mapping. On smaller systems, we use one-to-one mapping between IA-64 vector and
- * IRQ. A platform can implemnent platform_irq_to_vector(irq) and
+ * IRQ. A platform can implement platform_irq_to_vector(irq) and
* platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
* Please see also include/asm-ia64/hw_irq.h for those APIs.
*
*/
#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/acpi.h>
#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/pci.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
-#include <linux/irq.h>
-#include <linux/acpi.h>
#include <asm/delay.h>
#include <asm/hw_irq.h>
static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED;
-/* PCI pin to GSI routing information. This info typically comes from ACPI. */
-
-static struct {
- int num_routes;
- struct pci_vector_struct *route;
-} pci_irq;
-
/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
static struct iosapic_intr_info {
int
gsi_to_vector (unsigned int gsi)
{
- int vector;
+ struct iosapic_intr_info *info;
- for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
- if (iosapic_intr_info[vector].gsi_base + iosapic_intr_info[vector].rte_index == gsi)
- return vector;
+ for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
+ if (info->gsi_base + info->rte_index == gsi)
+ return info - iosapic_intr_info;
return -1;
}
int rte_index;
char redir;
- DBG(KERN_DEBUG "%s: routing vector %d to %x\n", __FUNCTION__, vector, dest);
+ DBG(KERN_DEBUG"IOSAPIC: routing vector %d to %x\n", vector, dest);
rte_index = iosapic_intr_info[vector].rte_index;
if (rte_index < 0)
index = find_iosapic(gsi);
if (index < 0) {
- printk("ISA: No corresponding IOSAPIC found : ISA IRQ %u -> GSI 0x%x\n", isa_irq, gsi);
+ printk("ISA: No corresponding IOSAPIC found : ISA IRQ %u -> GSI 0x%x\n",
+ isa_irq, gsi);
return;
}
set_rte(vector, dest);
}
-/*
- * Map PCI pin to the corresponding GSI.
- * If no such mapping exists, return -1.
- */
-static int
-pci_pin_to_gsi (int bus, int slot, int pci_pin, unsigned int *gsi)
-{
- 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) {
- *gsi = r->irq;
- return 0;
- }
-
- return -1;
-}
-
-/*
- * Map PCI pin to the corresponding IA-64 interrupt vector. If no such mapping exists,
- * try to allocate a new vector. If it fails, return -1.
- */
-static int
-pci_pin_to_vector (int bus, int slot, int pci_pin)
-{
- int index, vector;
- int gsi_base, pcat_compat;
- char *addr;
- unsigned int gsi;
-
- if (pci_pin_to_gsi(bus, slot, pci_pin, &gsi) < 0) {
- printk("PCI: no interrupt route for %02x:%02x pin %c\n", bus, slot, 'A' + pci_pin);
- return -1;
- }
-
- vector = gsi_to_vector(gsi);
-
- if (vector < 0) {
- /* we should allocate a vector for this interrupt line */
-
- index = find_iosapic(gsi);
-
- if (index < 0) {
- printk("PCI: GSI 0x%x has no IOSAPIC mapping\n", gsi);
- return -1;
- }
-
- addr = iosapic_lists[index].addr;
- gsi_base = iosapic_lists[index].gsi_base;
- pcat_compat = iosapic_lists[index].pcat_compat;
-
- if (pcat_compat && (gsi < 16))
- vector = isa_irq_to_vector(gsi);
- else {
- /* new GSI; allocate a vector for it */
- vector = ia64_alloc_vector();
- }
-
- register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
- 0, 0, gsi_base, addr);
-
- DBG("PCI: (%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
- bus, slot, 'A' + pci_pin, gsi, vector);
- }
-
- return vector;
-}
-
void __devinit
iosapic_init (unsigned long phys_addr, unsigned int gsi_base, int pcat_compat)
{
iosapic_lists[num_iosapic].num_rte = num_rte;
num_iosapic++;
- printk("IOSAPIC: version %x.%x, address 0x%lx, GSIs 0x%x-0x%x\n",
+ printk(KERN_INFO" IOSAPIC v%x.%x, address 0x%lx, GSIs 0x%x-0x%x\n",
(ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, gsi_base, gsi_base + num_rte - 1);
if ((gsi_base == 0) && pcat_compat) {
}
}
-
-/*
- * Set allocated interrupt vector to dev->irq and
- * program IOSAPIC to deliver interrupts
- */
-void
-iosapic_fixup_pci_interrupt (struct pci_dev *dev)
+static void
+fixup_vector (int vector, unsigned int gsi, const char *pci_id)
{
- unsigned char pci_pin;
- int vector;
- unsigned int dest;
- struct hw_interrupt_type *irq_type;
+ struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
irq_desc_t *idesc;
+ unsigned int dest;
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pci_pin);
- if (pci_pin) {
- pci_pin--; /* interrupt pins are numberd starting from 1 */
-
- vector = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pci_pin);
-
- if (vector < 0 && dev->bus->parent) {
- /* go back to the bridge */
- struct pci_dev *bridge = dev->bus->self;
-
- if (bridge) {
- /* allow for multiple bridges on an adapter */
- do {
- /* do the bridge swizzle... */
- pci_pin = (pci_pin + PCI_SLOT(dev->devfn)) % 4;
- vector = pci_pin_to_vector(bridge->bus->number,
- PCI_SLOT(bridge->devfn),
- pci_pin);
- } while (vector < 0 && (bridge = bridge->bus->self));
- }
- if (vector >= 0)
- printk(KERN_WARNING
- "PCI: using PPB (%s INT%c) to get vector %d\n",
- dev->slot_name, 'A' + pci_pin,
- vector);
- else
- printk(KERN_WARNING
- "PCI: Couldn't map irq for (%s INT%c)\n",
- dev->slot_name, 'A' + pci_pin);
- }
-
- if (vector >= 0) {
- dev->irq = vector;
-
- irq_type = &irq_type_iosapic_level;
- idesc = irq_desc(vector);
- if (idesc->handler != irq_type) {
- if (idesc->handler != &no_irq_type)
- printk("%s: changing vector %d from %s to %s\n",
- __FUNCTION__, vector,
- idesc->handler->typename,
- irq_type->typename);
- idesc->handler = irq_type;
- }
+ idesc = irq_desc(vector);
+ if (idesc->handler != irq_type) {
+ if (idesc->handler != &no_irq_type)
+ printk("IOSAPIC: changing vector %d from %s to %s\n",
+ vector, idesc->handler->typename, irq_type->typename);
+ idesc->handler = irq_type;
+ }
#ifdef CONFIG_SMP
- /*
- * For platforms that do not support interrupt redirect
- * via the XTP interface, we can round-robin the PCI
- * device interrupts to the processors
- */
- if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
- static int cpu_index = 0;
-
- while (!cpu_online(cpu_index))
- if (++cpu_index >= NR_CPUS)
- cpu_index = 0;
-
- dest = cpu_physical_id(cpu_index) & 0xffff;
- } else {
- /*
- * Direct the interrupt vector to the current cpu,
- * platform redirection will distribute them.
- */
- dest = (ia64_get_lid() >> 16) & 0xffff;
- }
+ /*
+ * For platforms that do not support interrupt redirect via the XTP interface, we
+ * can round-robin the PCI device interrupts to the processors
+ */
+ if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
+ static int cpu_index = -1;
+
+ do
+ if (++cpu_index >= NR_CPUS)
+ cpu_index = 0;
+ while (!cpu_online(cpu_index));
+
+ dest = cpu_physical_id(cpu_index) & 0xffff;
+ } else {
+ /*
+ * Direct the interrupt vector to the current cpu, platform redirection
+ * will distribute them.
+ */
+ dest = (ia64_get_lid() >> 16) & 0xffff;
+ }
#else
- /* direct the interrupt vector to the running cpu id */
- dest = (ia64_get_lid() >> 16) & 0xffff;
+ /* direct the interrupt vector to the running cpu id */
+ dest = (ia64_get_lid() >> 16) & 0xffff;
#endif
+ set_rte(vector, dest);
- printk("PCI->APIC IRQ transform: (%s INT%c) -> CPU 0x%04x vector %d\n",
- dev->slot_name, 'A' + pci_pin, dest, vector);
- set_rte(vector, dest);
- }
- }
+ printk("IOSAPIC: %s -> GSI 0x%x -> CPU 0x%04x vector %d\n", pci_id, gsi, dest, vector);
}
-
-void
-iosapic_pci_fixup (int phase)
+void __init
+iosapic_parse_prt (void)
{
- struct pci_dev *dev;
+ struct acpi_prt_entry *entry;
+ struct list_head *node;
+ unsigned int gsi, gsi_base;
+ int index, vector, pcat_compat;
+ char pci_id[16];
+ char *addr;
- if (phase == 0) {
- if (acpi_get_prt(&pci_irq.route, &pci_irq.num_routes)) {
- printk("%s: acpi_get_prt failed\n", __FILE__);
- }
- return;
- }
+ list_for_each(node, &acpi_prt.entries) {
+ entry = list_entry(node, struct acpi_prt_entry, node);
- if (phase != 1)
- return;
+ /* We're only interested in static (non-link) entries. */
+ if (entry->link.handle)
+ continue;
- pci_for_each_dev(dev) {
- /* fixup dev->irq and program IOSAPIC */
- iosapic_fixup_pci_interrupt(dev);
+ gsi = entry->link.index;
- /*
- * Nothing to fixup
- * Fix out-of-range IRQ numbers
- */
- if (dev->irq >= IA64_NUM_VECTORS)
- dev->irq = 15; /* Spurious interrupts */
+ vector = gsi_to_vector(gsi);
+ if (vector < 0) {
+ /* allocate a vector for this interrupt line */
+ index = find_iosapic(gsi);
+
+ if (index < 0) {
+ printk(KERN_WARNING"IOSAPIC: GSI 0x%x has no IOSAPIC!\n", gsi);
+ return;
+ }
+ addr = iosapic_lists[index].addr;
+ gsi_base = iosapic_lists[index].gsi_base;
+ pcat_compat = iosapic_lists[index].pcat_compat;
+
+ if (pcat_compat && (gsi < 16))
+ vector = isa_irq_to_vector(gsi);
+ else
+ /* new GSI; allocate a vector for it */
+ vector = ia64_alloc_vector();
+
+ register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, 0, 0, gsi_base, addr);
+ }
+ snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
+ entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin);
+
+ fixup_vector(vector, gsi, pci_id);
}
}
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
}
+device_initcall(ia64_mca_check_errors);
+
/*
* ia64_mca_register_cpev
*
+++ /dev/null
-/*
- * pci.c - Low-Level PCI Access in IA-64
- *
- * Derived from bios32.c of i386 tree.
- *
- * Copyright (C) 2002 Hewlett-Packard Co
- * David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * Note: Above list of copyright holders is incomplete...
- */
-#include <linux/config.h>
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-
-#include <asm/machvec.h>
-#include <asm/page.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/io.h>
-
-#include <asm/sal.h>
-
-
-#ifdef CONFIG_SMP
-# include <asm/smp.h>
-#endif
-#include <asm/irq.h>
-
-
-#undef DEBUG
-#define DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-#ifdef CONFIG_IA64_MCA
-extern void ia64_mca_check_errors( void );
-#endif
-
-struct pci_fixup pcibios_fixups[1];
-
-/*
- * 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).
- */
-
-#define PCI_SAL_ADDRESS(bus, dev, fn, reg) \
- ((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)
-{
- int result = 0;
- u64 data = 0;
-
- if (!value || (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);
-
- *value = (u32) data;
-
- return result;
-}
-
-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))
- return -EINVAL;
-
- return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(bus, dev, fn, reg), len, value);
-}
-
-
-static int
-pci_sal_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
-{
- return __pci_sal_read(0, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
- where, size, value);
-}
-
-static int
-pci_sal_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
-{
- return __pci_sal_write(0, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
- where, size, value);
-}
-
-struct pci_ops pci_sal_ops = {
- .read = pci_sal_read,
- .write = pci_sal_write,
-};
-
-struct pci_ops *pci_root_ops = &pci_sal_ops; /* default to SAL */
-
-struct pci_bus *
-pcibios_scan_root (int bus)
-{
- struct list_head *list = NULL;
- struct pci_bus *pci_bus = NULL;
-
- list_for_each(list, &pci_root_buses) {
- pci_bus = pci_bus_b(list);
- if (pci_bus->number == bus) {
- /* Already scanned */
- printk("PCI: Bus (%02x) already probed\n", bus);
- return pci_bus;
- }
- }
-
- printk("PCI: Probing PCI hardware on bus (%02x)\n", bus);
- return pci_scan_bus(bus, pci_root_ops, NULL);
-}
-
-static int __init
-pcibios_init (void)
-{
-# define PCI_BUSES_TO_SCAN 255
- int i = 0;
-
-acpi_init(); /* hackedy hack hack... */
-
-#ifdef CONFIG_IA64_MCA
- ia64_mca_check_errors(); /* For post-failure MCA error logging */
-#endif
-
- 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);
-
- platform_pci_fixup(1); /* phase 1 fixups (after buses scanned) */
- return 0;
-}
-
-subsys_initcall(pcibios_init);
-
-/*
- * Called after each bus is probed, but before its children
- * are examined.
- */
-void __init
-pcibios_fixup_bus (struct pci_bus *b)
-{
- return;
-}
-
-void __init
-pcibios_update_resource (struct pci_dev *dev, struct resource *root,
- struct resource *res, int resource)
-{
- unsigned long where, size;
- u32 reg;
-
- where = PCI_BASE_ADDRESS_0 + (resource * 4);
- size = res->end - res->start;
- pci_read_config_dword(dev, where, ®);
- reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
- pci_write_config_dword(dev, where, reg);
-
- /* ??? FIXME -- record old value for shutdown. */
-}
-
-void __init
-pcibios_update_irq (struct pci_dev *dev, int irq)
-{
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-
- /* ??? FIXME -- record old value for shutdown. */
-}
-
-void __init
-pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
-{
-}
-
-static inline int
-pcibios_enable_resources (struct pci_dev *dev, int mask)
-{
- u16 cmd, old_cmd;
- int idx;
- struct resource *r;
-
- if (!dev)
- return -EINVAL;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- old_cmd = cmd;
- for (idx=0; idx<6; idx++) {
- /* Only set up the desired resources. */
- if (!(mask & (1 << idx)))
- continue;
-
- r = &dev->resource[idx];
- if (!r->start && r->end) {
- printk(KERN_ERR
- "PCI: Device %s not available because of resource collisions\n",
- dev->slot_name);
- return -EINVAL;
- }
- if (r->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- if (r->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- if (dev->resource[PCI_ROM_RESOURCE].start)
- cmd |= PCI_COMMAND_MEMORY;
- if (cmd != old_cmd) {
- printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- return 0;
-}
-
-int
-pcibios_enable_device (struct pci_dev *dev, int mask)
-{
- int ret;
-
- ret = pcibios_enable_resources(dev, mask);
- if (ret < 0)
- return ret;
-
- printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
- return 0;
-}
-
-void
-pcibios_align_resource (void *data, struct resource *res,
- unsigned long size, unsigned long align)
-{
-}
-
-/*
- * PCI BIOS setup, always defaults to SAL interface
- */
-char * __init
-pcibios_setup (char *str)
-{
- return NULL;
-}
-
-int
-pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- /*
- * I/O space cannot be accessed via normal processor loads and stores on this
- * platform.
- */
- if (mmap_state == pci_mmap_io)
- /*
- * XXX we could relax this for I/O spaces for which ACPI indicates that
- * the space is 1-to-1 mapped. But at the moment, we don't support
- * multiple PCI address spaces and the legacy I/O space is not 1-to-1
- * mapped, so this is moot.
- */
- return -EINVAL;
-
- /*
- * Leave vm_pgoff as-is, the PCI space address is the physical address on this
- * platform.
- */
- vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
- if (write_combine)
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
-}
#
# Note 2! The CFLAGS definition is now in the main makefile...
-O_TARGET := mm.o
-
obj-y := init.o fault.o tlb.o extable.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
--- /dev/null
+obj-y := pci.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * pci.c - Low-Level PCI Access in IA-64
+ *
+ * Derived from bios32.c of i386 tree.
+ *
+ * Copyright (C) 2002 Hewlett-Packard Co
+ * David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * Note: Above list of copyright holders is incomplete...
+ */
+#include <linux/config.h>
+
+#include <linux/acpi.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+
+#include <asm/machvec.h>
+#include <asm/page.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <asm/sal.h>
+
+
+#ifdef CONFIG_SMP
+# include <asm/smp.h>
+#endif
+#include <asm/irq.h>
+
+
+#undef DEBUG
+#define DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#ifdef CONFIG_IA64_MCA
+extern void ia64_mca_check_errors( void );
+#endif
+
+struct pci_fixup pcibios_fixups[1];
+
+/*
+ * 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).
+ */
+
+#define PCI_SAL_ADDRESS(bus, dev, fn, reg) \
+ ((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)
+{
+ int result = 0;
+ u64 data = 0;
+
+ if (!value || (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);
+
+ *value = (u32) data;
+
+ return result;
+}
+
+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))
+ return -EINVAL;
+
+ return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(bus, dev, fn, reg), len, value);
+}
+
+
+static int
+pci_sal_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
+{
+ return __pci_sal_read(0, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ where, size, value);
+}
+
+static int
+pci_sal_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
+{
+ return __pci_sal_write(0, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ where, size, value);
+}
+
+struct pci_ops pci_sal_ops = {
+ .read = pci_sal_read,
+ .write = pci_sal_write
+};
+
+struct pci_ops *pci_root_ops = &pci_sal_ops; /* default to SAL */
+
+static int __init
+pci_acpi_init (void)
+{
+ if (!acpi_pci_irq_init())
+ printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+ else
+ printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
+ return 0;
+}
+
+subsys_initcall(pci_acpi_init);
+
+/* Called by ACPI when it finds a new root bus. */
+struct pci_bus *
+pcibios_scan_root (int bus)
+{
+ struct list_head *list;
+ struct pci_bus *pci_bus;
+
+ list_for_each(list, &pci_root_buses) {
+ pci_bus = pci_bus_b(list);
+ if (pci_bus->number == bus) {
+ /* Already scanned */
+ printk("PCI: Bus (%02x) already probed\n", bus);
+ return pci_bus;
+ }
+ }
+
+ printk("PCI: Probing PCI hardware on bus (%02x)\n", bus);
+ return pci_scan_bus(bus, pci_root_ops, NULL);
+}
+
+/*
+ * Called after each bus is probed, but before its children are examined.
+ */
+void __init
+pcibios_fixup_bus (struct pci_bus *b)
+{
+ return;
+}
+
+void __init
+pcibios_update_resource (struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+ unsigned long where, size;
+ u32 reg;
+
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ size = res->end - res->start;
+ pci_read_config_dword(dev, where, ®);
+ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+ pci_write_config_dword(dev, where, reg);
+
+ /* ??? FIXME -- record old value for shutdown. */
+}
+
+void __init
+pcibios_update_irq (struct pci_dev *dev, int irq)
+{
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+
+ /* ??? FIXME -- record old value for shutdown. */
+}
+
+void __init
+pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
+{
+}
+
+static inline int
+pcibios_enable_resources (struct pci_dev *dev, int mask)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ if (!dev)
+ return -EINVAL;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for (idx=0; idx<6; idx++) {
+ /* Only set up the desired resources. */
+ if (!(mask & (1 << idx)))
+ continue;
+
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk(KERN_ERR
+ "PCI: Device %s not available because of resource collisions\n",
+ dev->slot_name);
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ cmd |= PCI_COMMAND_MEMORY;
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+int
+pcibios_enable_device (struct pci_dev *dev, int mask)
+{
+ int ret;
+
+ ret = pcibios_enable_resources(dev, mask);
+ if (ret < 0)
+ return ret;
+
+ printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
+ return acpi_pci_irq_enable(dev);
+}
+
+void
+pcibios_align_resource (void *data, struct resource *res,
+ unsigned long size, unsigned long align)
+{
+}
+
+/*
+ * PCI BIOS setup, always defaults to SAL interface
+ */
+char * __init
+pcibios_setup (char *str)
+{
+ return NULL;
+}
+
+int
+pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
+{
+ /*
+ * I/O space cannot be accessed via normal processor loads and stores on this
+ * platform.
+ */
+ if (mmap_state == pci_mmap_io)
+ /*
+ * XXX we could relax this for I/O spaces for which ACPI indicates that
+ * the space is 1-to-1 mapped. But at the moment, we don't support
+ * multiple PCI address spaces and the legacy I/O space is not 1-to-1
+ * mapped, so this is moot.
+ */
+ return -EINVAL;
+
+ /*
+ * Leave vm_pgoff as-is, the PCI space address is the physical address on this
+ * platform.
+ */
+ vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+
+ if (write_combine)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
# define platform_setup ia64_mv.setup
# define platform_cpu_init ia64_mv.cpu_init
# define platform_irq_init ia64_mv.irq_init
-# define platform_map_nr ia64_mv.map_nr
# define platform_mca_init ia64_mv.mca_init
# define platform_mca_handler ia64_mv.mca_handler
# 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_global_tlb_purge ia64_mv.global_tlb_purge
# define platform_pci_dma_init ia64_mv.dma_init
platform_setup, \
platform_cpu_init, \
platform_irq_init, \
- platform_pci_fixup, \
- platform_map_nr, \
platform_mca_init, \
platform_mca_handler, \
platform_cmci_handler, \
#ifndef platform_log_print
# define platform_log_print ((ia64_mv_log_print_t *) machvec_noop)
#endif
-#ifndef platform_pci_fixup
-# define platform_pci_fixup ((ia64_mv_pci_fixup_t *) machvec_noop)
-#endif
#ifndef platform_send_ipi
# define platform_send_ipi ia64_send_ipi /* default to architected version */
#endif
#define platform_name "dig"
#define platform_setup dig_setup
#define platform_irq_init dig_irq_init
-#define platform_pci_fixup iosapic_pci_fixup
-#define platform_map_nr map_nr_dense
#endif /* _ASM_IA64_MACHVEC_DIG_h */
#define platform_name "hpsim"
#define platform_setup hpsim_setup
#define platform_irq_init hpsim_irq_init
-#define platform_map_nr map_nr_dense
#endif /* _ASM_IA64_MACHVEC_HPSIM_h */
*/
#define platform_name "hpzx1"
#define platform_setup dig_setup
-#define platform_pci_fixup hpzx1_pci_fixup
-#define platform_map_nr map_nr_dense
#define platform_pci_dma_init ((ia64_mv_pci_dma_init *) machvec_noop)
#define platform_pci_alloc_consistent sba_alloc_consistent
#define platform_pci_free_consistent sba_free_consistent
#define platform_setup sn1_setup
#define platform_cpu_init sn_cpu_init
#define platform_irq_init sn1_irq_init
-#define platform_map_nr sn1_map_nr
#define platform_send_ipi sn1_send_IPI
#define platform_global_tlb_purge sn1_global_tlb_purge
-#define platform_pci_fixup sn1_pci_fixup
#define platform_inb sn1_inb
#define platform_inw sn1_inw
#define platform_inl sn1_inl
#define platform_setup sn1_setup
#define platform_cpu_init sn_cpu_init
#define platform_irq_init sn1_irq_init
-#define platform_map_nr sn2_map_nr
#define platform_send_ipi sn2_send_IPI
#define platform_global_tlb_purge sn2_global_tlb_purge
-#define platform_pci_fixup sn1_pci_fixup
#ifdef Colin /* We are using the same is Generic IA64 calls defined in io.h */
#define platform_inb sn1_inb
#define platform_inw sn1_inw
*/
flush_tlb_mm(tlb->mm);
} else if (unlikely (end - start >= 1024*1024*1024*1024UL
- || REGION_NUMBER(start) != REGION_NUMBER(end - 1)))
+ || REGION_NUMBER(start) != REGION_NUMBER(end - 1)))
{
/*
* If we flush more than a tera-byte or across regions, we're probably