Commit d1127e40 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6:
  [IA64] ioremap() should prefer WB over UC
  [IA64] Add __mca_table to the DISCARD list in gate.lds
  [IA64] Move __mca_table out of the __init section
  [IA64] simplify some condition checks in iosapic_check_gsi_range
  [IA64] correct some messages and fixes some minor things
  [IA64-SGI] fix for-loop in sn_hwperf_geoid_to_cnode()
  [IA64-SGI] sn_hwperf use of num_online_cpus()
  [IA64] optimize flush_tlb_range on large numa box
  [IA64] lazy_mmu_prot_update needs to be aware of huge pages
parents 5abc97aa c1c57d76
...@@ -59,6 +59,7 @@ SECTIONS ...@@ -59,6 +59,7 @@ SECTIONS
*(.dynbss) *(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*) *(.bss .bss.* .gnu.linkonce.b.*)
*(__ex_table) *(__ex_table)
*(__mca_table)
} }
} }
......
...@@ -9,54 +9,65 @@ ...@@ -9,54 +9,65 @@
* Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
* *
* 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O
* In particular, we now have separate handlers for edge * APIC code. In particular, we now have separate
* and level triggered interrupts. * handlers for edge and level triggered
* 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation * interrupts.
* PCI to vector mapping, shared PCI interrupts. * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector
* 00/10/27 D. Mosberger Document things a bit more to make them more understandable. * allocation PCI to vector mapping, shared PCI
* Clean up much of the old IOSAPIC cruft. * interrupts.
* 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts and fixes for * 00/10/27 D. Mosberger Document things a bit more to make them more
* ACPI S5(SoftOff) support. * understandable. Clean up much of the old
* IOSAPIC cruft.
* 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts
* and fixes for ACPI S5(SoftOff) support.
* 02/01/23 J.I. Lee iosapic pgm fixes for PCI irq routing from _PRT * 02/01/23 J.I. Lee iosapic pgm fixes for PCI irq routing from _PRT
* 02/01/07 E. Focht <efocht@ess.nec.de> Redirectable interrupt vectors in * 02/01/07 E. Focht <efocht@ess.nec.de> Redirectable interrupt
* iosapic_set_affinity(), initializations for * vectors in iosapic_set_affinity(),
* /proc/irq/#/smp_affinity * initializations for /proc/irq/#/smp_affinity
* 02/04/02 P. Diefenbaugh Cleaned up ACPI PCI IRQ routing. * 02/04/02 P. Diefenbaugh Cleaned up ACPI PCI IRQ routing.
* 02/04/18 J.I. Lee bug fix in iosapic_init_pci_irq * 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 * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to
* error * IOSAPIC mapping error
* 02/07/29 T. Kochi Allocate interrupt vectors dynamically * 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
* 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's pci_irq code. * interrupt, vector, etc.)
* 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's
* pci_irq code.
* 03/02/19 B. Helgaas Make pcat_compat system-wide, not per-IOSAPIC. * 03/02/19 B. Helgaas Make pcat_compat system-wide, not per-IOSAPIC.
* Remove iosapic_address & gsi_base from external interfaces. * Remove iosapic_address & gsi_base from
* Rationalize __init/__devinit attributes. * external interfaces. Rationalize
* __init/__devinit attributes.
* 04/12/04 Ashok Raj <ashok.raj@intel.com> Intel Corporation 2004 * 04/12/04 Ashok Raj <ashok.raj@intel.com> Intel Corporation 2004
* Updated to work with irq migration necessary for CPU Hotplug * Updated to work with irq migration necessary
* for CPU Hotplug
*/ */
/* /*
* Here is what the interrupt logic between a PCI device and the kernel looks like: * Here is what the interrupt logic between a PCI device and the kernel looks
* like:
* *
* (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC,
* device is uniquely identified by its bus--, and slot-number (the function * INTD). The device is uniquely identified by its bus-, and slot-number
* number does not matter here because all functions share the same interrupt * (the function number does not matter here because all functions share
* lines). * the same interrupt lines).
* *
* (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller. * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC
* Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level * controller. Multiple interrupt lines may have to share the same
* triggered and use the same polarity). Each interrupt line has a unique Global * IOSAPIC pin (if they're level triggered and use the same polarity).
* System Interrupt (GSI) number which can be calculated as the sum of the controller's * Each interrupt line has a unique Global System Interrupt (GSI) number
* base GSI number and the IOSAPIC pin number to which the line connects. * which can be calculated as the sum of the controller's base GSI number
* and the IOSAPIC pin number to which the line connects.
* *
* (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the
* into the IA-64 interrupt vector. This interrupt vector is then sent to the CPU. * IOSAPIC pin into the IA-64 interrupt vector. This interrupt vector is then
* sent to the CPU.
* *
* (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is used as * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is
* architecture-independent interrupt handling mechanism in Linux. As an * used as architecture-independent interrupt handling mechanism in Linux.
* IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number * As an IRQ is a number, we have to have
* mapping. On smaller systems, we use one-to-one mapping between IA-64 vector and * IA-64 interrupt vector number <-> IRQ number mapping. On smaller
* IRQ. A platform can implement platform_irq_to_vector(irq) and * systems, we use one-to-one mapping between IA-64 vector and IRQ. A
* platform can implement platform_irq_to_vector(irq) and
* platform_local_vector_to_irq(vector) APIs to differentiate the mapping. * platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
* Please see also include/asm-ia64/hw_irq.h for those APIs. * Please see also include/asm-ia64/hw_irq.h for those APIs.
* *
...@@ -64,9 +75,9 @@ ...@@ -64,9 +75,9 @@
* *
* PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
* *
* Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts. * Note: The term "IRQ" is loosely used everywhere in Linux kernel to
* Now we use "IRQ" only for Linux IRQ's. ISA IRQ (isa_irq) is the only exception in this * describeinterrupts. Now we use "IRQ" only for Linux IRQ's. ISA IRQ
* source code. * (isa_irq) is the only exception in this source code.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -90,7 +101,6 @@ ...@@ -90,7 +101,6 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/system.h> #include <asm/system.h>
#undef DEBUG_INTERRUPT_ROUTING #undef DEBUG_INTERRUPT_ROUTING
#ifdef DEBUG_INTERRUPT_ROUTING #ifdef DEBUG_INTERRUPT_ROUTING
...@@ -99,36 +109,46 @@ ...@@ -99,36 +109,46 @@
#define DBG(fmt...) #define DBG(fmt...)
#endif #endif
#define NR_PREALLOCATE_RTE_ENTRIES (PAGE_SIZE / sizeof(struct iosapic_rte_info)) #define NR_PREALLOCATE_RTE_ENTRIES \
(PAGE_SIZE / sizeof(struct iosapic_rte_info))
#define RTE_PREALLOCATED (1) #define RTE_PREALLOCATED (1)
static DEFINE_SPINLOCK(iosapic_lock); static DEFINE_SPINLOCK(iosapic_lock);
/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ /*
* These tables map IA-64 vectors to the IOSAPIC pin that generates this
* vector.
*/
struct iosapic_rte_info { struct iosapic_rte_info {
struct list_head rte_list; /* node in list of RTEs sharing the same vector */ struct list_head rte_list; /* node in list of RTEs sharing the
* same vector */
char __iomem *addr; /* base address of IOSAPIC */ char __iomem *addr; /* base address of IOSAPIC */
unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this
* IOSAPIC */
char rte_index; /* IOSAPIC RTE index */ char rte_index; /* IOSAPIC RTE index */
int refcnt; /* reference counter */ int refcnt; /* reference counter */
unsigned int flags; /* flags */ unsigned int flags; /* flags */
} ____cacheline_aligned; } ____cacheline_aligned;
static struct iosapic_intr_info { static struct iosapic_intr_info {
struct list_head rtes; /* RTEs using this vector (empty => not an IOSAPIC interrupt) */ struct list_head rtes; /* RTEs using this vector (empty =>
* not an IOSAPIC interrupt) */
int count; /* # of RTEs that shares this vector */ int count; /* # of RTEs that shares this vector */
u32 low32; /* current value of low word of Redirection table entry */ u32 low32; /* current value of low word of
* Redirection table entry */
unsigned int dest; /* destination CPU physical ID */ unsigned int dest; /* destination CPU physical ID */
unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ unsigned char dmode : 3; /* delivery mode (see iosapic.h) */
unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ unsigned char polarity: 1; /* interrupt polarity
* (see iosapic.h) */
unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ unsigned char trigger : 1; /* trigger mode (see iosapic.h) */
} iosapic_intr_info[IA64_NUM_VECTORS]; } iosapic_intr_info[IA64_NUM_VECTORS];
static struct iosapic { static struct iosapic {
char __iomem *addr; /* base address of IOSAPIC */ char __iomem *addr; /* base address of IOSAPIC */
unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this
unsigned short num_rte; /* number of RTE in this IOSAPIC */ * IOSAPIC */
unsigned short num_rte; /* # of RTEs on this IOSAPIC */
int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ int rtes_inuse; /* # of RTEs in use on this IOSAPIC */
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
unsigned short node; /* numa node association via pxm */ unsigned short node; /* numa node association via pxm */
...@@ -149,7 +169,8 @@ find_iosapic (unsigned int gsi) ...@@ -149,7 +169,8 @@ find_iosapic (unsigned int gsi)
int i; int i;
for (i = 0; i < NR_IOSAPICS; i++) { for (i = 0; i < NR_IOSAPICS; i++) {
if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) if ((unsigned) (gsi - iosapic_lists[i].gsi_base) <
iosapic_lists[i].num_rte)
return i; return i;
} }
...@@ -162,7 +183,8 @@ _gsi_to_vector (unsigned int gsi) ...@@ -162,7 +183,8 @@ _gsi_to_vector (unsigned int gsi)
struct iosapic_intr_info *info; struct iosapic_intr_info *info;
struct iosapic_rte_info *rte; struct iosapic_rte_info *rte;
for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) for (info = iosapic_intr_info; info <
iosapic_intr_info + IA64_NUM_VECTORS; ++info)
list_for_each_entry(rte, &info->rtes, rte_list) list_for_each_entry(rte, &info->rtes, rte_list)
if (rte->gsi_base + rte->rte_index == gsi) if (rte->gsi_base + rte->rte_index == gsi)
return info - iosapic_intr_info; return info - iosapic_intr_info;
...@@ -185,8 +207,8 @@ gsi_to_irq (unsigned int gsi) ...@@ -185,8 +207,8 @@ gsi_to_irq (unsigned int gsi)
unsigned long flags; unsigned long flags;
int irq; int irq;
/* /*
* XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq * XXX fix me: this assumes an identity mapping between IA-64 vector
* numbers... * and Linux irq numbers...
*/ */
spin_lock_irqsave(&iosapic_lock, flags); spin_lock_irqsave(&iosapic_lock, flags);
{ {
...@@ -197,7 +219,8 @@ gsi_to_irq (unsigned int gsi) ...@@ -197,7 +219,8 @@ gsi_to_irq (unsigned int gsi)
return irq; return irq;
} }
static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec) static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi,
unsigned int vec)
{ {
struct iosapic_rte_info *rte; struct iosapic_rte_info *rte;
...@@ -237,7 +260,9 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) ...@@ -237,7 +260,9 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
for (irq = 0; irq < NR_IRQS; ++irq) for (irq = 0; irq < NR_IRQS; ++irq)
if (irq_to_vector(irq) == vector) { if (irq_to_vector(irq) == vector) {
set_irq_affinity_info(irq, (int)(dest & 0xffff), redir); set_irq_affinity_info(irq,
(int)(dest & 0xffff),
redir);
break; break;
} }
} }
...@@ -259,7 +284,7 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) ...@@ -259,7 +284,7 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
} }
static void static void
nop (unsigned int vector) nop (unsigned int irq)
{ {
/* do nothing... */ /* do nothing... */
} }
...@@ -281,7 +306,8 @@ mask_irq (unsigned int irq) ...@@ -281,7 +306,8 @@ mask_irq (unsigned int irq)
{ {
/* set only the mask bit */ /* set only the mask bit */
low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
rte_list) {
addr = rte->addr; addr = rte->addr;
rte_index = rte->rte_index; rte_index = rte->rte_index;
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
...@@ -306,7 +332,8 @@ unmask_irq (unsigned int irq) ...@@ -306,7 +332,8 @@ unmask_irq (unsigned int irq)
spin_lock_irqsave(&iosapic_lock, flags); spin_lock_irqsave(&iosapic_lock, flags);
{ {
low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
rte_list) {
addr = rte->addr; addr = rte->addr;
rte_index = rte->rte_index; rte_index = rte->rte_index;
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
...@@ -346,21 +373,25 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) ...@@ -346,21 +373,25 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
spin_lock_irqsave(&iosapic_lock, flags); spin_lock_irqsave(&iosapic_lock, flags);
{ {
low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); low32 = iosapic_intr_info[vec].low32 &
~(7 << IOSAPIC_DELIVERY_SHIFT);
if (redir) if (redir)
/* change delivery mode to lowest priority */ /* change delivery mode to lowest priority */
low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); low32 |= (IOSAPIC_LOWEST_PRIORITY <<
IOSAPIC_DELIVERY_SHIFT);
else else
/* change delivery mode to fixed */ /* change delivery mode to fixed */
low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
iosapic_intr_info[vec].low32 = low32; iosapic_intr_info[vec].low32 = low32;
iosapic_intr_info[vec].dest = dest; iosapic_intr_info[vec].dest = dest;
list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
rte_list) {
addr = rte->addr; addr = rte->addr;
rte_index = rte->rte_index; rte_index = rte->rte_index;
iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index),
high32);
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
} }
} }
...@@ -433,7 +464,8 @@ iosapic_ack_edge_irq (unsigned int irq) ...@@ -433,7 +464,8 @@ iosapic_ack_edge_irq (unsigned int irq)
* interrupt for real. This prevents IRQ storms from unhandled * interrupt for real. This prevents IRQ storms from unhandled
* devices. * devices.
*/ */
if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED)) if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) ==
(IRQ_PENDING|IRQ_DISABLED))
mask_irq(irq); mask_irq(irq);
} }
...@@ -467,7 +499,8 @@ iosapic_version (char __iomem *addr) ...@@ -467,7 +499,8 @@ iosapic_version (char __iomem *addr)
return iosapic_read(addr, IOSAPIC_VERSION); return iosapic_read(addr, IOSAPIC_VERSION);
} }
static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol) static int iosapic_find_sharable_vector (unsigned long trigger,
unsigned long pol)
{ {
int i, vector = -1, min_count = -1; int i, vector = -1, min_count = -1;
struct iosapic_intr_info *info; struct iosapic_intr_info *info;
...@@ -482,7 +515,8 @@ static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long po ...@@ -482,7 +515,8 @@ static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long po
for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) { for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
info = &iosapic_intr_info[i]; info = &iosapic_intr_info[i];
if (info->trigger == trigger && info->polarity == pol && if (info->trigger == trigger && info->polarity == pol &&
(info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) { (info->dmode == IOSAPIC_FIXED || info->dmode ==
IOSAPIC_LOWEST_PRIORITY)) {
if (min_count == -1 || info->count < min_count) { if (min_count == -1 || info->count < min_count) {
vector = i; vector = i;
min_count = info->count; min_count = info->count;
...@@ -506,12 +540,15 @@ iosapic_reassign_vector (int vector) ...@@ -506,12 +540,15 @@ iosapic_reassign_vector (int vector)
new_vector = assign_irq_vector(AUTO_ASSIGN); new_vector = assign_irq_vector(AUTO_ASSIGN);
if (new_vector < 0) if (new_vector < 0)
panic("%s: out of interrupt vectors!\n", __FUNCTION__); panic("%s: out of interrupt vectors!\n", __FUNCTION__);
printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); printk(KERN_INFO "Reassigning vector %d to %d\n",
vector, new_vector);
memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
sizeof(struct iosapic_intr_info)); sizeof(struct iosapic_intr_info));
INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes); INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes); list_move(iosapic_intr_info[vector].rtes.next,
memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); &iosapic_intr_info[new_vector].rtes);
memset(&iosapic_intr_info[vector], 0,
sizeof(struct iosapic_intr_info));
iosapic_intr_info[vector].low32 = IOSAPIC_MASK; iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
} }
...@@ -524,7 +561,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void) ...@@ -524,7 +561,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void)
int preallocated = 0; int preallocated = 0;
if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) { if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES); rte = alloc_bootmem(sizeof(struct iosapic_rte_info) *
NR_PREALLOCATE_RTE_ENTRIES);
if (!rte) if (!rte)
return NULL; return NULL;
for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++) for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
...@@ -532,7 +570,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void) ...@@ -532,7 +570,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void)
} }
if (!list_empty(&free_rte_list)) { if (!list_empty(&free_rte_list)) {
rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list); rte = list_entry(free_rte_list.next, struct iosapic_rte_info,
rte_list);
list_del(&rte->rte_list); list_del(&rte->rte_list);
preallocated++; preallocated++;
} else { } else {
...@@ -575,7 +614,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, ...@@ -575,7 +614,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
index = find_iosapic(gsi); index = find_iosapic(gsi);
if (index < 0) { if (index < 0) {
printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi); printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",
__FUNCTION__, gsi);
return -ENODEV; return -ENODEV;
} }
...@@ -586,7 +626,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, ...@@ -586,7 +626,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
if (!rte) { if (!rte) {
rte = iosapic_alloc_rte(); rte = iosapic_alloc_rte();
if (!rte) { if (!rte) {
printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__); printk(KERN_WARNING "%s: cannot allocate memory\n",
__FUNCTION__);
return -ENOMEM; return -ENOMEM;
} }
...@@ -602,7 +643,9 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, ...@@ -602,7 +643,9 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
else if (vector_is_shared(vector)) { else if (vector_is_shared(vector)) {
struct iosapic_intr_info *info = &iosapic_intr_info[vector]; struct iosapic_intr_info *info = &iosapic_intr_info[vector];
if (info->trigger != trigger || info->polarity != polarity) { if (info->trigger != trigger || info->polarity != polarity) {
printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__); printk (KERN_WARNING
"%s: cannot override the interrupt\n",
__FUNCTION__);
return -EINVAL; return -EINVAL;
} }
} }
...@@ -619,8 +662,10 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, ...@@ -619,8 +662,10 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
idesc = irq_descp(vector); idesc = irq_descp(vector);
if (idesc->handler != irq_type) { if (idesc->handler != irq_type) {
if (idesc->handler != &no_irq_type) if (idesc->handler != &no_irq_type)
printk(KERN_WARNING "%s: changing vector %d from %s to %s\n", printk(KERN_WARNING
__FUNCTION__, vector, idesc->handler->typename, irq_type->typename); "%s: changing vector %d from %s to %s\n",
__FUNCTION__, vector,
idesc->handler->typename, irq_type->typename);
idesc->handler = irq_type; idesc->handler = irq_type;
} }
return 0; return 0;
...@@ -681,7 +726,7 @@ get_target_cpu (unsigned int gsi, int vector) ...@@ -681,7 +726,7 @@ get_target_cpu (unsigned int gsi, int vector)
if (!num_cpus) if (!num_cpus)
goto skip_numa_setup; goto skip_numa_setup;
/* Use vector assigment to distribute across cpus in node */ /* Use vector assignment to distribute across cpus in node */
cpu_index = vector % num_cpus; cpu_index = vector % num_cpus;
for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++) for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
...@@ -703,7 +748,7 @@ get_target_cpu (unsigned int gsi, int vector) ...@@ -703,7 +748,7 @@ get_target_cpu (unsigned int gsi, int vector)
} while (!cpu_online(cpu)); } while (!cpu_online(cpu));
return cpu_physical_id(cpu); return cpu_physical_id(cpu);
#else #else /* CONFIG_SMP */
return cpu_physical_id(smp_processor_id()); return cpu_physical_id(smp_processor_id());
#endif #endif
} }
...@@ -755,7 +800,8 @@ iosapic_register_intr (unsigned int gsi, ...@@ -755,7 +800,8 @@ iosapic_register_intr (unsigned int gsi,
if (list_empty(&iosapic_intr_info[vector].rtes)) if (list_empty(&iosapic_intr_info[vector].rtes))
free_irq_vector(vector); free_irq_vector(vector);
spin_unlock(&iosapic_lock); spin_unlock(&iosapic_lock);
spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); spin_unlock_irqrestore(&irq_descp(vector)->lock,
flags);
goto again; goto again;
} }
...@@ -764,7 +810,8 @@ iosapic_register_intr (unsigned int gsi, ...@@ -764,7 +810,8 @@ iosapic_register_intr (unsigned int gsi,
polarity, trigger); polarity, trigger);
if (err < 0) { if (err < 0) {
spin_unlock(&iosapic_lock); spin_unlock(&iosapic_lock);
spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); spin_unlock_irqrestore(&irq_descp(vector)->lock,
flags);
return err; return err;
} }
...@@ -806,7 +853,8 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -806,7 +853,8 @@ iosapic_unregister_intr (unsigned int gsi)
*/ */
irq = gsi_to_irq(gsi); irq = gsi_to_irq(gsi);
if (irq < 0) { if (irq < 0) {
printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",
gsi);
WARN_ON(1); WARN_ON(1);
return; return;
} }
...@@ -817,7 +865,9 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -817,7 +865,9 @@ iosapic_unregister_intr (unsigned int gsi)
spin_lock(&iosapic_lock); spin_lock(&iosapic_lock);
{ {
if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) { if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); printk(KERN_ERR
"iosapic_unregister_intr(%u) unbalanced\n",
gsi);
WARN_ON(1); WARN_ON(1);
goto out; goto out;
} }
...@@ -827,7 +877,8 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -827,7 +877,8 @@ iosapic_unregister_intr (unsigned int gsi)
/* Mask the interrupt */ /* Mask the interrupt */
low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32); iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index),
low32);
/* Remove the rte entry from the list */ /* Remove the rte entry from the list */
list_del(&rte->rte_list); list_del(&rte->rte_list);
...@@ -840,7 +891,9 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -840,7 +891,9 @@ iosapic_unregister_intr (unsigned int gsi)
trigger = iosapic_intr_info[vector].trigger; trigger = iosapic_intr_info[vector].trigger;
polarity = iosapic_intr_info[vector].polarity; polarity = iosapic_intr_info[vector].polarity;
dest = iosapic_intr_info[vector].dest; dest = iosapic_intr_info[vector].dest;
printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n", printk(KERN_INFO
"GSI %u (%s, %s) -> CPU %d (0x%04x)"
" vector %d unregistered\n",
gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
cpu_logical_id(dest), dest, vector); cpu_logical_id(dest), dest, vector);
...@@ -853,12 +906,15 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -853,12 +906,15 @@ iosapic_unregister_intr (unsigned int gsi)
idesc->handler = &no_irq_type; idesc->handler = &no_irq_type;
/* Clear the interrupt information */ /* Clear the interrupt information */
memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); memset(&iosapic_intr_info[vector], 0,
sizeof(struct iosapic_intr_info));
iosapic_intr_info[vector].low32 |= IOSAPIC_MASK; iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
if (idesc->action) { if (idesc->action) {
printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq); printk(KERN_ERR
"interrupt handlers still exist on"
"IRQ %u\n", irq);
WARN_ON(1); WARN_ON(1);
} }
...@@ -873,7 +929,6 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -873,7 +929,6 @@ iosapic_unregister_intr (unsigned int gsi)
/* /*
* ACPI calls this when it finds an entry for a platform interrupt. * ACPI calls this when it finds an entry for a platform interrupt.
* Note that the irq_base and IOSAPIC address must be set in iosapic_init().
*/ */
int __init int __init
iosapic_register_platform_intr (u32 int_type, unsigned int gsi, iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
...@@ -907,13 +962,16 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi, ...@@ -907,13 +962,16 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
mask = 1; mask = 1;
break; break;
default: default:
printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type); printk(KERN_ERR "%s: invalid int type 0x%x\n", __FUNCTION__,
int_type);
return -1; return -1;
} }
register_intr(gsi, vector, delivery, polarity, trigger); register_intr(gsi, vector, delivery, polarity, trigger);
printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", printk(KERN_INFO
"PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)"
" vector %d\n",
int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown", int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
...@@ -923,10 +981,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi, ...@@ -923,10 +981,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
return vector; return vector;
} }
/* /*
* ACPI calls this when it finds an entry for a legacy ISA IRQ override. * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
* Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
*/ */
void __init void __init
iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
...@@ -955,16 +1011,19 @@ iosapic_system_init (int system_pcat_compat) ...@@ -955,16 +1011,19 @@ iosapic_system_init (int system_pcat_compat)
for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) { for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
iosapic_intr_info[vector].low32 = IOSAPIC_MASK; iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* mark as unused */ /* mark as unused */
INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
} }
pcat_compat = system_pcat_compat; pcat_compat = system_pcat_compat;
if (pcat_compat) { if (pcat_compat) {
/* /*
* Disable the compatibility mode interrupts (8259 style), needs IN/OUT support * Disable the compatibility mode interrupts (8259 style),
* enabled. * needs IN/OUT support enabled.
*/ */
printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__); printk(KERN_INFO
"%s: Disabling PC-AT compatible 8259 interrupts\n",
__FUNCTION__);
outb(0xff, 0xA1); outb(0xff, 0xA1);
outb(0xff, 0x21); outb(0xff, 0x21);
} }
...@@ -1004,10 +1063,7 @@ iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) ...@@ -1004,10 +1063,7 @@ iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
base = iosapic_lists[index].gsi_base; base = iosapic_lists[index].gsi_base;
end = base + iosapic_lists[index].num_rte - 1; end = base + iosapic_lists[index].num_rte - 1;
if (gsi_base < base && gsi_end < base) if (gsi_end < base || end < gsi_base)
continue;/* OK */
if (gsi_base > end && gsi_end > end)
continue; /* OK */ continue; /* OK */
return -EBUSY; return -EBUSY;
...@@ -1053,12 +1109,14 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) ...@@ -1053,12 +1109,14 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
if ((gsi_base == 0) && pcat_compat) { if ((gsi_base == 0) && pcat_compat) {
/* /*
* Map the legacy ISA devices into the IOSAPIC data. Some of these may * Map the legacy ISA devices into the IOSAPIC data. Some of
* get reprogrammed later on with data from the ACPI Interrupt Source * these may get reprogrammed later on with data from the ACPI
* Override table. * Interrupt Source Override table.
*/ */
for (isa_irq = 0; isa_irq < 16; ++isa_irq) for (isa_irq = 0; isa_irq < 16; ++isa_irq)
iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); iosapic_override_isa_irq(isa_irq, isa_irq,
IOSAPIC_POL_HIGH,
IOSAPIC_EDGE);
} }
return 0; return 0;
} }
...@@ -1081,7 +1139,8 @@ iosapic_remove (unsigned int gsi_base) ...@@ -1081,7 +1139,8 @@ iosapic_remove (unsigned int gsi_base)
if (iosapic_lists[index].rtes_inuse) { if (iosapic_lists[index].rtes_inuse) {
err = -EBUSY; err = -EBUSY;
printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", printk(KERN_WARNING
"%s: IOSAPIC for GSI base %u is busy\n",
__FUNCTION__, gsi_base); __FUNCTION__, gsi_base);
goto out; goto out;
} }
......
...@@ -70,6 +70,15 @@ SECTIONS ...@@ -70,6 +70,15 @@ SECTIONS
__stop___ex_table = .; __stop___ex_table = .;
} }
/* MCA table */
. = ALIGN(16);
__mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET)
{
__start___mca_table = .;
*(__mca_table)
__stop___mca_table = .;
}
/* Global data */ /* Global data */
_data = .; _data = .;
...@@ -130,15 +139,6 @@ SECTIONS ...@@ -130,15 +139,6 @@ SECTIONS
__initcall_end = .; __initcall_end = .;
} }
/* MCA table */
. = ALIGN(16);
__mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET)
{
__start___mca_table = .;
*(__mca_table)
__stop___mca_table = .;
}
.data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET)
{ {
__start___vtop_patchlist = .; __start___vtop_patchlist = .;
......
...@@ -109,6 +109,7 @@ lazy_mmu_prot_update (pte_t pte) ...@@ -109,6 +109,7 @@ lazy_mmu_prot_update (pte_t pte)
{ {
unsigned long addr; unsigned long addr;
struct page *page; struct page *page;
unsigned long order;
if (!pte_exec(pte)) if (!pte_exec(pte))
return; /* not an executable page... */ return; /* not an executable page... */
...@@ -119,6 +120,11 @@ lazy_mmu_prot_update (pte_t pte) ...@@ -119,6 +120,11 @@ lazy_mmu_prot_update (pte_t pte)
if (test_bit(PG_arch_1, &page->flags)) if (test_bit(PG_arch_1, &page->flags))
return; /* i-cache is already coherent with d-cache */ return; /* i-cache is already coherent with d-cache */
if (PageCompound(page)) {
order = (unsigned long) (page[1].lru.prev);
flush_icache_range(addr, addr + (1UL << order << PAGE_SHIFT));
}
else
flush_icache_range(addr, addr + PAGE_SIZE); flush_icache_range(addr, addr + PAGE_SIZE);
set_bit(PG_arch_1, &page->flags); /* mark page as clean */ set_bit(PG_arch_1, &page->flags); /* mark page as clean */
} }
......
...@@ -21,12 +21,12 @@ __ioremap (unsigned long offset, unsigned long size) ...@@ -21,12 +21,12 @@ __ioremap (unsigned long offset, unsigned long size)
void __iomem * void __iomem *
ioremap (unsigned long offset, unsigned long size) ioremap (unsigned long offset, unsigned long size)
{ {
if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC))
return __ioremap(offset, size);
if (efi_mem_attribute_range(offset, size, EFI_MEMORY_WB)) if (efi_mem_attribute_range(offset, size, EFI_MEMORY_WB))
return phys_to_virt(offset); return phys_to_virt(offset);
if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC))
return __ioremap(offset, size);
/* /*
* Someday this should check ACPI resources so we * Someday this should check ACPI resources so we
* can do the right thing for hot-plugged regions. * can do the right thing for hot-plugged regions.
......
...@@ -156,17 +156,19 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start, ...@@ -156,17 +156,19 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start,
nbits = purge.max_bits; nbits = purge.max_bits;
start &= ~((1UL << nbits) - 1); start &= ~((1UL << nbits) - 1);
# ifdef CONFIG_SMP
platform_global_tlb_purge(mm, start, end, nbits);
# else
preempt_disable(); preempt_disable();
#ifdef CONFIG_SMP
if (mm != current->active_mm || cpus_weight(mm->cpu_vm_mask) != 1) {
platform_global_tlb_purge(mm, start, end, nbits);
preempt_enable();
return;
}
#endif
do { do {
ia64_ptcl(start, (nbits<<2)); ia64_ptcl(start, (nbits<<2));
start += (1UL << nbits); start += (1UL << nbits);
} while (start < end); } while (start < end);
preempt_enable(); preempt_enable();
# endif
ia64_srlz_i(); /* srlz.i implies srlz.d */ ia64_srlz_i(); /* srlz.i implies srlz.d */
} }
EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(flush_tlb_range);
......
...@@ -110,7 +110,11 @@ static int sn_hwperf_geoid_to_cnode(char *location) ...@@ -110,7 +110,11 @@ static int sn_hwperf_geoid_to_cnode(char *location)
if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
return -1; return -1;
for_each_node(cnode) { /*
* FIXME: replace with cleaner for_each_XXX macro which addresses
* both compute and IO nodes once ACPI3.0 is available.
*/
for (cnode = 0; cnode < num_cnodes; cnode++) {
geoid = cnodeid_get_geoid(cnode); geoid = cnodeid_get_geoid(cnode);
module_id = geo_module(geoid); module_id = geo_module(geoid);
this_rack = MODULE_GET_RACK(module_id); this_rack = MODULE_GET_RACK(module_id);
...@@ -605,7 +609,7 @@ static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info) ...@@ -605,7 +609,7 @@ static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info)
op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK; op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;
if (cpu != SN_HWPERF_ARG_ANY_CPU) { if (cpu != SN_HWPERF_ARG_ANY_CPU) {
if (cpu >= num_online_cpus() || !cpu_online(cpu)) { if (cpu >= NR_CPUS || !cpu_online(cpu)) {
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
......
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
/* /*
* Helper macros for accessing user memory. * Helper macros for accessing user memory.
*
* When adding any new .section/.previous entries here, make sure to
* also add it to the DISCARD section in arch/ia64/kernel/gate.lds.S or
* unpleasant things will happen.
*/ */
.section "__ex_table", "a" // declare section & section attributes .section "__ex_table", "a" // declare section & section attributes
......
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