Commit e761e9ff authored by David Mosberger's avatar David Mosberger

ia64: Switch over to using ACPI PCI support routines. This gets rid of much of the

	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).
parent 18a2add4
......@@ -86,11 +86,10 @@ endif
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
......
......@@ -68,6 +68,7 @@ if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_H
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
......
......@@ -7,7 +7,6 @@ O_TARGET := hp.o
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))
......
......@@ -5,8 +5,6 @@
# 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
......
......@@ -335,19 +335,14 @@ hpzx1_acpi_dev_init(void)
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;
case 1:
hpzx1_acpi_dev_init();
sba_init();
break;
}
}
subsys_initcall(hpzx1_init);
......@@ -2,7 +2,6 @@
# Makefile for the linux kernel.
#
O_TARGET := kernel.o
EXTRA_TARGETS := head.o init_task.o
export-objs := ia64_ksyms.o
......@@ -10,12 +9,9 @@ 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
......
......@@ -27,8 +27,8 @@
* 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:
......@@ -51,7 +51,7 @@
* 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.
*
......@@ -65,14 +65,15 @@
*/
#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>
......@@ -95,13 +96,6 @@
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 {
......@@ -146,11 +140,11 @@ find_iosapic (unsigned int gsi)
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;
}
......@@ -163,7 +157,7 @@ set_rte (unsigned int vector, unsigned int dest)
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)
......@@ -584,7 +578,8 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
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;
}
......@@ -604,75 +599,6 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
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)
{
......@@ -713,7 +639,7 @@ 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) {
......@@ -740,82 +666,38 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base, int 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);
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
* 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;
static int cpu_index = -1;
while (!cpu_online(cpu_index))
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.
* Direct the interrupt vector to the current cpu, platform redirection
* will distribute them.
*/
dest = (ia64_get_lid() >> 16) & 0xffff;
}
......@@ -823,39 +705,54 @@ iosapic_fixup_pci_interrupt (struct pci_dev *dev)
/* direct the interrupt vector to the running cpu id */
dest = (ia64_get_lid() >> 16) & 0xffff;
#endif
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__);
}
list_for_each(node, &acpi_prt.entries) {
entry = list_entry(node, struct acpi_prt_entry, node);
/* We're only interested in static (non-link) entries. */
if (entry->link.handle)
continue;
gsi = entry->link.index;
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 (phase != 1)
return;
if (pcat_compat && (gsi < 16))
vector = isa_irq_to_vector(gsi);
else
/* new GSI; allocate a vector for it */
vector = ia64_alloc_vector();
pci_for_each_dev(dev) {
/* fixup dev->irq and program IOSAPIC */
iosapic_fixup_pci_interrupt(dev);
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);
/*
* Nothing to fixup
* Fix out-of-range IRQ numbers
*/
if (dev->irq >= IA64_NUM_VECTORS)
dev->irq = 15; /* Spurious interrupts */
fixup_vector(vector, gsi, pci_id);
}
}
......@@ -208,6 +208,8 @@ ia64_mca_check_errors (void)
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
}
device_initcall(ia64_mca_check_errors);
/*
* ia64_mca_register_cpev
*
......
......@@ -7,8 +7,6 @@
#
# 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
......
obj-y := pci.o
include $(TOPDIR)/Rules.make
......@@ -10,6 +10,7 @@
*/
#include <linux/config.h>
#include <linux/acpi.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
......@@ -100,16 +101,29 @@ pci_sal_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32
struct pci_ops pci_sal_ops = {
.read = pci_sal_read,
.write = pci_sal_write,
.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 = NULL;
struct pci_bus *pci_bus = NULL;
struct list_head *list;
struct pci_bus *pci_bus;
list_for_each(list, &pci_root_buses) {
pci_bus = pci_bus_b(list);
......@@ -124,33 +138,8 @@ pcibios_scan_root (int 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.
* Called after each bus is probed, but before its children are examined.
*/
void __init
pcibios_fixup_bus (struct pci_bus *b)
......@@ -235,7 +224,7 @@ pcibios_enable_device (struct pci_dev *dev, int mask)
return ret;
printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
return 0;
return acpi_pci_irq_enable(dev);
}
void
......
......@@ -86,12 +86,10 @@ extern void machvec_noop (void);
# 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
......@@ -159,8 +157,6 @@ struct ia64_machine_vector {
platform_setup, \
platform_cpu_init, \
platform_irq_init, \
platform_pci_fixup, \
platform_map_nr, \
platform_mca_init, \
platform_mca_handler, \
platform_cmci_handler, \
......@@ -237,9 +233,6 @@ extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported;
#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
......
......@@ -16,7 +16,5 @@ extern ia64_mv_map_nr_t map_nr_dense;
#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 */
......@@ -15,6 +15,5 @@ extern ia64_mv_map_nr_t map_nr_dense;
#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 */
......@@ -22,8 +22,6 @@ extern ia64_mv_pci_dma_supported sba_dma_supported;
*/
#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
......
......@@ -68,10 +68,8 @@ extern ia64_mv_pci_dma_address sn1_dma_address;
#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
......
......@@ -73,10 +73,8 @@ extern ia64_mv_pci_dma_address sn1_dma_address;
#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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment