summaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-11-23 02:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-11-23 02:00:47 +0000
commit06615f62b17d7de6e12d2f5ec6b88cf30af08413 (patch)
tree8766f208847d4876a6db619aebbf54d53b76eb44 /arch/ia64/kernel
parentfa9bdb574f4febb751848a685d9a9017e04e1d53 (diff)
Merge with Linux 2.4.0-test10.
Diffstat (limited to 'arch/ia64/kernel')
-rw-r--r--arch/ia64/kernel/Makefile6
-rw-r--r--arch/ia64/kernel/acpi.c48
-rw-r--r--arch/ia64/kernel/efi.c51
-rw-r--r--arch/ia64/kernel/entry.S5
-rw-r--r--arch/ia64/kernel/fw-emu.c9
-rw-r--r--arch/ia64/kernel/head.S2
-rw-r--r--arch/ia64/kernel/ia64_ksyms.c51
-rw-r--r--arch/ia64/kernel/irq.c3
-rw-r--r--arch/ia64/kernel/irq_ia64.c17
-rw-r--r--arch/ia64/kernel/ivt.S233
-rw-r--r--arch/ia64/kernel/mca.c34
-rw-r--r--arch/ia64/kernel/mca_asm.S26
-rw-r--r--arch/ia64/kernel/minstate.h10
-rw-r--r--arch/ia64/kernel/pal.S19
-rw-r--r--arch/ia64/kernel/palinfo.c72
-rw-r--r--arch/ia64/kernel/pci-dma.c15
-rw-r--r--arch/ia64/kernel/perfmon.c236
-rw-r--r--arch/ia64/kernel/process.c60
-rw-r--r--arch/ia64/kernel/ptrace.c147
-rw-r--r--arch/ia64/kernel/sal.c5
-rw-r--r--arch/ia64/kernel/semaphore.c8
-rw-r--r--arch/ia64/kernel/setup.c35
-rw-r--r--arch/ia64/kernel/signal.c29
-rw-r--r--arch/ia64/kernel/smp.c221
-rw-r--r--arch/ia64/kernel/smpboot.c74
-rw-r--r--arch/ia64/kernel/sys_ia64.c20
-rw-r--r--arch/ia64/kernel/time.c4
-rw-r--r--arch/ia64/kernel/traps.c82
-rw-r--r--arch/ia64/kernel/unaligned.c60
-rw-r--r--arch/ia64/kernel/unwind.c381
-rw-r--r--arch/ia64/kernel/unwind_i.h14
31 files changed, 1260 insertions, 717 deletions
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 563c308ea..7a49511d3 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -3,9 +3,9 @@
#
.S.s:
- $(CPP) $(AFLAGS) -o $*.s $<
+ $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $<
.S.o:
- $(CC) $(AFLAGS) -c -o $*.o $<
+ $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $<
all: kernel.o head.o init_task.o
@@ -16,7 +16,7 @@ obj-y := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_sapic.o ivt
obj-$(CONFIG_IA64_GENERIC) += machvec.o
obj-$(CONFIG_IA64_PALINFO) += palinfo.o
obj-$(CONFIG_PCI) += pci.o
-obj-$(CONFIG_SMP) += smp.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
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 4bba56e1d..a8c1ead1f 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -24,18 +24,17 @@
#include <asm/iosapic.h>
#include <asm/machvec.h>
#include <asm/page.h>
+#ifdef CONFIG_ACPI_KERNEL_CONFIG
+# include <asm/acpikcfg.h>
+#endif
#undef ACPI_DEBUG /* Guess what this does? */
-#ifdef CONFIG_SMP
-extern struct smp_boot_data smp;
-#endif
-
/* These are ugly but will be reclaimed by the kernel */
-int __initdata available_cpus = 0;
-int __initdata total_cpus = 0;
+int __initdata available_cpus;
+int __initdata total_cpus;
-void (*pm_idle) (void);
+void (*pm_idle)(void);
/*
* Identify usable CPU's and remember them for SMP bringup later.
@@ -60,18 +59,16 @@ acpi_lsapic(char *p)
add = 0;
}
+#ifdef CONFIG_SMP
+ smp_boot_data.cpu_phys_id[total_cpus] = -1;
+#endif
if (add) {
printk("Available.\n");
available_cpus++;
#ifdef CONFIG_SMP
-# if LARGE_CPU_ID_OK
- smp.cpu_map[total_cpus] = (lsapic->id << 8) | lsapic->eid;
-# else
- smp.cpu_map[total_cpus] = lsapic->id;
-# endif
-#endif
+ smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
+#endif /* CONFIG_SMP */
}
-
total_cpus++;
}
@@ -139,13 +136,12 @@ acpi_legacy_irq(char *p)
break;
}
-#if 1/*def ACPI_DEBUG*/
+# ifdef ACPI_DEBUG
printk("Legacy ISA IRQ %x -> IA64 Vector %x IOSAPIC Pin %x Active %s %s Trigger\n",
legacy->isa_irq, vector, iosapic_pin(vector),
((iosapic_polarity(vector) == IO_SAPIC_POL_LOW) ? "Low" : "High"),
((iosapic_trigger(vector) == IO_SAPIC_LEVEL) ? "Level" : "Edge"));
-#endif /* ACPI_DEBUG */
-
+# endif /* ACPI_DEBUG */
#endif /* CONFIG_IA64_IRQ_ACPI */
}
@@ -172,10 +168,6 @@ acpi_parse_msapic(acpi_sapic_t *msapic)
/* Base address of IPI Message Block */
ipi_base_addr = (unsigned long) ioremap(msapic->interrupt_block, 0);
-#ifdef CONFIG_SMP
- memset(&smp, -1, sizeof(smp));
-#endif
-
p = (char *) (msapic + 1);
end = p + (msapic->header.length - sizeof(acpi_sapic_t));
@@ -248,6 +240,10 @@ acpi_parse(acpi_rsdp_t *rsdp)
printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id,
rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff);
+#ifdef CONFIG_ACPI_KERNEL_CONFIG
+ acpi_cf_init(rsdp);
+#endif
+
tables = (rsdt->header.length - sizeof(acpi_desc_table_hdr_t)) / 8;
for (i = 0; i < tables; i++) {
hdrp = (acpi_desc_table_hdr_t *) __va(rsdt->entry_ptrs[i]);
@@ -259,12 +255,16 @@ acpi_parse(acpi_rsdp_t *rsdp)
acpi_parse_msapic((acpi_sapic_t *) hdrp);
}
+#ifdef CONFIG_ACPI_KERNEL_CONFIG
+ acpi_cf_terminate();
+#endif
+
#ifdef CONFIG_SMP
if (available_cpus == 0) {
printk("ACPI: Found 0 CPUS; assuming 1\n");
available_cpus = 1; /* We've got at least one of these, no? */
}
- smp.cpu_count = available_cpus;
+ smp_boot_data.cpu_count = available_cpus;
#endif
return 1;
}
@@ -278,7 +278,7 @@ acpi_get_sysname (void)
#else
# if defined (CONFIG_IA64_HP_SIM)
return "hpsim";
-# elif defined (CONFIG_IA64_SGI_SN1_SIM)
+# elif defined (CONFIG_IA64_SGI_SN1)
return "sn1";
# elif defined (CONFIG_IA64_DIG)
return "dig";
@@ -286,4 +286,4 @@ acpi_get_sysname (void)
# error Unknown platform. Fix acpi.c.
# endif
#endif
-}
+}
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 32d83ae75..759db7f52 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -18,6 +18,7 @@
* Goutham Rao: <goutham.rao@intel.com>
* Skip non-WB memory and ignore empty memory ranges.
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -216,12 +217,41 @@ efi_map_pal_code (void)
md->phys_addr);
continue;
}
- mask = ~((1 << _PAGE_SIZE_4M)-1); /* XXX should be dynamic? */
+ /*
+ * We must use the same page size as the one used
+ * for the kernel region when we map the PAL code.
+ * This way, we avoid overlapping TRs if code is
+ * executed nearby. The Alt I-TLB installs 256MB
+ * page sizes as defined for region 7.
+ *
+ * XXX Fixme: should be dynamic here (for page size)
+ */
+ mask = ~((1 << _PAGE_SIZE_256M)-1);
vaddr = PAGE_OFFSET + md->phys_addr;
- printk(__FUNCTION__": mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
- md->phys_addr, md->phys_addr + (md->num_pages << 12),
- vaddr & mask, (vaddr & mask) + 4*1024*1024);
+ /*
+ * We must check that the PAL mapping won't overlap
+ * with the kernel mapping on ITR1.
+ *
+ * PAL code is guaranteed to be aligned on a power of 2
+ * between 4k and 256KB.
+ * Also from the documentation, it seems like there is an
+ * implicit guarantee that you will need only ONE ITR to
+ * map it. This implies that the PAL code is always aligned
+ * on its size, i.e., the closest matching page size supported
+ * by the TLB. Therefore PAL code is guaranteed never to cross
+ * a 256MB unless it is bigger than 256MB (very unlikely!).
+ * So for now the following test is enough to determine whether
+ * or not we need a dedicated ITR for the PAL code.
+ */
+ if ((vaddr & mask) == (PAGE_OFFSET & mask)) {
+ printk(__FUNCTION__ " : no need to install ITR for PAL Code\n");
+ continue;
+ }
+
+ printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
+ smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12),
+ vaddr & mask, (vaddr & mask) + 256*1024*1024);
/*
* Cannot write to CRx with PSR.ic=1
@@ -232,12 +262,11 @@ efi_map_pal_code (void)
* ITR0/DTR0: used for kernel code/data
* ITR1/DTR1: used by HP simulator
* ITR2/DTR2: map PAL code
- * ITR3/DTR3: used to map PAL calls buffer
*/
ia64_itr(0x1, 2, vaddr & mask,
pte_val(mk_pte_phys(md->phys_addr,
__pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX))),
- _PAGE_SIZE_4M);
+ _PAGE_SIZE_256M);
local_irq_restore(flags);
ia64_srlz_i ();
}
@@ -348,6 +377,16 @@ efi_init (void)
#endif
efi_map_pal_code();
+
+#ifndef CONFIG_IA64_SOFTSDV_HACKS
+ /*
+ * (Some) SoftSDVs seem to have a problem with this call.
+ * Since it's mostly a performance optimization, just don't do
+ * it for now... --davidm 99/12/6
+ */
+ efi_enter_virtual_mode();
+#endif
+
}
void
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index eba75378e..ffb1760ea 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -120,6 +120,9 @@ GLOBAL_ENTRY(ia64_switch_to)
mov r13=in0 // set "current" pointer
;;
DO_LOAD_SWITCH_STACK( )
+#ifdef CONFIG_SMP
+ sync.i // ensure "fc"s done by this CPU are visible on other CPUs
+#endif
br.ret.sptk.few rp
END(ia64_switch_to)
@@ -1088,7 +1091,7 @@ sys_call_table:
data8 sys_setpriority
data8 sys_statfs
data8 sys_fstatfs
- data8 sys_ioperm // 1105
+ data8 ia64_ni_syscall
data8 sys_semget
data8 sys_semop
data8 sys_semctl
diff --git a/arch/ia64/kernel/fw-emu.c b/arch/ia64/kernel/fw-emu.c
index c34bbaeee..34316fe58 100644
--- a/arch/ia64/kernel/fw-emu.c
+++ b/arch/ia64/kernel/fw-emu.c
@@ -20,7 +20,7 @@
#define MB (1024*1024UL)
-#define NUM_MEM_DESCS 3
+#define NUM_MEM_DESCS 2
static char fw_mem[( sizeof(efi_system_table_t)
+ sizeof(efi_runtime_services_t)
@@ -453,6 +453,12 @@ sys_fw_init (const char *args, int arglen)
md->num_pages = (1*MB) >> 12; /* 1MB (in 4KB pages) */
md->attribute = EFI_MEMORY_WB;
+#if 0
+ /*
+ * XXX bootmem is broken for now... (remember to NUM_MEM_DESCS
+ * if you re-enable this!)
+ */
+
/* descriptor for high memory (>4GB): */
md = &efi_memmap[2];
md->type = EFI_CONVENTIONAL_MEMORY;
@@ -461,6 +467,7 @@ sys_fw_init (const char *args, int arglen)
md->virt_addr = 0;
md->num_pages = (32*MB) >> 12; /* 32MB (in 4KB pages) */
md->attribute = EFI_MEMORY_WB;
+#endif
bp = id(ZERO_PAGE_ADDR);
bp->efi_systab = __pa(&fw_mem);
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index bea14236d..e6298b297 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -111,7 +111,7 @@ GLOBAL_ENTRY(_start)
* be implemented more efficiently (for example, __switch_to()
* always sets the psr.dfh bit of the task it is switching to).
*/
- addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2
+ addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2
addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE
mov ar.rsc=r0 // place RSE in enforced lazy mode
;;
diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
index 62e792612..d3d2416cf 100644
--- a/arch/ia64/kernel/ia64_ksyms.c
+++ b/arch/ia64/kernel/ia64_ksyms.c
@@ -10,6 +10,7 @@ EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memscan);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strcmp);
@@ -18,6 +19,8 @@ EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strtok);
@@ -27,24 +30,58 @@ EXPORT_SYMBOL(pci_free_consistent);
#include <linux/in6.h>
#include <asm/checksum.h>
+/* not coded yet?? EXPORT_SYMBOL(csum_ipv6_magic); */
EXPORT_SYMBOL(csum_partial_copy_nocheck);
+EXPORT_SYMBOL(csum_tcpudp_magic);
+EXPORT_SYMBOL(ip_compute_csum);
+EXPORT_SYMBOL(ip_fast_csum);
+
+#include <asm/io.h>
+EXPORT_SYMBOL(__ia64_memcpy_fromio);
+EXPORT_SYMBOL(__ia64_memcpy_toio);
+EXPORT_SYMBOL(__ia64_memset_c_io);
#include <asm/irq.h>
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
+
+#include <asm/page.h>
+EXPORT_SYMBOL(clear_page);
+
+#include <asm/pci.h>
+EXPORT_SYMBOL(pci_dma_sync_sg);
+EXPORT_SYMBOL(pci_dma_sync_single);
+EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_unmap_sg);
+EXPORT_SYMBOL(pci_unmap_single);
#include <asm/processor.h>
EXPORT_SYMBOL(cpu_data);
EXPORT_SYMBOL(kernel_thread);
+#include <asm/system.h>
+#ifdef CONFIG_IA64_DEBUG_IRQ
+EXPORT_SYMBOL(last_cli_ip);
+#endif
+
#ifdef CONFIG_SMP
+
+#include <asm/current.h>
#include <asm/hardirq.h>
EXPORT_SYMBOL(synchronize_irq);
+#include <asm/smp.h>
+EXPORT_SYMBOL(smp_call_function);
+
+#include <linux/smp.h>
+EXPORT_SYMBOL(smp_num_cpus);
+
#include <asm/smplock.h>
EXPORT_SYMBOL(kernel_flag);
-#include <asm/system.h>
+/* #include <asm/system.h> */
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_save_flags);
@@ -54,17 +91,29 @@ EXPORT_SYMBOL(__global_restore_flags);
#include <asm/uaccess.h>
EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(__do_clear_user);
#include <asm/unistd.h>
EXPORT_SYMBOL(__ia64_syscall);
/* from arch/ia64/lib */
+extern void __divsi3(void);
+extern void __udivsi3(void);
+extern void __modsi3(void);
+extern void __umodsi3(void);
extern void __divdi3(void);
extern void __udivdi3(void);
extern void __moddi3(void);
extern void __umoddi3(void);
+EXPORT_SYMBOL_NOVERS(__divsi3);
+EXPORT_SYMBOL_NOVERS(__udivsi3);
+EXPORT_SYMBOL_NOVERS(__modsi3);
+EXPORT_SYMBOL_NOVERS(__umodsi3);
EXPORT_SYMBOL_NOVERS(__divdi3);
EXPORT_SYMBOL_NOVERS(__udivdi3);
EXPORT_SYMBOL_NOVERS(__moddi3);
EXPORT_SYMBOL_NOVERS(__umoddi3);
+
+extern unsigned long ia64_iobase;
+EXPORT_SYMBOL(ia64_iobase);
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index c913fdc3d..30d4def40 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -536,8 +536,7 @@ void enable_irq(unsigned int irq)
desc->depth--;
break;
case 0:
- printk("enable_irq() unbalanced from %p\n",
- __builtin_return_address(0));
+ printk("enable_irq() unbalanced from %p\n", (void *) __builtin_return_address(0));
}
spin_unlock_irqrestore(&desc->lock, flags);
}
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index fe686db0e..2166e205f 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -39,7 +39,8 @@
spinlock_t ivr_read_lock;
#endif
-unsigned long ipi_base_addr = IPI_DEFAULT_BASE_ADDR; /* default base addr of IPI table */
+/* default base addr of IPI table */
+unsigned long ipi_base_addr = (__IA64_UNCACHED_OFFSET | IPI_DEFAULT_BASE_ADDR);
/*
* Legacy IRQ to IA-64 vector translation table. Any vector not in
@@ -220,13 +221,23 @@ ipi_send (int cpu, int vector, int delivery_mode, int redirect)
{
unsigned long ipi_addr;
unsigned long ipi_data;
+ unsigned long phys_cpu_id;
#ifdef CONFIG_ITANIUM_A1_SPECIFIC
unsigned long flags;
#endif
-# define EID 0
+
+#ifdef CONFIG_SMP
+ phys_cpu_id = cpu_physical_id(cpu);
+#else
+ phys_cpu_id = (ia64_get_lid() >> 16) & 0xffff;
+#endif
+
+ /*
+ * cpu number is in 8bit ID and 8bit EID
+ */
ipi_data = (delivery_mode << 8) | (vector & 0xff);
- ipi_addr = ipi_base_addr | ((cpu << 8 | EID) << 4) | ((redirect & 1) << 3);
+ ipi_addr = ipi_base_addr | (phys_cpu_id << 4) | ((redirect & 1) << 3);
#ifdef CONFIG_ITANIUM_A1_SPECIFIC
spin_lock_irqsave(&ivr_read_lock, flags);
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index d1b599f77..fa0ad0993 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -4,6 +4,8 @@
* Copyright (C) 1998-2000 Hewlett-Packard Co
* Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 1998-2000 David Mosberger <davidm@hpl.hp.com>
+ *
+ * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling for SMP
*/
/*
* This file defines the interrupt vector table used by the CPU.
@@ -134,32 +136,51 @@ ia64_ivt:
(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL?
dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry
;;
-(p7) ld8 r17=[r17] // fetch the L2 entry (may be 0)
+(p7) ld8 r20=[r17] // fetch the L2 entry (may be 0)
shr.u r19=r16,PAGE_SHIFT // shift L3 index into position
;;
-(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL?
- dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry
+(p7) cmp.eq.or.andcm p6,p7=r20,r0 // was L2 entry NULL?
+ dep r21=r19,r20,3,(PAGE_SHIFT-3) // compute address of L3 page table entry
;;
-(p7) ld8 r18=[r17] // read the L3 PTE
+(p7) ld8 r18=[r21] // read the L3 PTE
mov r19=cr.isr // cr.isr bit 0 tells us if this is an insn miss
;;
(p7) tbit.z p6,p7=r18,0 // page present bit cleared?
- mov r21=cr.iha // get the VHPT address that caused the TLB miss
+ mov r22=cr.iha // get the VHPT address that caused the TLB miss
;; // avoid RAW on p7
(p7) tbit.nz.unc p10,p11=r19,32 // is it an instruction TLB miss?
- dep r17=0,r17,0,PAGE_SHIFT // clear low bits to get page address
+ dep r23=0,r20,0,PAGE_SHIFT // clear low bits to get page address
;;
(p10) itc.i r18 // insert the instruction TLB entry
(p11) itc.d r18 // insert the data TLB entry
(p6) br.spnt.few page_fault // handle bad address/page not present (page fault)
- mov cr.ifa=r21
+ mov cr.ifa=r22
// Now compute and insert the TLB entry for the virtual page table.
// We never execute in a page table page so there is no need to set
// the exception deferral bit.
- adds r16=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r17
+ adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23
+ ;;
+(p7) itc.d r24
+ ;;
+#ifdef CONFIG_SMP
+ //
+ // Re-check L2 and L3 pagetable. If they changed, we may have received
+ // a ptc.g between reading the pagetable and the "itc". If so,
+ // flush the entry we inserted and retry.
+ //
+ ld8 r25=[r21] // read L3 PTE again
+ ld8 r26=[r17] // read L2 entry again
+ ;;
+ cmp.ne p6,p7=r26,r20 // did L2 entry change
+ mov r27=PAGE_SHIFT<<2
+ ;;
+(p6) ptc.l r22,r27 // purge PTE page translation
+(p7) cmp.ne.or.andcm p6,p7=r25,r18 // did L3 PTE change
;;
-(p7) itc.d r16
+(p6) ptc.l r16,r27 // purge translation
+#endif
+
mov pr=r31,-1 // restore predicate registers
rfi
@@ -175,22 +196,32 @@ ia64_ivt:
* The speculative access will fail if there is no TLB entry
* for the L3 page table page we're trying to access.
*/
- mov r16=cr.iha // get virtual address of L3 PTE
+ mov r16=cr.ifa // get virtual address
+ mov r19=cr.iha // get virtual address of L3 PTE
;;
- ld8.s r16=[r16] // try to read L3 PTE
+ ld8.s r17=[r19] // try to read L3 PTE
mov r31=pr // save predicates
;;
- tnat.nz p6,p0=r16 // did read succeed?
+ tnat.nz p6,p0=r17 // did read succeed?
(p6) br.cond.spnt.many 1f
;;
- itc.i r16
+ itc.i r17
+ ;;
+#ifdef CONFIG_SMP
+ ld8.s r18=[r19] // try to read L3 PTE again and see if same
+ mov r20=PAGE_SHIFT<<2 // setup page size for purge
;;
+ cmp.eq p6,p7=r17,r18
+ ;;
+(p7) ptc.l r16,r20
+#endif
mov pr=r31,-1
rfi
-1: mov r16=cr.ifa // get address that caused the TLB miss
- ;;
- rsm psr.dt // use physical addressing for data
+#ifdef CONFIG_DISABLE_VHPT
+itlb_fault:
+#endif
+1: rsm psr.dt // use physical addressing for data
mov r19=ar.k7 // get page table base address
shl r21=r16,3 // shift bit 60 into sign bit
shr.u r17=r16,61 // get the region number into r17
@@ -228,6 +259,15 @@ ia64_ivt:
(p7) itc.i r18 // insert the instruction TLB entry
(p6) br.spnt.few page_fault // handle bad address/page not present (page fault)
;;
+#ifdef CONFIG_SMP
+ ld8 r19=[r17] // re-read the PTE and check if same
+ ;;
+ cmp.eq p6,p7=r18,r19
+ mov r20=PAGE_SHIFT<<2
+ ;;
+(p7) ptc.l r16,r20 // PTE changed purge translation
+#endif
+
mov pr=r31,-1 // restore predicate registers
rfi
@@ -243,22 +283,32 @@ ia64_ivt:
* The speculative access will fail if there is no TLB entry
* for the L3 page table page we're trying to access.
*/
- mov r16=cr.iha // get virtual address of L3 PTE
+ mov r16=cr.ifa // get virtual address
+ mov r19=cr.iha // get virtual address of L3 PTE
;;
- ld8.s r16=[r16] // try to read L3 PTE
+ ld8.s r17=[r19] // try to read L3 PTE
mov r31=pr // save predicates
;;
- tnat.nz p6,p0=r16 // did read succeed?
+ tnat.nz p6,p0=r17 // did read succeed?
(p6) br.cond.spnt.many 1f
;;
- itc.d r16
+ itc.d r17
+ ;;
+#ifdef CONFIG_SMP
+ ld8.s r18=[r19] // try to read L3 PTE again and see if same
+ mov r20=PAGE_SHIFT<<2 // setup page size for purge
;;
+ cmp.eq p6,p7=r17,r18
+ ;;
+(p7) ptc.l r16,r20
+#endif
mov pr=r31,-1
rfi
-1: mov r16=cr.ifa // get address that caused the TLB miss
- ;;
- rsm psr.dt // use physical addressing for data
+#ifdef CONFIG_DISABLE_VHPT
+dtlb_fault:
+#endif
+1: rsm psr.dt // use physical addressing for data
mov r19=ar.k7 // get page table base address
shl r21=r16,3 // shift bit 60 into sign bit
shr.u r17=r16,61 // get the region number into r17
@@ -296,6 +346,14 @@ ia64_ivt:
(p7) itc.d r18 // insert the instruction TLB entry
(p6) br.spnt.few page_fault // handle bad address/page not present (page fault)
;;
+#ifdef CONFIG_SMP
+ ld8 r19=[r17] // re-read the PTE and check if same
+ ;;
+ cmp.eq p6,p7=r18,r19
+ mov r20=PAGE_SHIFT<<2
+ ;;
+(p7) ptc.l r16,r20 // PTE changed purge translation
+#endif
mov pr=r31,-1 // restore predicate registers
rfi
@@ -303,6 +361,16 @@ ia64_ivt:
/////////////////////////////////////////////////////////////////////////////////////////
// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19)
mov r16=cr.ifa // get address that caused the TLB miss
+#ifdef CONFIG_DISABLE_VHPT
+ mov r31=pr
+ ;;
+ shr.u r21=r16,61 // get the region number into r21
+ ;;
+ cmp.gt p6,p0=6,r21 // user mode
+(p6) br.cond.dptk.many itlb_fault
+ ;;
+ mov pr=r31,-1
+#endif
movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX
;;
shr.u r18=r16,57 // move address bit 61 to bit 4
@@ -323,8 +391,14 @@ ia64_ivt:
movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW
mov r20=cr.isr
mov r21=cr.ipsr
- mov r19=pr
+ mov r31=pr
+ ;;
+#ifdef CONFIG_DISABLE_VHPT
+ shr.u r22=r16,61 // get the region number into r21
;;
+ cmp.gt p8,p0=6,r22 // user mode
+(p8) br.cond.dptk.many dtlb_fault
+#endif
tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on?
shr.u r18=r16,57 // move address bit 61 to bit 4
dep r16=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits
@@ -337,7 +411,7 @@ ia64_ivt:
(p6) mov cr.ipsr=r21
;;
(p7) itc.d r16 // insert the TLB entry
- mov pr=r19,-1
+ mov pr=r31,-1
rfi
;;
@@ -452,6 +526,7 @@ page_fault:
// a nested TLB miss hit where we look up the physical address of the L3 PTE
// and then continue at label 1 below.
//
+#ifndef CONFIG_SMP
mov r16=cr.ifa // get the address that caused the fault
movl r30=1f // load continuation point in case of nested fault
;;
@@ -465,6 +540,36 @@ page_fault:
;;
st8 [r17]=r18 // store back updated PTE
itc.d r18 // install updated PTE
+#else
+ mov r16=cr.ifa // get the address that caused the fault
+ movl r30=1f // load continuation point in case of nested fault
+ ;;
+ thash r17=r16 // compute virtual address of L3 PTE
+ mov r28=ar.ccv // save ar.ccv
+ mov r29=b0 // save b0 in case of nested fault
+ mov r27=pr
+ ;;
+1: ld8 r18=[r17]
+ ;; // avoid RAW on r18
+ mov ar.ccv=r18 // set compare value for cmpxchg
+ or r25=_PAGE_D,r18 // set the dirty bit
+ ;;
+ cmpxchg8.acq r26=[r17],r25,ar.ccv
+ mov r24=PAGE_SHIFT<<2
+ ;;
+ cmp.eq p6,p7=r26,r18
+ ;;
+(p6) itc.d r25 // install updated PTE
+ ;;
+ ld8 r18=[r17] // read PTE again
+ ;;
+ cmp.eq p6,p7=r18,r25 // is it same as the newly installed
+ ;;
+(p7) ptc.l r16,r24
+ mov b0=r29 // restore b0
+ mov ar.ccv=r28
+ mov pr=r27,-1
+#endif
rfi
.align 1024
@@ -486,6 +591,8 @@ page_fault:
(p6) mov r16=r18 // if so, use cr.iip instead of cr.ifa
mov pr=r31,-1
#endif /* CONFIG_ITANIUM */
+
+#ifndef CONFIG_SMP
movl r30=1f // load continuation point in case of nested fault
;;
thash r17=r16 // compute virtual address of L3 PTE
@@ -515,12 +622,58 @@ page_fault:
;;
st8 [r17]=r18 // store back updated PTE
itc.i r18 // install updated PTE
+#else
+ movl r30=1f // load continuation point in case of nested fault
+ ;;
+ thash r17=r16 // compute virtual address of L3 PTE
+ mov r28=ar.ccv // save ar.ccv
+ mov r29=b0 // save b0 in case of nested fault)
+ mov r27=pr
+ ;;
+1: ld8 r18=[r17]
+#if defined(CONFIG_IA32_SUPPORT) && \
+ (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC))
+ //
+ // Erratum 85 (Access bit fault could be reported before page not present fault)
+ // If the PTE is indicates the page is not present, then just turn this into a
+ // page fault.
+ //
+ ;;
+ tbit.nz p6,p0=r18,0 // page present bit set?
+(p6) br.cond.sptk 1f
+ ;; // avoid WAW on p6
+ mov pr=r27,-1
+ br.cond.sptk page_fault // page wasn't present
+1:
+#else
+ ;; // avoid RAW on r18
+#endif
+ mov ar.ccv=r18 // set compare value for cmpxchg
+ or r25=_PAGE_A,r18 // set the accessed bit
+ ;;
+ cmpxchg8.acq r26=[r17],r25,ar.ccv
+ mov r24=PAGE_SHIFT<<2
+ ;;
+ cmp.eq p6,p7=r26,r18
+ ;;
+(p6) itc.i r25 // install updated PTE
+ ;;
+ ld8 r18=[r17] // read PTE again
+ ;;
+ cmp.eq p6,p7=r18,r25 // is it same as the newly installed
+ ;;
+(p7) ptc.l r16,r24
+ mov b0=r29 // restore b0
+ mov ar.ccv=r28
+ mov pr=r27,-1
+#endif
rfi
.align 1024
/////////////////////////////////////////////////////////////////////////////////////////
// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55)
// Like Entry 8, except for data access
+#ifndef CONFIG_SMP
mov r16=cr.ifa // get the address that caused the fault
movl r30=1f // load continuation point in case of nested fault
;;
@@ -534,6 +687,36 @@ page_fault:
;;
st8 [r17]=r18 // store back updated PTE
itc.d r18 // install updated PTE
+#else
+ mov r16=cr.ifa // get the address that caused the fault
+ movl r30=1f // load continuation point in case of nested fault
+ ;;
+ thash r17=r16 // compute virtual address of L3 PTE
+ mov r28=ar.ccv // save ar.ccv
+ mov r29=b0 // save b0 in case of nested fault
+ mov r27=pr
+ ;;
+1: ld8 r18=[r17]
+ ;; // avoid RAW on r18
+ mov ar.ccv=r18 // set compare value for cmpxchg
+ or r25=_PAGE_A,r18 // set the dirty bit
+ ;;
+ cmpxchg8.acq r26=[r17],r25,ar.ccv
+ mov r24=PAGE_SHIFT<<2
+ ;;
+ cmp.eq p6,p7=r26,r18
+ ;;
+(p6) itc.d r25 // install updated PTE
+ ;;
+ ld8 r18=[r17] // read PTE again
+ ;;
+ cmp.eq p6,p7=r18,r25 // is it same as the newly installed
+ ;;
+(p7) ptc.l r16,r24
+ mov b0=r29 // restore b0
+ mov ar.ccv=r28
+ mov pr=r27,-1
+#endif
rfi
.align 1024
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index b57d4702d..333258d35 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -43,10 +43,6 @@ u64 ia64_mca_stackframe[32];
u64 ia64_mca_bspstore[1024];
u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));
-#if defined(SAL_MPINIT_WORKAROUND) && !defined(CONFIG_SMP)
-int bootstrap_processor = -1;
-#endif
-
static void ia64_mca_cmc_vector_setup(int enable,
int_vector_t cmc_vector);
static void ia64_mca_wakeup_ipi_wait(void);
@@ -223,12 +219,6 @@ ia64_mca_init(void)
IA64_MCA_DEBUG("ia64_mca_init : begin\n");
-#if defined(SAL_MPINIT_WORKAROUND) && !defined(CONFIG_SMP)
- /* XXX -- workaround for SAL bug for running on MP system, but UP kernel */
-
- bootstrap_processor = hard_smp_processor_id();
-#endif
-
/* Clear the Rendez checkin flag for all cpus */
for(i = 0 ; i < IA64_MAXCPUS; i++)
ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
@@ -265,8 +255,11 @@ ia64_mca_init(void)
IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n");
ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch);
- ia64_mc_info.imi_mca_handler_size =
- __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch);
+ /*
+ * XXX - disable SAL checksum by setting size to 0; should be
+ * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch);
+ */
+ ia64_mc_info.imi_mca_handler_size = 0;
/* Register the os mca handler with SAL */
if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
ia64_mc_info.imi_mca_handler,
@@ -278,10 +271,14 @@ ia64_mca_init(void)
IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n");
+ /*
+ * XXX - disable SAL checksum by setting size to 0, should be
+ * IA64_INIT_HANDLER_SIZE
+ */
ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp);
- ia64_mc_info.imi_monarch_init_handler_size = IA64_INIT_HANDLER_SIZE;
+ ia64_mc_info.imi_monarch_init_handler_size = 0;
ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp);
- ia64_mc_info.imi_slave_init_handler_size = IA64_INIT_HANDLER_SIZE;
+ ia64_mc_info.imi_slave_init_handler_size = 0;
IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler);
@@ -386,7 +383,7 @@ ia64_mca_wakeup_all(void)
int cpu;
/* Clear the Rendez checkin flag for all cpus */
- for(cpu = 0 ; cpu < IA64_MAXCPUS; cpu++)
+ for(cpu = 0 ; cpu < smp_num_cpus; cpu++)
if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE)
ia64_mca_wakeup(cpu);
@@ -404,11 +401,14 @@ ia64_mca_wakeup_all(void)
void
ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
{
- int flags;
+ int flags, cpu = 0;
/* Mask all interrupts */
save_and_cli(flags);
- ia64_mc_info.imi_rendez_checkin[ia64_get_cpuid(0)] = IA64_MCA_RENDEZ_CHECKIN_DONE;
+#ifdef CONFIG_SMP
+ cpu = cpu_logical_id(hard_smp_processor_id());
+#endif
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE;
/* Register with the SAL monarch that the slave has
* reached SAL
*/
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index 6b714108e..15993525d 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -6,6 +6,8 @@
// 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp kstack,
// switch modes, jump to C INIT handler
//
+#include <linux/config.h>
+
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/mca_asm.h>
@@ -680,32 +682,22 @@ end_os_mca_restore:
.proc ia64_monarch_init_handler
ia64_monarch_init_handler:
-#if defined(SAL_MPINIT_WORKAROUND)
+#if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND)
//
// work around SAL bug that sends all processors to monarch entry
//
- .global bootstrap_processor
-
- movl r21=24
- movl r20=16
mov r17=cr.lid
- movl r18=bootstrap_processor
+ movl r18=__cpu_physical_id
;;
- dep r18=0,r18,61,3 // convert bsp to physical address
+ dep r18=0,r18,61,3 // convert to physical address
;;
- shr r19=r17,r20
- shr r22=r17,r21
+ shr.u r17=r17,16
ld4 r18=[r18] // get the BSP ID
;;
- and r19=0xf, r19
- and r22=0xf, r22
- ;;
- shl r19=r19,8 // get them in the right order
- ;;
- or r22=r22,r19 // combine EID and LID
+ dep r17=0,r17,16,48
;;
- cmp.eq p6,p7=r22,r18 // Am I the BSP ?
-(p7) br.cond.spnt slave_init_spin_me
+ cmp4.ne p6,p0=r17,r18 // Am I the BSP ?
+(p6) br.cond.spnt slave_init_spin_me
;;
#endif
diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h
index 24be2f53d..8790d49c3 100644
--- a/arch/ia64/kernel/minstate.h
+++ b/arch/ia64/kernel/minstate.h
@@ -192,13 +192,3 @@
#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS
#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS
#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS
-
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
-# define STOPS nop.i 0x0;; nop.i 0x0;; nop.i 0x0;;
-#else
-# define STOPS
-#endif
-
-#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS
-#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS
-#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS
diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S
index 0b07163dc..2e56a428e 100644
--- a/arch/ia64/kernel/pal.S
+++ b/arch/ia64/kernel/pal.S
@@ -54,7 +54,8 @@ END(ia64_pal_default_handler)
*
* in0 Pointer to struct ia64_pal_retval
* in1 Index of PAL service
- * in2 - in4 Remaning PAL arguments
+ * in2 - in4 Remaining PAL arguments
+ * in5 1 ==> clear psr.ic, 0 ==> don't clear psr.ic
*
*/
GLOBAL_ENTRY(ia64_pal_call_static)
@@ -68,18 +69,22 @@ GLOBAL_ENTRY(ia64_pal_call_static)
}
;;
ld8 loc2 = [loc2] // loc2 <- entry point
- mov r30 = in2
- mov r31 = in3
+ tbit.nz p6,p7 = in5, 0
+ adds r8 = 1f-1b,r8
;;
mov loc3 = psr
mov loc0 = rp
UNW(.body)
- adds r8 = 1f-1b,r8
- ;;
- rsm psr.i
+ mov r30 = in2
+
+(p6) rsm psr.i | psr.ic
+ mov r31 = in3
mov b7 = loc2
+
+(p7) rsm psr.i
+ ;;
+(p6) srlz.i
mov rp = r8
- ;;
br.cond.sptk.few b7
1: mov psr.l = loc3
mov ar.pfs = loc1
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index ecd7b0886..de71a2d22 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -10,11 +10,11 @@
* Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
*
* 05/26/2000 S.Eranian initial release
+ * 08/21/2000 S.Eranian updated to July 2000 PAL specs
*
* ISSUES:
- * - because of some PAL bugs, some calls return invalid results or
- * are empty for now.
- * - remove hack to avoid problem with <= 256M RAM for itr.
+ * - as of 2.2.9/2.2.12, the following values are still wrong
+ * PAL_VM_SUMMARY: key & rid sizes
*/
#include <linux/config.h>
#include <linux/types.h>
@@ -111,7 +111,7 @@ static const char *rse_hints[]={
#define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *))
/*
- * The current revision of the Volume 2 of
+ * The current revision of the Volume 2 (July 2000) of
* IA-64 Architecture Software Developer's Manual is wrong.
* Table 4-10 has invalid information concerning the ma field:
* Correct table is:
@@ -132,38 +132,6 @@ static const char *mem_attrib[]={
"NaTPage" /* 111 */
};
-
-
-/*
- * Allocate a buffer suitable for calling PAL code in Virtual mode
- *
- * The documentation (PAL2.6) allows DTLB misses on the buffer. So
- * using the TC is enough, no need to pin the entry.
- *
- * We allocate a kernel-sized page (at least 4KB). This is enough to
- * hold any possible reply.
- */
-static inline void *
-get_palcall_buffer(void)
-{
- void *tmp;
-
- tmp = (void *)__get_free_page(GFP_KERNEL);
- if (tmp == 0) {
- printk(KERN_ERR __FUNCTION__" : can't get a buffer page\n");
- }
- return tmp;
-}
-
-/*
- * Free a palcall buffer allocated with the previous call
- */
-static inline void
-free_palcall_buffer(void *addr)
-{
- __free_page(addr);
-}
-
/*
* Take a 64bit vector and produces a string such that
* if bit n is set then 2^n in clear text is generated. The adjustment
@@ -243,17 +211,12 @@ power_info(char *page)
{
s64 status;
char *p = page;
- pal_power_mgmt_info_u_t *halt_info;
+ u64 halt_info_buffer[8];
+ pal_power_mgmt_info_u_t *halt_info =(pal_power_mgmt_info_u_t *)halt_info_buffer;
int i;
- halt_info = get_palcall_buffer();
- if (halt_info == 0) return 0;
-
status = ia64_pal_halt_info(halt_info);
- if (status != 0) {
- free_palcall_buffer(halt_info);
- return 0;
- }
+ if (status != 0) return 0;
for (i=0; i < 8 ; i++ ) {
if (halt_info[i].pal_power_mgmt_info_s.im == 1) {
@@ -270,9 +233,6 @@ power_info(char *page)
p += sprintf(p,"Power level %d: not implemented\n",i);
}
}
-
- free_palcall_buffer(halt_info);
-
return p - page;
}
@@ -502,7 +462,7 @@ register_info(char *page)
"RSE load/store hints : %ld (%s)\n",
phys_stacked,
hints.ph_data,
- hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)");
+ hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)");
if (ia64_pal_debug_info(&iregs, &dregs)) return 0;
@@ -569,7 +529,9 @@ static const char *bus_features[]={
"Enable Half Transfer",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ "Enable Cache Line Repl. Exclusive",
+ "Enable Cache Line Repl. Shared",
"Disable Transaction Queuing",
"Disable Reponse Error Checking",
"Disable Bus Error Checking",
@@ -673,16 +635,10 @@ static int
perfmon_info(char *page)
{
char *p = page;
- u64 *pm_buffer;
+ u64 pm_buffer[16];
pal_perf_mon_info_u_t pm_info;
- pm_buffer = (u64 *)get_palcall_buffer();
- if (pm_buffer == 0) return 0;
-
- if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) {
- free_palcall_buffer(pm_buffer);
- return 0;
- }
+ if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;
#ifdef IA64_PAL_PERF_MON_INFO_BUG
/*
@@ -719,8 +675,6 @@ perfmon_info(char *page)
p += sprintf(p, "\n");
- free_palcall_buffer(pm_buffer);
-
return p - page;
}
diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c
index 80509c6a1..6293cdfa0 100644
--- a/arch/ia64/kernel/pci-dma.c
+++ b/arch/ia64/kernel/pci-dma.c
@@ -97,7 +97,8 @@ setup_swiotlb (void)
io_tlb_index = 0;
io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
- printk("Placing software IO TLB between 0x%p - 0x%p\n", io_tlb_start, io_tlb_end);
+ printk("Placing software IO TLB between 0x%p - 0x%p\n",
+ (void *) io_tlb_start, (void *) io_tlb_end);
}
/*
@@ -394,7 +395,7 @@ pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int
* Once the device is given the dma address, the device owns this memory
* until either pci_unmap_single or pci_dma_sync_single is performed.
*/
-extern inline dma_addr_t
+dma_addr_t
pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction)
{
if (direction == PCI_DMA_NONE)
@@ -410,7 +411,7 @@ pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction)
* After this call, reads by the cpu to the buffer are guarenteed to see
* whatever the device wrote there.
*/
-extern inline void
+void
pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
{
if (direction == PCI_DMA_NONE)
@@ -433,7 +434,7 @@ pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int d
* Device ownership issues as mentioned above for pci_map_single are
* the same here.
*/
-extern inline int
+int
pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
{
if (direction == PCI_DMA_NONE)
@@ -446,7 +447,7 @@ pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direct
* Again, cpu read rules concerning calls here are the same as for
* pci_unmap_single() above.
*/
-extern inline void
+void
pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
{
if (direction == PCI_DMA_NONE)
@@ -463,7 +464,7 @@ pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int dire
* next point you give the PCI dma address back to the card, the
* device again owns the buffer.
*/
-extern inline void
+void
pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
{
if (direction == PCI_DMA_NONE)
@@ -478,7 +479,7 @@ pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size,
* The same as pci_dma_sync_single but for a scatter-gather list,
* same rules and usage.
*/
-extern inline void
+void
pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
{
if (direction == PCI_DMA_NONE)
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 752b2a9a1..e5efbc8b5 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -10,15 +10,19 @@
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/init.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
#include <asm/errno.h>
#include <asm/hw_irq.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+#include <asm/pal.h>
/* Long blurb on how this works:
* We set dcr.pp, psr.pp, and the appropriate pmc control values with
@@ -52,68 +56,107 @@
#ifdef CONFIG_PERFMON
#define MAX_PERF_COUNTER 4 /* true for Itanium, at least */
+#define PMU_FIRST_COUNTER 4 /* first generic counter */
+
#define WRITE_PMCS_AND_START 0xa0
#define WRITE_PMCS 0xa1
#define READ_PMDS 0xa2
#define STOP_PMCS 0xa3
-#define IA64_COUNTER_MASK 0xffffffffffffff6fL
-#define PERF_OVFL_VAL 0xffffffffL
-volatile int used_by_system;
-struct perfmon_counter {
- unsigned long data;
- unsigned long counter_num;
-};
+/*
+ * this structure needs to be enhanced
+ */
+typedef struct {
+ unsigned long pmu_reg_data; /* generic PMD register */
+ unsigned long pmu_reg_num; /* which register number */
+} perfmon_reg_t;
+
+/*
+ * This structure is initialize at boot time and contains
+ * a description of the PMU main characteristic as indicated
+ * by PAL
+ */
+typedef struct {
+ unsigned long perf_ovfl_val; /* overflow value for generic counters */
+ unsigned long max_pmc; /* highest PMC */
+ unsigned long max_pmd; /* highest PMD */
+ unsigned long max_counters; /* number of generic counter pairs (PMC/PMD) */
+} pmu_config_t;
+
+/* XXX will go static when ptrace() is cleaned */
+unsigned long perf_ovfl_val; /* overflow value for generic counters */
+
+static pmu_config_t pmu_conf;
+/*
+ * could optimize to avoid cache conflicts in SMP
+ */
unsigned long pmds[NR_CPUS][MAX_PERF_COUNTER];
asmlinkage unsigned long
-sys_perfmonctl (int cmd1, int cmd2, void *ptr)
+sys_perfmonctl (int cmd, int count, void *ptr, long arg4, long arg5, long arg6, long arg7, long arg8, long stack)
{
- struct perfmon_counter tmp, *cptr = ptr;
- unsigned long cnum, dcr, flags;
- struct perf_counter;
+ struct pt_regs *regs = (struct pt_regs *) &stack;
+ perfmon_reg_t tmp, *cptr = ptr;
+ unsigned long cnum;
int i;
- switch (cmd1) {
+ switch (cmd) {
case WRITE_PMCS: /* Writes to PMC's and clears PMDs */
case WRITE_PMCS_AND_START: /* Also starts counting */
- if (cmd2 <= 0 || cmd2 > MAX_PERF_COUNTER - used_by_system)
- return -EINVAL;
-
- if (!access_ok(VERIFY_READ, cptr, sizeof(struct perf_counter)*cmd2))
+ if (!access_ok(VERIFY_READ, cptr, sizeof(struct perfmon_reg_t)*count))
return -EFAULT;
- current->thread.flags |= IA64_THREAD_PM_VALID;
+ for (i = 0; i < count; i++, cptr++) {
- for (i = 0; i < cmd2; i++, cptr++) {
copy_from_user(&tmp, cptr, sizeof(tmp));
- /* XXX need to check validity of counter_num and perhaps data!! */
- if (tmp.counter_num < 4
- || tmp.counter_num >= 4 + MAX_PERF_COUNTER - used_by_system)
- return -EFAULT;
-
- ia64_set_pmc(tmp.counter_num, tmp.data);
- ia64_set_pmd(tmp.counter_num, 0);
- pmds[smp_processor_id()][tmp.counter_num - 4] = 0;
+
+ /* XXX need to check validity of pmu_reg_num and perhaps data!! */
+
+ if (tmp.pmu_reg_num > pmu_conf.max_pmc || tmp.pmu_reg_num == 0) return -EFAULT;
+
+ ia64_set_pmc(tmp.pmu_reg_num, tmp.pmu_reg_data);
+
+ /* to go away */
+ if (tmp.pmu_reg_num >= PMU_FIRST_COUNTER && tmp.pmu_reg_num < PMU_FIRST_COUNTER+pmu_conf.max_counters) {
+ ia64_set_pmd(tmp.pmu_reg_num, 0);
+ pmds[smp_processor_id()][tmp.pmu_reg_num - PMU_FIRST_COUNTER] = 0;
+
+ printk(__FUNCTION__" setting PMC/PMD[%ld] es=0x%lx pmd[%ld]=%lx\n", tmp.pmu_reg_num, (tmp.pmu_reg_data>>8) & 0x7f, tmp.pmu_reg_num, ia64_get_pmd(tmp.pmu_reg_num));
+ } else
+ printk(__FUNCTION__" setting PMC[%ld]=0x%lx\n", tmp.pmu_reg_num, tmp.pmu_reg_data);
}
- if (cmd1 == WRITE_PMCS_AND_START) {
+ if (cmd == WRITE_PMCS_AND_START) {
+#if 0
+/* irrelevant with user monitors */
local_irq_save(flags);
+
dcr = ia64_get_dcr();
dcr |= IA64_DCR_PP;
ia64_set_dcr(dcr);
+
local_irq_restore(flags);
+#endif
+
ia64_set_pmc(0, 0);
+
+ /* will start monitoring right after rfi */
+ ia64_psr(regs)->up = 1;
}
+ /*
+ * mark the state as valid.
+ * this will trigger save/restore at context switch
+ */
+ current->thread.flags |= IA64_THREAD_PM_VALID;
break;
case READ_PMDS:
- if (cmd2 <= 0 || cmd2 > MAX_PERF_COUNTER - used_by_system)
+ if (count <= 0 || count > MAX_PERF_COUNTER)
return -EINVAL;
- if (!access_ok(VERIFY_WRITE, cptr, sizeof(struct perf_counter)*cmd2))
+ if (!access_ok(VERIFY_WRITE, cptr, sizeof(struct perfmon_reg_t)*count))
return -EFAULT;
/* This looks shady, but IMHO this will work fine. This is
@@ -121,14 +164,15 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr)
* with the interrupt handler. See explanation in the
* following comment.
*/
-
+#if 0
+/* irrelevant with user monitors */
local_irq_save(flags);
__asm__ __volatile__("rsm psr.pp\n");
dcr = ia64_get_dcr();
dcr &= ~IA64_DCR_PP;
ia64_set_dcr(dcr);
local_irq_restore(flags);
-
+#endif
/*
* We cannot write to pmc[0] to stop counting here, as
* that particular instruction might cause an overflow
@@ -142,36 +186,47 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr)
* when we re-enabled interrupts. When I muck with dcr,
* is the irq_save/restore needed?
*/
- for (i = 0, cnum = 4;i < cmd2; i++, cnum++, cptr++) {
- tmp.data = (pmds[smp_processor_id()][i]
- + (ia64_get_pmd(cnum) & PERF_OVFL_VAL));
- tmp.counter_num = cnum;
- if (copy_to_user(cptr, &tmp, sizeof(tmp)))
- return -EFAULT;
- //put_user(pmd, &cptr->data);
+
+
+ /* XXX: This needs to change to read more than just the counters */
+ for (i = 0, cnum = PMU_FIRST_COUNTER;i < count; i++, cnum++, cptr++) {
+
+ tmp.pmu_reg_data = (pmds[smp_processor_id()][i]
+ + (ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val));
+
+ tmp.pmu_reg_num = cnum;
+
+ if (copy_to_user(cptr, &tmp, sizeof(tmp))) return -EFAULT;
}
+#if 0
+/* irrelevant with user monitors */
local_irq_save(flags);
__asm__ __volatile__("ssm psr.pp");
dcr = ia64_get_dcr();
dcr |= IA64_DCR_PP;
ia64_set_dcr(dcr);
local_irq_restore(flags);
+#endif
break;
case STOP_PMCS:
ia64_set_pmc(0, 1);
ia64_srlz_d();
- for (i = 0; i < MAX_PERF_COUNTER - used_by_system; ++i)
+ for (i = 0; i < MAX_PERF_COUNTER; ++i)
ia64_set_pmc(4+i, 0);
- if (!used_by_system) {
- local_irq_save(flags);
- dcr = ia64_get_dcr();
- dcr &= ~IA64_DCR_PP;
- ia64_set_dcr(dcr);
- local_irq_restore(flags);
- }
+#if 0
+/* irrelevant with user monitors */
+ local_irq_save(flags);
+ dcr = ia64_get_dcr();
+ dcr &= ~IA64_DCR_PP;
+ ia64_set_dcr(dcr);
+ local_irq_restore(flags);
+ ia64_psr(regs)->up = 0;
+#endif
+
current->thread.flags &= ~(IA64_THREAD_PM_VALID);
+
break;
default:
@@ -187,13 +242,21 @@ update_counters (void)
unsigned long mask, i, cnum, val;
mask = ia64_get_pmc(0) >> 4;
- for (i = 0, cnum = 4; i < MAX_PERF_COUNTER - used_by_system; cnum++, i++, mask >>= 1) {
- val = 0;
+ for (i = 0, cnum = PMU_FIRST_COUNTER ; i < pmu_conf.max_counters; cnum++, i++, mask >>= 1) {
+
+
+ val = mask & 0x1 ? pmu_conf.perf_ovfl_val + 1 : 0;
+
if (mask & 0x1)
- val += PERF_OVFL_VAL + 1;
+ printk(__FUNCTION__ " PMD%ld overflowed pmd=%lx pmod=%lx\n", cnum, ia64_get_pmd(cnum), pmds[smp_processor_id()][i]);
+
/* since we got an interrupt, might as well clear every pmd. */
- val += ia64_get_pmd(cnum) & PERF_OVFL_VAL;
+ val += ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val;
+
+ printk(__FUNCTION__ " adding val=%lx to pmod[%ld]=%lx \n", val, i, pmds[smp_processor_id()][i]);
+
pmds[smp_processor_id()][i] += val;
+
ia64_set_pmd(cnum, 0);
}
}
@@ -212,16 +275,69 @@ static struct irqaction perfmon_irqaction = {
name: "perfmon"
};
-void
+static int
+perfmon_proc_info(char *page)
+{
+ char *p = page;
+ u64 pmc0 = ia64_get_pmc(0);
+
+ p += sprintf(p, "PMC[0]=%lx\n", pmc0);
+
+ return p - page;
+}
+
+static int
+perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = perfmon_proc_info(page);
+
+ if (len <= off+count) *eof = 1;
+
+ *start = page + off;
+ len -= off;
+
+ if (len>count) len = count;
+ if (len<0) len = 0;
+
+ return len;
+}
+
+static struct proc_dir_entry *perfmon_dir;
+
+void __init
perfmon_init (void)
{
+ pal_perf_mon_info_u_t pm_info;
+ u64 pm_buffer[16];
+ s64 status;
+
irq_desc[PERFMON_IRQ].status |= IRQ_PER_CPU;
irq_desc[PERFMON_IRQ].handler = &irq_type_ia64_sapic;
setup_irq(PERFMON_IRQ, &perfmon_irqaction);
ia64_set_pmv(PERFMON_IRQ);
ia64_srlz_d();
- printk("Initialized perfmon vector to %u\n",PERFMON_IRQ);
+
+ printk("perfmon: Initialized vector to %u\n",PERFMON_IRQ);
+
+ if ((status=ia64_pal_perf_mon_info(pm_buffer, &pm_info)) != 0) {
+ printk(__FUNCTION__ " pal call failed (%ld)\n", status);
+ return;
+ }
+ pmu_conf.perf_ovfl_val = perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1;
+
+ /* XXX need to use PAL instead */
+ pmu_conf.max_pmc = 13;
+ pmu_conf.max_pmd = 17;
+ pmu_conf.max_counters = pm_info.pal_perf_mon_info_s.generic;
+
+ printk("perfmon: Counters are %d bits\n", pm_info.pal_perf_mon_info_s.width);
+ printk("perfmon: Maximum counter value 0x%lx\n", pmu_conf.perf_ovfl_val);
+
+ /*
+ * for now here for debug purposes
+ */
+ perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
}
void
@@ -238,10 +354,13 @@ ia64_save_pm_regs (struct thread_struct *t)
ia64_set_pmc(0, 1);
ia64_srlz_d();
- for (i=0; i< IA64_NUM_PM_REGS - used_by_system ; i++) {
- t->pmd[i] = ia64_get_pmd(4+i);
+ /*
+ * XXX: this will need to be extended beyong just counters
+ */
+ for (i=0; i< IA64_NUM_PM_REGS; i++) {
+ t->pmd[i] = ia64_get_pmd(4+i);
t->pmod[i] = pmds[smp_processor_id()][i];
- t->pmc[i] = ia64_get_pmc(4+i);
+ t->pmc[i] = ia64_get_pmc(4+i);
}
}
@@ -250,7 +369,10 @@ ia64_load_pm_regs (struct thread_struct *t)
{
int i;
- for (i=0; i< IA64_NUM_PM_REGS - used_by_system ; i++) {
+ /*
+ * XXX: this will need to be extended beyong just counters
+ */
+ for (i=0; i< IA64_NUM_PM_REGS ; i++) {
ia64_set_pmd(4+i, t->pmd[i]);
pmds[smp_processor_id()][i] = t->pmod[i];
ia64_set_pmc(4+i, t->pmc[i]);
@@ -262,7 +384,7 @@ ia64_load_pm_regs (struct thread_struct *t)
#else /* !CONFIG_PERFMON */
asmlinkage unsigned long
-sys_perfmonctl (int cmd1, int cmd2, void *ptr)
+sys_perfmonctl (int cmd, int count, void *ptr)
{
return -ENOSYS;
}
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index e586a4074..41db60a0c 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -294,7 +294,8 @@ copy_thread (int nr, unsigned long clone_flags,
* call behavior where scratch registers are preserved across
* system calls (unless used by the system call itself).
*/
-# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID)
+# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID \
+ | IA64_THREAD_PM_VALID)
# define THREAD_FLAGS_TO_SET 0
p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
| THREAD_FLAGS_TO_SET);
@@ -333,6 +334,17 @@ do_copy_regs (struct unw_frame_info *info, void *arg)
if (ia64_peek(pt, current, addr, &val) == 0)
access_process_vm(current, addr, &val, sizeof(val), 1);
+ /*
+ * coredump format:
+ * r0-r31
+ * NaT bits (for r0-r31; bit N == 1 iff rN is a NaT)
+ * predicate registers (p0-p63)
+ * b0-b7
+ * ip cfm user-mask
+ * ar.rsc ar.bsp ar.bspstore ar.rnat
+ * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec
+ */
+
/* r0 is zero */
for (i = 1, mask = (1UL << i); i < 32; ++i) {
unw_get_gr(info, i, &dst[i], &nat);
@@ -370,7 +382,6 @@ do_copy_regs (struct unw_frame_info *info, void *arg)
void
do_dump_fpu (struct unw_frame_info *info, void *arg)
{
- struct task_struct *fpu_owner = ia64_get_fpu_owner();
elf_fpreg_t *dst = arg;
int i;
@@ -384,10 +395,9 @@ do_dump_fpu (struct unw_frame_info *info, void *arg)
for (i = 2; i < 32; ++i)
unw_get_fr(info, i, dst + i);
- if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) {
- ia64_sync_fph(current);
+ ia64_flush_fph(current);
+ if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0)
memcpy(dst + 32, current->thread.fph, 96*16);
- }
}
#endif /* CONFIG_IA64_NEW_UNWIND */
@@ -463,7 +473,6 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
unw_init_running(do_dump_fpu, dst);
#else
struct switch_stack *sw = ((struct switch_stack *) pt) - 1;
- struct task_struct *fpu_owner = ia64_get_fpu_owner();
memset(dst, 0, sizeof (dst)); /* don't leak any "random" bits */
@@ -472,12 +481,9 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
dst[8] = pt->f8; dst[9] = pt->f9;
memcpy(dst + 10, &sw->f10, 22*16); /* f10-f31 are contiguous */
- if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) {
- if (fpu_owner == current) {
- __ia64_save_fpu(current->thread.fph);
- }
+ ia64_flush_fph(current);
+ if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0)
memcpy(dst + 32, current->thread.fph, 96*16);
- }
#endif
return 1; /* f0-f31 are always valid so we always return 1 */
}
@@ -501,14 +507,14 @@ pid_t
kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
{
struct task_struct *parent = current;
- int result;
+ int result, tid;
- clone(flags | CLONE_VM, 0);
+ tid = clone(flags | CLONE_VM, 0);
if (parent != current) {
result = (*fn)(arg);
_exit(result);
}
- return 0; /* parent: just return */
+ return tid;
}
/*
@@ -520,9 +526,10 @@ flush_thread (void)
/* drop floating-point and debug-register state if it exists: */
current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID);
- if (ia64_get_fpu_owner() == current) {
+#ifndef CONFIG_SMP
+ if (ia64_get_fpu_owner() == current)
ia64_set_fpu_owner(0);
- }
+#endif
}
/*
@@ -532,9 +539,28 @@ flush_thread (void)
void
exit_thread (void)
{
- if (ia64_get_fpu_owner() == current) {
+#ifndef CONFIG_SMP
+ if (ia64_get_fpu_owner() == current)
ia64_set_fpu_owner(0);
+#endif
+#ifdef CONFIG_PERFMON
+ /* stop monitoring */
+ if ((current->thread.flags & IA64_THREAD_PM_VALID) != 0) {
+ /*
+ * we cannot rely on switch_to() to save the PMU
+ * context for the last time. There is a possible race
+ * condition in SMP mode between the child and the
+ * parent. by explicitly saving the PMU context here
+ * we garantee no race. this call we also stop
+ * monitoring
+ */
+ ia64_save_pm_regs(&current->thread);
+ /*
+ * make sure that switch_to() will not save context again
+ */
+ current->thread.flags &= ~IA64_THREAD_PM_VALID;
}
+#endif
}
unsigned long
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 10868ce41..820a87854 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -376,7 +376,8 @@ ia64_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr,
ret = 0;
} else {
if ((unsigned long) laddr >= (unsigned long) high_memory) {
- printk("yikes: trying to access long at %p\n", laddr);
+ printk("yikes: trying to access long at %p\n",
+ (void *) laddr);
return -EIO;
}
ret = *laddr;
@@ -543,21 +544,48 @@ sync_thread_rbs (struct task_struct *child, struct mm_struct *mm, int make_writa
}
/*
- * Ensure the state in child->thread.fph is up-to-date.
+ * Write f32-f127 back to task->thread.fph if it has been modified.
*/
-void
-ia64_sync_fph (struct task_struct *child)
+inline void
+ia64_flush_fph (struct task_struct *task)
{
- if (ia64_psr(ia64_task_regs(child))->mfh && ia64_get_fpu_owner() == child) {
- ia64_psr(ia64_task_regs(child))->mfh = 0;
- ia64_set_fpu_owner(0);
- ia64_save_fpu(&child->thread.fph[0]);
- child->thread.flags |= IA64_THREAD_FPH_VALID;
+ struct ia64_psr *psr = ia64_psr(ia64_task_regs(task));
+#ifdef CONFIG_SMP
+ struct task_struct *fpu_owner = current;
+#else
+ struct task_struct *fpu_owner = ia64_get_fpu_owner();
+#endif
+
+ if (task == fpu_owner && psr->mfh) {
+ psr->mfh = 0;
+ ia64_save_fpu(&task->thread.fph[0]);
+ task->thread.flags |= IA64_THREAD_FPH_VALID;
}
- if (!(child->thread.flags & IA64_THREAD_FPH_VALID)) {
- memset(&child->thread.fph, 0, sizeof(child->thread.fph));
- child->thread.flags |= IA64_THREAD_FPH_VALID;
+}
+
+/*
+ * Sync the fph state of the task so that it can be manipulated
+ * through thread.fph. If necessary, f32-f127 are written back to
+ * thread.fph or, if the fph state hasn't been used before, thread.fph
+ * is cleared to zeroes. Also, access to f32-f127 is disabled to
+ * ensure that the task picks up the state from thread.fph when it
+ * executes again.
+ */
+void
+ia64_sync_fph (struct task_struct *task)
+{
+ struct ia64_psr *psr = ia64_psr(ia64_task_regs(task));
+
+ ia64_flush_fph(task);
+ if (!(task->thread.flags & IA64_THREAD_FPH_VALID)) {
+ task->thread.flags |= IA64_THREAD_FPH_VALID;
+ memset(&task->thread.fph, 0, sizeof(task->thread.fph));
}
+#ifndef CONFIG_SMP
+ if (ia64_get_fpu_owner() == task)
+ ia64_set_fpu_owner(0);
+#endif
+ psr->dfh = 1;
}
#ifdef CONFIG_IA64_NEW_UNWIND
@@ -589,6 +617,7 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
struct switch_stack *sw;
struct unw_frame_info info;
struct pt_regs *pt;
+ unsigned long pmd_tmp;
pt = ia64_task_regs(child);
sw = (struct switch_stack *) (child->thread.ksp + 16);
@@ -600,7 +629,10 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
if (addr < PT_F127 + 16) {
/* accessing fph */
- ia64_sync_fph(child);
+ if (write_access)
+ ia64_sync_fph(child);
+ else
+ ia64_flush_fph(child);
ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr);
} else if (addr >= PT_F10 && addr < PT_F15 + 16) {
/* scratch registers untouched by kernel (saved in switch_stack) */
@@ -656,6 +688,9 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
case PT_B1: case PT_B2: case PT_B3: case PT_B4: case PT_B5:
return unw_access_br(&info, (addr - PT_B1)/8 + 1, data, write_access);
+ case PT_AR_EC:
+ return unw_access_ar(&info, UNW_AR_EC, data, write_access);
+
case PT_AR_LC:
return unw_access_ar(&info, UNW_AR_LC, data, write_access);
@@ -759,7 +794,11 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
addr);
return -1;
}
- } else {
+ } else
+#ifdef CONFIG_PERFMON
+ if (addr < PT_PMD)
+#endif
+ {
/* access debug registers */
if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
@@ -782,6 +821,32 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
ptr += regnum;
}
+#ifdef CONFIG_PERFMON
+ else {
+ /*
+ * XXX: will eventually move back to perfmonctl()
+ */
+ unsigned long pmd = (addr - PT_PMD) >> 3;
+ extern unsigned long perf_ovfl_val;
+
+ /* we just use ptrace to read */
+ if (write_access) return -1;
+
+ if (pmd > 3) {
+ printk("ptrace: rejecting access to PMD[%ld] address 0x%lx\n", pmd, addr);
+ return -1;
+ }
+
+ /*
+ * We always need to mask upper 32bits of pmd because value is random
+ */
+ pmd_tmp = child->thread.pmod[pmd]+(child->thread.pmd[pmd]& perf_ovfl_val);
+
+ /*printk(__FUNCTION__" child=%d reading pmd[%ld]=%lx\n", child->pid, pmd, pmd_tmp);*/
+
+ ptr = &pmd_tmp;
+ }
+#endif
if (write_access)
*ptr = *data;
else
@@ -794,8 +859,9 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
static int
access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access)
{
- unsigned long *ptr, *rbs, *bspstore, ndirty, regnum;
+ unsigned long *ptr = NULL, *rbs, *bspstore, ndirty, regnum;
struct switch_stack *sw;
+ unsigned long pmd_tmp;
struct pt_regs *pt;
if ((addr & 0x7) != 0)
@@ -803,7 +869,10 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
if (addr < PT_F127+16) {
/* accessing fph */
- ia64_sync_fph(child);
+ if (write_access)
+ ia64_sync_fph(child);
+ else
+ ia64_flush_fph(child);
ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr);
} else if (addr < PT_F9+16) {
/* accessing switch_stack or pt_regs: */
@@ -864,6 +933,14 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
*data = (pt->cr_ipsr & IPSR_READ_MASK);
return 0;
+ case PT_AR_EC:
+ if (write_access)
+ sw->ar_pfs = (((*data & 0x3f) << 52)
+ | (sw->ar_pfs & ~(0x3fUL << 52)));
+ else
+ *data = (sw->ar_pfs >> 52) & 0x3f;
+ break;
+
case PT_R1: case PT_R2: case PT_R3:
case PT_R4: case PT_R5: case PT_R6: case PT_R7:
case PT_R8: case PT_R9: case PT_R10: case PT_R11:
@@ -900,7 +977,12 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
/* disallow accessing anything else... */
return -1;
}
- } else {
+ } else
+#ifdef CONFIG_PERFMON
+ if (addr < PT_PMD)
+#endif
+ {
+
/* access debug registers */
if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
@@ -921,6 +1003,33 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data
ptr += regnum;
}
+#ifdef CONFIG_PERFMON
+ else {
+ /*
+ * XXX: will eventually move back to perfmonctl()
+ */
+ unsigned long pmd = (addr - PT_PMD) >> 3;
+ extern unsigned long perf_ovfl_val;
+
+ /* we just use ptrace to read */
+ if (write_access) return -1;
+
+ if (pmd > 3) {
+ printk("ptrace: rejecting access to PMD[%ld] address 0x%lx\n", pmd, addr);
+ return -1;
+ }
+
+ /*
+ * We always need to mask upper 32bits of pmd because value is random
+ */
+ pmd_tmp = child->thread.pmod[pmd]+(child->thread.pmd[pmd]& perf_ovfl_val);
+
+ /*printk(__FUNCTION__" child=%d reading pmd[%ld]=%lx\n", child->pid, pmd, pmd_tmp);*/
+
+ ptr = &pmd_tmp;
+ }
+#endif
+
if (write_access)
*ptr = *data;
else
@@ -996,10 +1105,12 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
ret = -ESRCH;
if (!(child->ptrace & PT_PTRACED))
goto out_tsk;
+
if (child->state != TASK_STOPPED) {
- if (request != PTRACE_KILL)
+ if (request != PTRACE_KILL && request != PTRACE_PEEKUSR)
goto out_tsk;
}
+
if (child->p_pptr != current)
goto out_tsk;
diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c
index f73cd8968..87c7befea 100644
--- a/arch/ia64/kernel/sal.c
+++ b/arch/ia64/kernel/sal.c
@@ -34,6 +34,7 @@ default_handler (void)
}
ia64_sal_handler ia64_sal = (ia64_sal_handler) default_handler;
+ia64_sal_desc_ptc_t *ia64_ptc_domain_info;
const char *
ia64_sal_strerror (long status)
@@ -127,6 +128,10 @@ ia64_sal_init (struct ia64_sal_systab *systab)
ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp));
break;
+ case SAL_DESC_PTC:
+ ia64_ptc_domain_info = (ia64_sal_desc_ptc_t *)p;
+ break;
+
case SAL_DESC_AP_WAKEUP:
#ifdef CONFIG_SMP
{
diff --git a/arch/ia64/kernel/semaphore.c b/arch/ia64/kernel/semaphore.c
index 1bbe4feab..84ff34cf6 100644
--- a/arch/ia64/kernel/semaphore.c
+++ b/arch/ia64/kernel/semaphore.c
@@ -7,9 +7,9 @@
/*
* Semaphores are implemented using a two-way counter: The "count"
- * variable is decremented for each process that tries to aquire the
+ * variable is decremented for each process that tries to acquire the
* semaphore, while the "sleepers" variable is a count of such
- * aquires.
+ * acquires.
*
* Notably, the inline "up()" and "down()" functions can efficiently
* test if they need to do any extra work (up needs to do something
@@ -188,7 +188,7 @@ down_read_failed_biased (struct rw_semaphore *sem)
}
/*
- * This gets called if we failed to aquire the lock and we are not
+ * This gets called if we failed to acquire the lock and we are not
* biased to acquire the lock. We undo the decrement that was
* done earlier, go to sleep, and then attempt to re-acquire the
* lock afterwards.
@@ -279,7 +279,7 @@ down_write_failed (struct rw_semaphore *sem)
while (sem->count < 0) {
set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
if (sem->count >= 0)
- break; /* we must attempt to aquire or bias the lock */
+ break; /* we must attempt to acquire or bias the lock */
schedule();
}
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 62e3e19ea..ed091d864 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -36,6 +36,7 @@
#include <asm/system.h>
#include <asm/efi.h>
#include <asm/mca.h>
+#include <asm/smp.h>
#ifdef CONFIG_BLK_DEV_RAM
# include <linux/blk.h>
@@ -43,7 +44,7 @@
extern char _end;
-/* cpu_data[bootstrap_processor] is data for the bootstrap processor: */
+/* cpu_data[0] is data for the bootstrap processor: */
struct cpuinfo_ia64 cpu_data[NR_CPUS];
unsigned long ia64_cycles_per_usec;
@@ -56,6 +57,8 @@ int cpu_now_booting = 0;
volatile unsigned long cpu_online_map;
#endif
+unsigned long ia64_iobase; /* virtual address for I/O accesses */
+
#define COMMAND_LINE_SIZE 512
char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */
@@ -111,6 +114,7 @@ free_available_memory (unsigned long start, unsigned long end, void *arg)
void __init
setup_arch (char **cmdline_p)
{
+ extern unsigned long ia64_iobase;
unsigned long max_pfn, bootmap_start, bootmap_size;
unw_init();
@@ -157,7 +161,7 @@ setup_arch (char **cmdline_p)
if (initrd_start >= PAGE_OFFSET)
printk("Warning: boot loader passed virtual address "
"for initrd, please upgrade the loader\n");
- } else
+ else
#endif
/*
* The loader ONLY passes physical addresses
@@ -215,9 +219,16 @@ setup_arch (char **cmdline_p)
ia64_sal_init(efi.sal_systab);
#ifdef CONFIG_SMP
- bootstrap_processor = hard_smp_processor_id();
- current->processor = bootstrap_processor;
+ current->processor = 0;
+ cpu_physical_id(0) = hard_smp_processor_id();
#endif
+ /*
+ * Set `iobase' to the appropriate address in region 6
+ * (uncached access range)
+ */
+ __asm__ ("mov %0=ar.k0;;" : "=r"(ia64_iobase));
+ ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET);
+
cpu_init(); /* initialize the bootstrap CPU */
#ifdef CONFIG_IA64_GENERIC
@@ -259,6 +270,11 @@ setup_arch (char **cmdline_p)
int
get_cpuinfo (char *buffer)
{
+#ifdef CONFIG_SMP
+# define lps c->loops_per_sec
+#else
+# define lps loops_per_sec
+#endif
char family[32], model[32], features[128], *cp, *p = buffer;
struct cpuinfo_ia64 *c;
unsigned long mask;
@@ -309,7 +325,7 @@ get_cpuinfo (char *buffer)
features,
c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000,
c->itc_freq / 1000000, c->itc_freq % 1000000,
- loops_per_sec() / 500000, (loops_per_sec() / 5000) % 100);
+ lps / 500000, (lps / 5000) % 100);
}
return p - buffer;
}
@@ -371,8 +387,8 @@ identify_cpu (struct cpuinfo_ia64 *c)
#endif
phys_addr_size = vm1.pal_vm_info_1_s.phys_add_size;
}
- printk("processor implements %lu virtual and %lu physical address bits\n",
- impl_va_msb + 1, phys_addr_size);
+ printk("CPU %d: %lu virtual and %lu physical address bits\n",
+ smp_processor_id(), impl_va_msb + 1, phys_addr_size);
c->unimpl_va_mask = ~((7L<<61) | ((1L << (impl_va_msb + 1)) - 1));
c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
@@ -405,9 +421,12 @@ cpu_init (void)
* do NOT defer TLB misses, page-not-present, access bit, or
* debug faults but kernel code should not rely on any
* particular setting of these bits.
- */
ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP);
+ */
+ ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX );
+#ifndef CONFIG_SMP
ia64_set_fpu_owner(0); /* initialize ar.k5 */
+#endif
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 12f312672..e0adf1981 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -147,11 +147,12 @@ restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr)
ia64_put_nat_bits(&scr->pt, &scr->sw, nat); /* restore the original scratch NaT bits */
#endif
- if (flags & IA64_SC_FLAG_FPH_VALID) {
- struct task_struct *fpu_owner = ia64_get_fpu_owner();
+ if ((flags & IA64_SC_FLAG_FPH_VALID) != 0) {
+ struct ia64_psr *psr = ia64_psr(&scr->pt);
__copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16);
- if (fpu_owner == current) {
+ if (!psr->dfh) {
+ psr->mfh = 0;
__ia64_load_fpu(current->thread.fph);
}
}
@@ -235,9 +236,12 @@ ia64_rt_sigreturn (struct sigscratch *scr)
goto give_sigsegv;
sigdelsetmask(&set, ~_BLOCKABLE);
+
spin_lock_irq(&current->sigmask_lock);
- current->blocked = set;
- recalc_sigpending(current);
+ {
+ current->blocked = set;
+ recalc_sigpending(current);
+ }
spin_unlock_irq(&current->sigmask_lock);
if (restore_sigcontext(sc, scr))
@@ -274,7 +278,6 @@ ia64_rt_sigreturn (struct sigscratch *scr)
static long
setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr)
{
- struct task_struct *fpu_owner = ia64_get_fpu_owner();
unsigned long flags = 0, ifs, nat;
long err;
@@ -286,11 +289,9 @@ setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr)
/* if cr_ifs isn't valid, we got here through a syscall */
flags |= IA64_SC_FLAG_IN_SYSCALL;
}
- if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) {
+ ia64_flush_fph(current);
+ if ((current->thread.flags & IA64_THREAD_FPH_VALID)) {
flags |= IA64_SC_FLAG_FPH_VALID;
- if (fpu_owner == current) {
- __ia64_save_fpu(current->thread.fph);
- }
__copy_to_user(&sc->sc_fr[32], current->thread.fph, 96*16);
}
@@ -425,9 +426,11 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sigmask_lock);
- sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
- sigaddset(&current->blocked, sig);
- recalc_sigpending(current);
+ {
+ sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+ sigaddset(&current->blocked, sig);
+ recalc_sigpending(current);
+ }
spin_unlock_irq(&current->sigmask_lock);
}
return 1;
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index d64305cf3..694711507 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -6,6 +6,8 @@
*
* Lots of stuff stolen from arch/alpha/kernel/smp.c
*
+ * 00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_sec calibration on each CPU.
+ * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> fixed logical processor id
* 00/03/31 Rohit Seth <rohit.seth@intel.com> Fixes for Bootstrap Processor & cpu_online_map
* now gets done here (instead of setup.c)
* 99/10/05 davidm Update to bring it in sync with new command-line processing scheme.
@@ -27,6 +29,7 @@
#include <asm/bitops.h>
#include <asm/current.h>
#include <asm/delay.h>
+#include <asm/efi.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -39,27 +42,31 @@
#include <asm/system.h>
#include <asm/unistd.h>
+extern void __init calibrate_delay(void);
extern int cpu_idle(void * unused);
-extern void _start(void);
extern void machine_halt(void);
+extern void start_ap(void);
extern int cpu_now_booting; /* Used by head.S to find idle task */
extern volatile unsigned long cpu_online_map; /* Bitmap of available cpu's */
extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; /* Duh... */
+struct smp_boot_data smp_boot_data __initdata;
+
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
-struct smp_boot_data __initdata smp;
-char __initdata no_int_routing = 0;
+char __initdata no_int_routing;
unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */
-volatile int __cpu_number_map[NR_CPUS] = { -1, }; /* SAPIC ID -> Logical ID */
-volatile int __cpu_logical_map[NR_CPUS] = { -1, }; /* logical ID -> SAPIC ID */
+volatile int __cpu_physical_id[NR_CPUS] = { -1, }; /* Logical ID -> SAPIC ID */
int smp_num_cpus = 1;
-int bootstrap_processor = -1; /* SAPIC ID of BSP */
-int smp_threads_ready = 0; /* Set when the idlers are all forked */
-cycles_t cacheflush_time = 0;
+volatile int smp_threads_ready; /* Set when the idlers are all forked */
+cycles_t cacheflush_time;
unsigned long ap_wakeup_vector = -1; /* External Int to use to wakeup AP's */
+
+static volatile unsigned long cpu_callin_map;
+static volatile int smp_commenced;
+
static int max_cpus = -1; /* Command line */
static unsigned long ipi_op[NR_CPUS];
struct smp_call_struct {
@@ -135,6 +142,7 @@ halt_processor(void)
static inline int
pointer_lock(void *lock, void *data, int retry)
{
+ volatile long *ptr = lock;
again:
if (cmpxchg_acq((void **) lock, 0, data) == 0)
return 0;
@@ -142,7 +150,7 @@ pointer_lock(void *lock, void *data, int retry)
if (!retry)
return -EBUSY;
- while (*(void **) lock)
+ while (*ptr)
;
goto again;
@@ -275,12 +283,10 @@ static inline void
send_IPI_allbutself(int op)
{
int i;
- int cpu_id = 0;
for (i = 0; i < smp_num_cpus; i++) {
- cpu_id = __cpu_logical_map[i];
- if (cpu_id != smp_processor_id())
- send_IPI_single(cpu_id, op);
+ if (i != smp_processor_id())
+ send_IPI_single(i, op);
}
}
@@ -290,7 +296,7 @@ send_IPI_all(int op)
int i;
for (i = 0; i < smp_num_cpus; i++)
- send_IPI_single(__cpu_logical_map[i], op);
+ send_IPI_single(i, op);
}
static inline void
@@ -335,7 +341,7 @@ int
smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int retry, int wait)
{
struct smp_call_struct data;
- long timeout;
+ unsigned long timeout;
int cpus = 1;
if (cpuid == smp_processor_id()) {
@@ -387,7 +393,7 @@ int
smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
{
struct smp_call_struct data;
- long timeout;
+ unsigned long timeout;
int cpus = smp_num_cpus - 1;
if (cpus == 0)
@@ -453,80 +459,16 @@ smp_do_timer(struct pt_regs *regs)
if (--data->prof_counter <= 0) {
data->prof_counter = data->prof_multiplier;
- /*
- * update_process_times() expects us to have done irq_enter().
- * Besides, if we don't timer interrupts ignore the global
- * interrupt lock, which is the WrongThing (tm) to do.
- */
- irq_enter(cpu, 0);
update_process_times(user);
- irq_exit(cpu, 0);
}
}
-static inline void __init
-smp_calibrate_delay(int cpuid)
-{
- struct cpuinfo_ia64 *c = &cpu_data[cpuid];
-#if 0
- unsigned long old = loops_per_sec;
- extern void calibrate_delay(void);
-
- loops_per_sec = 0;
- calibrate_delay();
- c->loops_per_sec = loops_per_sec;
- loops_per_sec = old;
-#else
- c->loops_per_sec = loops_per_sec;
-#endif
-}
-
-/*
- * SAL shoves the AP's here when we start them. Physical mode, no kernel TR,
- * no RRs set, better than even chance that psr is bogus. Fix all that and
- * call _start. In effect, pretend to be lilo.
- *
- * Stolen from lilo_start.c. Thanks David!
- */
-void
-start_ap(void)
-{
- unsigned long flags;
-
- /*
- * Install a translation register that identity maps the
- * kernel's 256MB page(s).
- */
- ia64_clear_ic(flags);
- ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2));
- ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2));
- ia64_srlz_d();
- ia64_itr(0x3, 1, PAGE_OFFSET,
- pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))),
- _PAGE_SIZE_256M);
- ia64_srlz_i();
-
- flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH |
- IA64_PSR_BN);
-
- asm volatile ("movl r8 = 1f\n"
- ";;\n"
- "mov cr.ipsr=%0\n"
- "mov cr.iip=r8\n"
- "mov cr.ifs=r0\n"
- ";;\n"
- "rfi;;"
- "1:\n"
- "movl r1 = __gp" :: "r"(flags) : "r8");
- _start();
-}
-
/*
* AP's start using C here.
*/
void __init
-smp_callin(void)
+smp_callin (void)
{
extern void ia64_rid_init(void);
extern void ia64_init_itm(void);
@@ -534,12 +476,17 @@ smp_callin(void)
#ifdef CONFIG_PERFMON
extern void perfmon_init_percpu(void);
#endif
+ int cpu = smp_processor_id();
- efi_map_pal_code();
+ if (test_and_set_bit(cpu, &cpu_online_map)) {
+ printk("CPU#%d already initialized!\n", cpu);
+ machine_halt();
+ }
+ efi_map_pal_code();
cpu_init();
- smp_setup_percpu_timer(smp_processor_id());
+ smp_setup_percpu_timer(cpu);
/* setup the CPU local timer tick */
ia64_init_itm();
@@ -552,16 +499,16 @@ smp_callin(void)
ia64_set_lrr0(0, 1);
ia64_set_lrr1(0, 1);
- if (test_and_set_bit(smp_processor_id(), &cpu_online_map)) {
- printk("CPU#%d already initialized!\n", smp_processor_id());
- machine_halt();
- }
- while (!smp_threads_ready)
- mb();
-
local_irq_enable(); /* Interrupts have been off until now */
- smp_calibrate_delay(smp_processor_id());
- printk("SMP: CPU %d starting idle loop\n", smp_processor_id());
+
+ calibrate_delay();
+ my_cpu_data.loops_per_sec = loops_per_sec;
+
+ /* allow the master to continue */
+ set_bit(cpu, &cpu_callin_map);
+
+ /* finally, wait for the BP to finish initialization: */
+ while (!smp_commenced);
cpu_idle(NULL);
}
@@ -583,14 +530,13 @@ fork_by_hand(void)
}
/*
- * Bring one cpu online.
- *
- * NB: cpuid is the CPU BUS-LOCAL ID, not the entire SAPIC ID. See asm/smp.h.
+ * Bring one cpu online. Return 0 if this fails for any reason.
*/
static int __init
-smp_boot_one_cpu(int cpuid, int cpunum)
+smp_boot_one_cpu(int cpu)
{
struct task_struct *idle;
+ int cpu_phys_id = cpu_physical_id(cpu);
long timeout;
/*
@@ -603,50 +549,37 @@ smp_boot_one_cpu(int cpuid, int cpunum)
* Sheesh . . .
*/
if (fork_by_hand() < 0)
- panic("failed fork for CPU %d", cpuid);
+ panic("failed fork for CPU 0x%x", cpu_phys_id);
/*
* We remove it from the pidhash and the runqueue
* once we got the process:
*/
idle = init_task.prev_task;
if (!idle)
- panic("No idle process for CPU %d", cpuid);
- init_tasks[cpunum] = idle;
+ panic("No idle process for CPU 0x%x", cpu_phys_id);
+ init_tasks[cpu] = idle;
del_from_runqueue(idle);
unhash_process(idle);
/* Schedule the first task manually. */
- idle->processor = cpuid;
+ idle->processor = cpu;
idle->has_cpu = 1;
/* Let _start know what logical CPU we're booting (offset into init_tasks[] */
- cpu_now_booting = cpunum;
-
+ cpu_now_booting = cpu;
+
/* Kick the AP in the butt */
- ipi_send(cpuid, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
- ia64_srlz_i();
- mb();
+ ipi_send(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
- /*
- * OK, wait a bit for that CPU to finish staggering about. smp_callin() will
- * call cpu_init() which will set a bit for this AP. When that bit flips, the AP
- * is waiting for smp_threads_ready to be 1 and we can move on.
- */
+ /* wait up to 10s for the AP to start */
for (timeout = 0; timeout < 100000; timeout++) {
- if (test_bit(cpuid, &cpu_online_map))
- goto alive;
+ if (test_bit(cpu, &cpu_callin_map))
+ return 1;
udelay(100);
- barrier();
}
- printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
+ printk(KERN_ERR "SMP: Processor 0x%x is stuck.\n", cpu_phys_id);
return 0;
-
-alive:
- /* Remember the AP data */
- __cpu_number_map[cpuid] = cpunum;
- __cpu_logical_map[cpunum] = cpuid;
- return 1;
}
@@ -663,21 +596,20 @@ smp_boot_cpus(void)
unsigned long bogosum;
/* Take care of some initial bookkeeping. */
- memset(&__cpu_number_map, -1, sizeof(__cpu_number_map));
- memset(&__cpu_logical_map, -1, sizeof(__cpu_logical_map));
+ memset(&__cpu_physical_id, -1, sizeof(__cpu_physical_id));
memset(&ipi_op, 0, sizeof(ipi_op));
- /* Setup BSP mappings */
- __cpu_number_map[bootstrap_processor] = 0;
- __cpu_logical_map[0] = bootstrap_processor;
+ /* Setup BP mappings */
+ __cpu_physical_id[0] = hard_smp_processor_id();
- smp_calibrate_delay(smp_processor_id());
+ /* on the BP, the kernel already called calibrate_delay_loop() in init/main.c */
+ my_cpu_data.loops_per_sec = loops_per_sec;
#if 0
smp_tune_scheduling();
#endif
- smp_setup_percpu_timer(bootstrap_processor);
+ smp_setup_percpu_timer(0);
- if (test_and_set_bit(bootstrap_processor, &cpu_online_map)) {
+ if (test_and_set_bit(0, &cpu_online_map)) {
printk("CPU#%d already initialized!\n", smp_processor_id());
machine_halt();
}
@@ -692,16 +624,18 @@ smp_boot_cpus(void)
if (max_cpus != -1)
printk("Limiting CPUs to %d\n", max_cpus);
- if (smp.cpu_count > 1) {
+ if (smp_boot_data.cpu_count > 1) {
printk(KERN_INFO "SMP: starting up secondaries.\n");
- for (i = 0; i < NR_CPUS; i++) {
- if (smp.cpu_map[i] == -1 ||
- smp.cpu_map[i] == bootstrap_processor)
+ for (i = 0; i < smp_boot_data.cpu_count; i++) {
+ /* skip performance restricted and bootstrap cpu: */
+ if (smp_boot_data.cpu_phys_id[i] == -1
+ || smp_boot_data.cpu_phys_id[i] == hard_smp_processor_id())
continue;
- if (smp_boot_one_cpu(smp.cpu_map[i], cpu_count) == 0)
- continue;
+ cpu_physical_id(cpu_count) = smp_boot_data.cpu_phys_id[i];
+ if (!smp_boot_one_cpu(cpu_count))
+ continue; /* failed */
cpu_count++; /* Count good CPUs only... */
/*
@@ -731,20 +665,12 @@ smp_boot_cpus(void)
}
/*
- * Called from main.c by each AP.
+ * Called when the BP is just about to fire off init.
*/
void __init
smp_commence(void)
{
- mb();
-}
-
-/*
- * Not used; part of the i386 bringup
- */
-void __init
-initialize_secondary(void)
-{
+ smp_commenced = 1;
}
int __init
@@ -759,9 +685,7 @@ setup_profiling_timer(unsigned int multiplier)
*
* Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP().
*
- * So this just gets the BSP SAPIC ID and print's it out. Dull, huh?
- *
- * Not anymore. This also registers the AP OS_MC_REDVEZ address with SAL.
+ * This also registers the AP OS_MC_REDVEZ address with SAL.
*/
void __init
init_smp_config(void)
@@ -772,9 +696,6 @@ init_smp_config(void)
} *ap_startup;
long sal_ret;
- /* Grab the BSP ID */
- bootstrap_processor = hard_smp_processor_id();
-
/* Tell SAL where to drop the AP's. */
ap_startup = (struct fptr *) start_ap;
sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ,
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 3550cc390..83bff8b0c 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -1,2 +1,74 @@
-unsigned long cpu_online_map;
+/*
+ * SMP Support
+ *
+ * Application processor startup code, moved from smp.c to better support kernel profile
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/current.h>
+#include <asm/delay.h>
+#include <asm/efi.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/sal.h>
+#include <asm/system.h>
+#include <asm/unistd.h>
+
+/*
+ * SAL shoves the AP's here when we start them. Physical mode, no kernel TR,
+ * no RRs set, better than even chance that psr is bogus. Fix all that and
+ * call _start. In effect, pretend to be lilo.
+ *
+ * Stolen from lilo_start.c. Thanks David!
+ */
+void
+start_ap(void)
+{
+ extern void _start (void);
+ unsigned long flags;
+
+ /*
+ * Install a translation register that identity maps the
+ * kernel's 256MB page(s).
+ */
+ ia64_clear_ic(flags);
+ ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2));
+ ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2));
+ ia64_srlz_d();
+ ia64_itr(0x3, 1, PAGE_OFFSET,
+ pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))),
+ _PAGE_SIZE_256M);
+ ia64_srlz_i();
+
+ flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH |
+ IA64_PSR_BN);
+
+ asm volatile ("movl r8 = 1f\n"
+ ";;\n"
+ "mov cr.ipsr=%0\n"
+ "mov cr.iip=r8\n"
+ "mov cr.ifs=r0\n"
+ ";;\n"
+ "rfi;;"
+ "1:\n"
+ "movl r1 = __gp" :: "r"(flags) : "r8");
+ _start();
+}
+
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index a3e5242fc..f78512229 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -147,7 +147,7 @@ sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, l
struct pt_regs *regs = (struct pt_regs *) &stack;
addr = do_mmap2(addr, len, prot, flags, fd, pgoff);
- if (!IS_ERR(addr))
+ if (!IS_ERR((void *) addr))
regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */
return addr;
}
@@ -162,26 +162,12 @@ sys_mmap (unsigned long addr, unsigned long len, int prot, int flags,
return -EINVAL;
addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
- if (!IS_ERR(addr))
+ if (!IS_ERR((void *) addr))
regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */
return addr;
}
asmlinkage long
-sys_ioperm (unsigned long from, unsigned long num, int on)
-{
- printk(KERN_ERR "sys_ioperm(from=%lx, num=%lx, on=%d)\n", from, num, on);
- return -EIO;
-}
-
-asmlinkage long
-sys_iopl (int level, long arg1, long arg2, long arg3)
-{
- printk(KERN_ERR "sys_iopl(level=%d)!\n", level);
- return -ENOSYS;
-}
-
-asmlinkage long
sys_vm86 (long arg0, long arg1, long arg2, long arg3)
{
printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
@@ -204,7 +190,7 @@ ia64_create_module (const char *name_user, size_t size, long arg2, long arg3,
unsigned long addr;
addr = sys_create_module (name_user, size);
- if (!IS_ERR(addr))
+ if (!IS_ERR((void *) addr))
regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */
return addr;
}
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 96ff76c01..5e54e4f4b 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -183,7 +183,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#ifdef CONFIG_SMP
smp_do_timer(regs);
- if (smp_processor_id() == bootstrap_processor)
+ if (smp_processor_id() == 0)
do_timer(regs);
#else
do_timer(regs);
@@ -303,7 +303,7 @@ ia64_init_itm (void)
itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
itm.delta = itc_freq / HZ;
- printk("timer: CPU %d base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n",
+ printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n",
smp_processor_id(),
platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index bf1abd839..43340bf85 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -192,38 +192,45 @@ ia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, uns
}
/*
- * disabled_fp_fault() is called when a user-level process attempts to
- * access one of the registers f32..f127 while it doesn't own the
+ * disabled_fph_fault() is called when a user-level process attempts
+ * to access one of the registers f32..f127 when it doesn't own the
* fp-high register partition. When this happens, we save the current
* fph partition in the task_struct of the fpu-owner (if necessary)
* and then load the fp-high partition of the current task (if
- * necessary).
+ * necessary). Note that the kernel has access to fph by the time we
+ * get here, as the IVT's "Diabled FP-Register" handler takes care of
+ * clearing psr.dfh.
*/
static inline void
disabled_fph_fault (struct pt_regs *regs)
{
- struct task_struct *fpu_owner = ia64_get_fpu_owner();
+ struct ia64_psr *psr = ia64_psr(regs);
- /* first, clear psr.dfh and psr.mfh: */
- regs->cr_ipsr &= ~(IA64_PSR_DFH | IA64_PSR_MFH);
- if (fpu_owner != current) {
- ia64_set_fpu_owner(current);
+ /* first, grant user-level access to fph partition: */
+ psr->dfh = 0;
+#ifndef CONFIG_SMP
+ {
+ struct task_struct *fpu_owner = ia64_get_fpu_owner();
- if (fpu_owner && ia64_psr(ia64_task_regs(fpu_owner))->mfh) {
- ia64_psr(ia64_task_regs(fpu_owner))->mfh = 0;
- fpu_owner->thread.flags |= IA64_THREAD_FPH_VALID;
- __ia64_save_fpu(fpu_owner->thread.fph);
- }
- if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) {
- __ia64_load_fpu(current->thread.fph);
- } else {
- __ia64_init_fpu();
- /*
- * Set mfh because the state in thread.fph does not match
- * the state in the fph partition.
- */
- ia64_psr(regs)->mfh = 1;
- }
+ if (fpu_owner == current)
+ return;
+
+ if (fpu_owner)
+ ia64_flush_fph(fpu_owner);
+
+ ia64_set_fpu_owner(current);
+ }
+#endif /* !CONFIG_SMP */
+ if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) {
+ __ia64_load_fpu(current->thread.fph);
+ psr->mfh = 0;
+ } else {
+ __ia64_init_fpu();
+ /*
+ * Set mfh because the state in thread.fph does not match the state in
+ * the fph partition.
+ */
+ psr->mfh = 1;
}
}
@@ -247,20 +254,21 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long
* kernel, so set those bits in the mask and set the low volatile
* pointer to point to these registers.
*/
- fp_state.bitmask_low64 = 0xffc0; /* bit6..bit15 */
#ifndef FPSWA_BUG
- fp_state.fp_state_low_volatile = &regs->f6;
+ fp_state.bitmask_low64 = 0x3c0; /* bit 6..9 */
+ fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) &regs->f6;
#else
+ fp_state.bitmask_low64 = 0xffc0; /* bit6..bit15 */
f6_15[0] = regs->f6;
f6_15[1] = regs->f7;
f6_15[2] = regs->f8;
f6_15[3] = regs->f9;
- __asm__ ("stf.spill %0=f10" : "=m"(f6_15[4]));
- __asm__ ("stf.spill %0=f11" : "=m"(f6_15[5]));
- __asm__ ("stf.spill %0=f12" : "=m"(f6_15[6]));
- __asm__ ("stf.spill %0=f13" : "=m"(f6_15[7]));
- __asm__ ("stf.spill %0=f14" : "=m"(f6_15[8]));
- __asm__ ("stf.spill %0=f15" : "=m"(f6_15[9]));
+ __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4]));
+ __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5]));
+ __asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6]));
+ __asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7]));
+ __asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8]));
+ __asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9]));
fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15;
#endif
/*
@@ -279,12 +287,12 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long
(unsigned long *) isr, (unsigned long *) pr,
(unsigned long *) ifs, &fp_state);
#ifdef FPSWA_BUG
- __asm__ ("ldf.fill f10=%0" :: "m"(f6_15[4]));
- __asm__ ("ldf.fill f11=%0" :: "m"(f6_15[5]));
- __asm__ ("ldf.fill f12=%0" :: "m"(f6_15[6]));
- __asm__ ("ldf.fill f13=%0" :: "m"(f6_15[7]));
- __asm__ ("ldf.fill f14=%0" :: "m"(f6_15[8]));
- __asm__ ("ldf.fill f15=%0" :: "m"(f6_15[9]));
+ __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4]));
+ __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5]));
+ __asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6]));
+ __asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7]));
+ __asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8]));
+ __asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9]));
regs->f6 = f6_15[0];
regs->f7 = f6_15[1];
regs->f8 = f6_15[2];
diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
index 7ca1146a0..7cc238a83 100644
--- a/arch/ia64/kernel/unaligned.c
+++ b/arch/ia64/kernel/unaligned.c
@@ -278,9 +278,9 @@ set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
bspstore = (unsigned long *)regs->ar_bspstore;
DPRINT(("rse_slot_num=0x%lx\n",ia64_rse_slot_num((unsigned long *)sw->ar_bspstore)));
- DPRINT(("kbs=%p nlocals=%ld\n", kbs, nlocals));
+ DPRINT(("kbs=%p nlocals=%ld\n", (void *) kbs, nlocals));
DPRINT(("bspstore next rnat slot %p\n",
- ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore)));
+ (void *) ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore)));
DPRINT(("on_kbs=%ld rnats=%ld\n",
on_kbs, ((sw->ar_bspstore-(unsigned long)kbs)>>3) - on_kbs));
@@ -292,7 +292,7 @@ set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
addr = slot = ia64_rse_skip_regs(bsp, r1 - 32);
DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n",
- ubs_end, bsp, addr, ia64_rse_slot_num(addr)));
+ (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr)));
ia64_poke(regs, current, (unsigned long)addr, val);
@@ -303,7 +303,7 @@ set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
ia64_peek(regs, current, (unsigned long)addr, &rnats);
DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n",
- addr, rnats, nat, rnats &ia64_rse_slot_num(slot)));
+ (void *) addr, rnats, nat, rnats &ia64_rse_slot_num(slot)));
if (nat) {
rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot);
@@ -312,7 +312,7 @@ set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
}
ia64_poke(regs, current, (unsigned long)addr, rnats);
- DPRINT(("rnat changed to @%p = 0x%lx\n", addr, rnats));
+ DPRINT(("rnat changed to @%p = 0x%lx\n", (void *) addr, rnats));
}
@@ -373,7 +373,7 @@ get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat
addr = slot = ia64_rse_skip_regs(bsp, r1 - 32);
DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n",
- ubs_end, bsp, addr, ia64_rse_slot_num(addr)));
+ (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr)));
ia64_peek(regs, current, (unsigned long)addr, val);
@@ -383,7 +383,7 @@ get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat
addr = ia64_rse_rnat_addr(addr);
ia64_peek(regs, current, (unsigned long)addr, &rnats);
- DPRINT(("rnat @%p = 0x%lx\n", addr, rnats));
+ DPRINT(("rnat @%p = 0x%lx\n", (void *) addr, rnats));
if (nat)
*nat = rnats >> ia64_rse_slot_num(slot) & 0x1;
@@ -437,13 +437,13 @@ setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs)
* UNAT bit_pos = GR[r3]{8:3} form EAS-2.4
*/
bitmask = __IA64_UL(1) << (addr >> 3 & 0x3f);
- DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, unat, *unat));
+ DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat));
if (nat) {
*unat |= bitmask;
} else {
*unat &= ~bitmask;
}
- DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, unat,*unat));
+ DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat));
}
#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)
@@ -455,16 +455,15 @@ setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
unsigned long addr;
/*
- * From EAS-2.5: FPDisableFault has higher priority than
- * Unaligned Fault. Thus, when we get here, we know the partition is
- * enabled.
+ * From EAS-2.5: FPDisableFault has higher priority than Unaligned
+ * Fault. Thus, when we get here, we know the partition is enabled.
+ * To update f32-f127, there are three choices:
+ *
+ * (1) save f32-f127 to thread.fph and update the values there
+ * (2) use a gigantic switch statement to directly access the registers
+ * (3) generate code on the fly to update the desired register
*
- * The registers [32-127] are ususally saved in the tss. When get here,
- * they are NECESSARILY live because they are only saved explicitely.
- * We have 3 ways of updating the values: force a save of the range
- * in tss, use a gigantic switch/case statement or generate code on the
- * fly to store to the right register.
- * For now, we are using the (slow) save/restore way.
+ * For now, we are using approach (1).
*/
if (regnum >= IA64_FIRST_ROTATING_FR) {
ia64_sync_fph(current);
@@ -491,7 +490,6 @@ setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
* let's do it for safety.
*/
regs->cr_ipsr |= IA64_PSR_MFL;
-
}
}
@@ -522,12 +520,12 @@ getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
* Unaligned Fault. Thus, when we get here, we know the partition is
* enabled.
*
- * When regnum > 31, the register is still live and
- * we need to force a save to the tss to get access to it.
- * See discussion in setfpreg() for reasons and other ways of doing this.
+ * When regnum > 31, the register is still live and we need to force a save
+ * to current->thread.fph to get access to it. See discussion in setfpreg()
+ * for reasons and other ways of doing this.
*/
if (regnum >= IA64_FIRST_ROTATING_FR) {
- ia64_sync_fph(current);
+ ia64_flush_fph(current);
*fpval = current->thread.fph[IA64_FPH_OFFS(regnum)];
} else {
/*
@@ -1084,9 +1082,9 @@ emulate_load_floatpair(unsigned long ifa, load_store_t *ld, struct pt_regs *regs
/*
* XXX fixme
*
- * A possible optimization would be to drop fpr_final
- * and directly use the storage from the saved context i.e.,
- * the actual final destination (pt_regs, switch_stack or tss).
+ * A possible optimization would be to drop fpr_final and directly
+ * use the storage from the saved context i.e., the actual final
+ * destination (pt_regs, switch_stack or thread structure).
*/
setfpreg(ld->r1, &fpr_final[0], regs);
setfpreg(ld->imm, &fpr_final[1], regs);
@@ -1212,9 +1210,9 @@ emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
/*
* XXX fixme
*
- * A possible optimization would be to drop fpr_final
- * and directly use the storage from the saved context i.e.,
- * the actual final destination (pt_regs, switch_stack or tss).
+ * A possible optimization would be to drop fpr_final and directly
+ * use the storage from the saved context i.e., the actual final
+ * destination (pt_regs, switch_stack or thread structure).
*/
setfpreg(ld->r1, &fpr_final, regs);
}
@@ -1223,9 +1221,7 @@ emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
* check for updates on any loads
*/
if (ld->op == 0x7 || ld->m)
- emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG,
- ld, regs, ifa);
-
+ emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);
/*
* invalidate ALAT entry in case of advanced floating point loads
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
index 5d0049f32..21a2ead16 100644
--- a/arch/ia64/kernel/unwind.c
+++ b/arch/ia64/kernel/unwind.c
@@ -66,7 +66,7 @@
#define UNW_STATS 0 /* WARNING: this disabled interrupts for long time-spans!! */
#if UNW_DEBUG
- static long unw_debug_level = 1;
+ static long unw_debug_level = 255;
# define debug(level,format...) if (unw_debug_level > level) printk(format)
# define dprintk(format...) printk(format)
# define inline
@@ -111,7 +111,7 @@ static struct {
struct unw_table kernel_table;
/* hash table that maps instruction pointer to script index: */
- unw_hash_index_t hash[UNW_HASH_SIZE];
+ unsigned short hash[UNW_HASH_SIZE];
/* script cache: */
struct unw_script cache[UNW_CACHE_SIZE];
@@ -152,47 +152,47 @@ static struct {
UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
},
preg_index: {
- struct_offset(struct unw_frame_info, pri_unat)/8, /* PRI_UNAT_GR */
- struct_offset(struct unw_frame_info, pri_unat)/8, /* PRI_UNAT_MEM */
- struct_offset(struct unw_frame_info, pbsp)/8,
- struct_offset(struct unw_frame_info, bspstore)/8,
- struct_offset(struct unw_frame_info, pfs)/8,
- struct_offset(struct unw_frame_info, rnat)/8,
+ struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */
+ struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */
+ struct_offset(struct unw_frame_info, bsp_loc)/8,
+ struct_offset(struct unw_frame_info, bspstore_loc)/8,
+ struct_offset(struct unw_frame_info, pfs_loc)/8,
+ struct_offset(struct unw_frame_info, rnat_loc)/8,
struct_offset(struct unw_frame_info, psp)/8,
- struct_offset(struct unw_frame_info, rp)/8,
+ struct_offset(struct unw_frame_info, rp_loc)/8,
struct_offset(struct unw_frame_info, r4)/8,
struct_offset(struct unw_frame_info, r5)/8,
struct_offset(struct unw_frame_info, r6)/8,
struct_offset(struct unw_frame_info, r7)/8,
- struct_offset(struct unw_frame_info, unat)/8,
- struct_offset(struct unw_frame_info, pr)/8,
- struct_offset(struct unw_frame_info, lc)/8,
- struct_offset(struct unw_frame_info, fpsr)/8,
- struct_offset(struct unw_frame_info, b1)/8,
- struct_offset(struct unw_frame_info, b2)/8,
- struct_offset(struct unw_frame_info, b3)/8,
- struct_offset(struct unw_frame_info, b4)/8,
- struct_offset(struct unw_frame_info, b5)/8,
- struct_offset(struct unw_frame_info, f2)/8,
- struct_offset(struct unw_frame_info, f3)/8,
- struct_offset(struct unw_frame_info, f4)/8,
- struct_offset(struct unw_frame_info, f5)/8,
- struct_offset(struct unw_frame_info, fr[16 - 16])/8,
- struct_offset(struct unw_frame_info, fr[17 - 16])/8,
- struct_offset(struct unw_frame_info, fr[18 - 16])/8,
- struct_offset(struct unw_frame_info, fr[19 - 16])/8,
- struct_offset(struct unw_frame_info, fr[20 - 16])/8,
- struct_offset(struct unw_frame_info, fr[21 - 16])/8,
- struct_offset(struct unw_frame_info, fr[22 - 16])/8,
- struct_offset(struct unw_frame_info, fr[23 - 16])/8,
- struct_offset(struct unw_frame_info, fr[24 - 16])/8,
- struct_offset(struct unw_frame_info, fr[25 - 16])/8,
- struct_offset(struct unw_frame_info, fr[26 - 16])/8,
- struct_offset(struct unw_frame_info, fr[27 - 16])/8,
- struct_offset(struct unw_frame_info, fr[28 - 16])/8,
- struct_offset(struct unw_frame_info, fr[29 - 16])/8,
- struct_offset(struct unw_frame_info, fr[30 - 16])/8,
- struct_offset(struct unw_frame_info, fr[31 - 16])/8,
+ struct_offset(struct unw_frame_info, unat_loc)/8,
+ struct_offset(struct unw_frame_info, pr_loc)/8,
+ struct_offset(struct unw_frame_info, lc_loc)/8,
+ struct_offset(struct unw_frame_info, fpsr_loc)/8,
+ struct_offset(struct unw_frame_info, b1_loc)/8,
+ struct_offset(struct unw_frame_info, b2_loc)/8,
+ struct_offset(struct unw_frame_info, b3_loc)/8,
+ struct_offset(struct unw_frame_info, b4_loc)/8,
+ struct_offset(struct unw_frame_info, b5_loc)/8,
+ struct_offset(struct unw_frame_info, f2_loc)/8,
+ struct_offset(struct unw_frame_info, f3_loc)/8,
+ struct_offset(struct unw_frame_info, f4_loc)/8,
+ struct_offset(struct unw_frame_info, f5_loc)/8,
+ struct_offset(struct unw_frame_info, fr_loc[16 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[17 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[18 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[19 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[20 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[21 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[22 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[23 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[24 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[25 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[26 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[27 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[28 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[29 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[30 - 16])/8,
+ struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8,
},
hash : { [0 ... UNW_HASH_SIZE - 1] = -1 },
#if UNW_DEBUG
@@ -211,6 +211,27 @@ static struct {
/* Unwind accessors. */
+/*
+ * Returns offset of rREG in struct pt_regs.
+ */
+static inline unsigned long
+pt_regs_off (unsigned long reg)
+{
+ unsigned long off =0;
+
+ if (reg >= 1 && reg <= 3)
+ off = struct_offset(struct pt_regs, r1) + 8*(reg - 1);
+ else if (reg <= 11)
+ off = struct_offset(struct pt_regs, r8) + 8*(reg - 8);
+ else if (reg <= 15)
+ off = struct_offset(struct pt_regs, r12) + 8*(reg - 12);
+ else if (reg <= 31)
+ off = struct_offset(struct pt_regs, r16) + 8*(reg - 16);
+ else
+ dprintk("unwind: bad scratch reg r%lu\n", reg);
+ return off;
+}
+
int
unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write)
{
@@ -251,26 +272,23 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char
}
/* fall through */
case UNW_NAT_NONE:
+ dummy_nat = 0;
nat_addr = &dummy_nat;
break;
- case UNW_NAT_SCRATCH:
- if (info->pri_unat)
- nat_addr = info->pri_unat;
- else
- nat_addr = &info->sw->caller_unat;
- case UNW_NAT_PRI_UNAT:
+ case UNW_NAT_MEMSTK:
nat_mask = (1UL << ((long) addr & 0x1f8)/8);
break;
- case UNW_NAT_STACKED:
+ case UNW_NAT_REGSTK:
nat_addr = ia64_rse_rnat_addr(addr);
if ((unsigned long) addr < info->regstk.limit
|| (unsigned long) addr >= info->regstk.top)
{
- dprintk("unwind: 0x%p outside of regstk "
- "[0x%lx-0x%lx)\n", addr,
- info->regstk.limit, info->regstk.top);
+ dprintk("unwind: %p outside of regstk "
+ "[0x%lx-0x%lx)\n", (void *) addr,
+ info->regstk.limit,
+ info->regstk.top);
return -1;
}
if ((unsigned long) nat_addr >= info->regstk.top)
@@ -289,18 +307,11 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char
pt = (struct pt_regs *) info->psp - 1;
else
pt = (struct pt_regs *) info->sp - 1;
- if (regnum <= 3)
- addr = &pt->r1 + (regnum - 1);
- else if (regnum <= 11)
- addr = &pt->r8 + (regnum - 8);
- else if (regnum <= 15)
- addr = &pt->r12 + (regnum - 12);
- else
- addr = &pt->r16 + (regnum - 16);
- if (info->pri_unat)
- nat_addr = info->pri_unat;
+ addr = (unsigned long *) ((long) pt + pt_regs_off(regnum));
+ if (info->pri_unat_loc)
+ nat_addr = info->pri_unat_loc;
else
- nat_addr = &info->sw->caller_unat;
+ nat_addr = &info->sw->ar_unat;
nat_mask = (1UL << ((long) addr & 0x1f8)/8);
}
} else {
@@ -320,7 +331,10 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char
if (write) {
*addr = *val;
- *nat_addr = (*nat_addr & ~nat_mask) | nat_mask;
+ if (*nat)
+ *nat_addr |= nat_mask;
+ else
+ *nat_addr &= ~nat_mask;
} else {
*val = *addr;
*nat = (*nat_addr & nat_mask) != 0;
@@ -346,7 +360,7 @@ unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int
/* preserved: */
case 1: case 2: case 3: case 4: case 5:
- addr = *(&info->b1 + (regnum - 1));
+ addr = *(&info->b1_loc + (regnum - 1));
if (!addr)
addr = &info->sw->b1 + (regnum - 1);
break;
@@ -379,7 +393,7 @@ unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val,
pt = (struct pt_regs *) info->sp - 1;
if (regnum <= 5) {
- addr = *(&info->f2 + (regnum - 2));
+ addr = *(&info->f2_loc + (regnum - 2));
if (!addr)
addr = &info->sw->f2 + (regnum - 2);
} else if (regnum <= 15) {
@@ -388,13 +402,16 @@ unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val,
else
addr = &info->sw->f10 + (regnum - 10);
} else if (regnum <= 31) {
- addr = info->fr[regnum - 16];
+ addr = info->fr_loc[regnum - 16];
if (!addr)
addr = &info->sw->f16 + (regnum - 16);
} else {
struct task_struct *t = info->task;
- ia64_sync_fph(t);
+ if (write)
+ ia64_sync_fph(t);
+ else
+ ia64_flush_fph(t);
addr = t->thread.fph + (regnum - 32);
}
@@ -418,52 +435,53 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int
switch (regnum) {
case UNW_AR_BSP:
- addr = info->pbsp;
+ addr = info->bsp_loc;
if (!addr)
addr = &info->sw->ar_bspstore;
break;
case UNW_AR_BSPSTORE:
- addr = info->bspstore;
+ addr = info->bspstore_loc;
if (!addr)
addr = &info->sw->ar_bspstore;
break;
case UNW_AR_PFS:
- addr = info->pfs;
+ addr = info->pfs_loc;
if (!addr)
addr = &info->sw->ar_pfs;
break;
case UNW_AR_RNAT:
- addr = info->rnat;
+ addr = info->rnat_loc;
if (!addr)
addr = &info->sw->ar_rnat;
break;
case UNW_AR_UNAT:
- addr = info->unat;
+ addr = info->unat_loc;
if (!addr)
addr = &info->sw->ar_unat;
break;
case UNW_AR_LC:
- addr = info->lc;
+ addr = info->lc_loc;
if (!addr)
addr = &info->sw->ar_lc;
break;
case UNW_AR_EC:
- if (!info->cfm)
+ if (!info->cfm_loc)
return -1;
if (write)
- *info->cfm = (*info->cfm & ~(0x3fUL << 52)) | ((*val & 0x3f) << 52);
+ *info->cfm_loc =
+ (*info->cfm_loc & ~(0x3fUL << 52)) | ((*val & 0x3f) << 52);
else
- *val = (*info->cfm >> 52) & 0x3f;
+ *val = (*info->cfm_loc >> 52) & 0x3f;
return 0;
case UNW_AR_FPSR:
- addr = info->fpsr;
+ addr = info->fpsr_loc;
if (!addr)
addr = &info->sw->ar_fpsr;
break;
@@ -493,7 +511,7 @@ unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write)
{
unsigned long *addr;
- addr = info->pr;
+ addr = info->pr_loc;
if (!addr)
addr = &info->sw->pr;
@@ -605,9 +623,8 @@ finish_prologue (struct unw_state_record *sr)
int i;
/*
- * First, resolve implicit register save locations
- * (see Section "11.4.2.3 Rules for Using Unwind
- * Descriptors", rule 3):
+ * First, resolve implicit register save locations (see Section "11.4.2.3 Rules
+ * for Using Unwind Descriptors", rule 3):
*/
for (i = 0; i < (int) sizeof(unw.save_order)/sizeof(unw.save_order[0]); ++i) {
reg = sr->curr.reg + unw.save_order[i];
@@ -1045,16 +1062,16 @@ desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word
static inline unw_hash_index_t
hash (unsigned long ip)
{
-# define magic 0x9e3779b97f4a7c16 /* (sqrt(5)/2-1)*2^64 */
+# define magic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */
return (ip >> 4)*magic >> (64 - UNW_LOG_HASH_SIZE);
}
static inline long
-cache_match (struct unw_script *script, unsigned long ip, unsigned long pr_val)
+cache_match (struct unw_script *script, unsigned long ip, unsigned long pr)
{
read_lock(&script->lock);
- if ((ip) == (script)->ip && (((pr_val) ^ (script)->pr_val) & (script)->pr_mask) == 0)
+ if (ip == script->ip && ((pr ^ script->pr_val) & script->pr_mask) == 0)
/* keep the read lock... */
return 1;
read_unlock(&script->lock);
@@ -1065,21 +1082,26 @@ static inline struct unw_script *
script_lookup (struct unw_frame_info *info)
{
struct unw_script *script = unw.cache + info->hint;
- unsigned long ip, pr_val;
+ unsigned short index;
+ unsigned long ip, pr;
STAT(++unw.stat.cache.lookups);
ip = info->ip;
- pr_val = info->pr_val;
+ pr = info->pr;
- if (cache_match(script, ip, pr_val)) {
+ if (cache_match(script, ip, pr)) {
STAT(++unw.stat.cache.hinted_hits);
return script;
}
- script = unw.cache + unw.hash[hash(ip)];
+ index = unw.hash[hash(ip)];
+ if (index >= UNW_CACHE_SIZE)
+ return 0;
+
+ script = unw.cache + index;
while (1) {
- if (cache_match(script, ip, pr_val)) {
+ if (cache_match(script, ip, pr)) {
/* update hint; no locking required as single-word writes are atomic */
STAT(++unw.stat.cache.normal_hits);
unw.cache[info->prev_script].hint = script - unw.cache;
@@ -1099,8 +1121,8 @@ static inline struct unw_script *
script_new (unsigned long ip)
{
struct unw_script *script, *prev, *tmp;
+ unw_hash_index_t index;
unsigned long flags;
- unsigned char index;
unsigned short head;
STAT(++unw.stat.script.news);
@@ -1133,22 +1155,24 @@ script_new (unsigned long ip)
unw.lru_tail = head;
/* remove the old script from the hash table (if it's there): */
- index = hash(script->ip);
- tmp = unw.cache + unw.hash[index];
- prev = 0;
- while (1) {
- if (tmp == script) {
- if (prev)
- prev->coll_chain = tmp->coll_chain;
- else
- unw.hash[index] = tmp->coll_chain;
- break;
- } else
- prev = tmp;
- if (tmp->coll_chain >= UNW_CACHE_SIZE)
+ if (script->ip) {
+ index = hash(script->ip);
+ tmp = unw.cache + unw.hash[index];
+ prev = 0;
+ while (1) {
+ if (tmp == script) {
+ if (prev)
+ prev->coll_chain = tmp->coll_chain;
+ else
+ unw.hash[index] = tmp->coll_chain;
+ break;
+ } else
+ prev = tmp;
+ if (tmp->coll_chain >= UNW_CACHE_SIZE)
/* old script wasn't in the hash-table */
- break;
- tmp = unw.cache + tmp->coll_chain;
+ break;
+ tmp = unw.cache + tmp->coll_chain;
+ }
}
/* enter new script in the hash table */
@@ -1198,19 +1222,17 @@ emit_nat_info (struct unw_state_record *sr, int i, struct unw_script *script)
struct unw_reg_info *r = sr->curr.reg + i;
enum unw_insn_opcode opc;
struct unw_insn insn;
- unsigned long val;
+ unsigned long val = 0;
switch (r->where) {
case UNW_WHERE_GR:
if (r->val >= 32) {
/* register got spilled to a stacked register */
opc = UNW_INSN_SETNAT_TYPE;
- val = UNW_NAT_STACKED;
- } else {
+ val = UNW_NAT_REGSTK;
+ } else
/* register got spilled to a scratch register */
- opc = UNW_INSN_SETNAT_TYPE;
- val = UNW_NAT_SCRATCH;
- }
+ opc = UNW_INSN_SETNAT_MEMSTK;
break;
case UNW_WHERE_FR:
@@ -1225,8 +1247,7 @@ emit_nat_info (struct unw_state_record *sr, int i, struct unw_script *script)
case UNW_WHERE_PSPREL:
case UNW_WHERE_SPREL:
- opc = UNW_INSN_SETNAT_PRI_UNAT;
- val = 0;
+ opc = UNW_INSN_SETNAT_MEMSTK;
break;
default:
@@ -1267,18 +1288,8 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script)
}
val = unw.preg_index[UNW_REG_R4 + (rval - 4)];
} else {
- opc = UNW_INSN_LOAD_SPREL;
- val = -sizeof(struct pt_regs);
- if (rval >= 1 && rval <= 3)
- val += struct_offset(struct pt_regs, r1) + 8*(rval - 1);
- else if (rval <= 11)
- val += struct_offset(struct pt_regs, r8) + 8*(rval - 8);
- else if (rval <= 15)
- val += struct_offset(struct pt_regs, r12) + 8*(rval - 12);
- else if (rval <= 31)
- val += struct_offset(struct pt_regs, r16) + 8*(rval - 16);
- else
- dprintk("unwind: bad scratch reg r%lu\n", rval);
+ opc = UNW_INSN_ADD_SP;
+ val = -sizeof(struct pt_regs) + pt_regs_off(rval);
}
break;
@@ -1288,7 +1299,7 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script)
else if (rval >= 16 && rval <= 31)
val = unw.preg_index[UNW_REG_F16 + (rval - 16)];
else {
- opc = UNW_INSN_LOAD_SPREL;
+ opc = UNW_INSN_ADD_SP;
val = -sizeof(struct pt_regs);
if (rval <= 9)
val += struct_offset(struct pt_regs, f6) + 16*(rval - 6);
@@ -1301,7 +1312,7 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script)
if (rval >= 1 && rval <= 5)
val = unw.preg_index[UNW_REG_B1 + (rval - 1)];
else {
- opc = UNW_INSN_LOAD_SPREL;
+ opc = UNW_INSN_ADD_SP;
val = -sizeof(struct pt_regs);
if (rval == 0)
val += struct_offset(struct pt_regs, b0);
@@ -1313,11 +1324,11 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script)
break;
case UNW_WHERE_SPREL:
- opc = UNW_INSN_LOAD_SPREL;
+ opc = UNW_INSN_ADD_SP;
break;
case UNW_WHERE_PSPREL:
- opc = UNW_INSN_LOAD_PSPREL;
+ opc = UNW_INSN_ADD_PSP;
break;
default:
@@ -1330,6 +1341,18 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script)
script_emit(script, insn);
if (need_nat_info)
emit_nat_info(sr, i, script);
+
+ if (i == UNW_REG_PSP) {
+ /*
+ * info->psp must contain the _value_ of the previous
+ * sp, not it's save location. We get this by
+ * dereferencing the value we just stored in
+ * info->psp:
+ */
+ insn.opc = UNW_INSN_LOAD;
+ insn.dst = insn.val = unw.preg_index[UNW_REG_PSP];
+ script_emit(script, insn);
+ }
}
static inline struct unw_table_entry *
@@ -1378,7 +1401,7 @@ build_script (struct unw_frame_info *info)
memset(&sr, 0, sizeof(sr));
for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r)
r->when = UNW_WHEN_NEVER;
- sr.pr_val = info->pr_val;
+ sr.pr_val = info->pr;
script = script_new(ip);
if (!script) {
@@ -1447,8 +1470,8 @@ build_script (struct unw_frame_info *info)
}
#if UNW_DEBUG
- printk ("unwind: state record for func 0x%lx, t=%u:\n",
- table->segment_base + e->start_offset, sr.when_target);
+ printk("unwind: state record for func 0x%lx, t=%u:\n",
+ table->segment_base + e->start_offset, sr.when_target);
for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) {
if (r->where != UNW_WHERE_NONE || r->when != UNW_WHEN_NEVER) {
printk(" %s <- ", unw.preg_name[r - sr.curr.reg]);
@@ -1463,7 +1486,7 @@ build_script (struct unw_frame_info *info)
break;
default: printk("BADWHERE(%d)", r->where); break;
}
- printk ("\t\t%d\n", r->when);
+ printk("\t\t%d\n", r->when);
}
}
#endif
@@ -1472,13 +1495,17 @@ build_script (struct unw_frame_info *info)
/* translate state record into unwinder instructions: */
- if (sr.curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE
- && sr.when_target > sr.curr.reg[UNW_REG_PSP].when && sr.curr.reg[UNW_REG_PSP].val != 0)
- {
+ /*
+ * First, set psp if we're dealing with a fixed-size frame;
+ * subsequent instructions may depend on this value.
+ */
+ if (sr.when_target > sr.curr.reg[UNW_REG_PSP].when
+ && (sr.curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE)
+ && sr.curr.reg[UNW_REG_PSP].val != 0) {
/* new psp is sp plus frame size */
insn.opc = UNW_INSN_ADD;
- insn.dst = unw.preg_index[UNW_REG_PSP];
- insn.val = sr.curr.reg[UNW_REG_PSP].val;
+ insn.dst = struct_offset(struct unw_frame_info, psp)/8;
+ insn.val = sr.curr.reg[UNW_REG_PSP].val; /* frame size */
script_emit(script, insn);
}
@@ -1562,23 +1589,34 @@ run_script (struct unw_script *script, struct unw_frame_info *state)
val);
break;
- case UNW_INSN_LOAD_PSPREL:
+ case UNW_INSN_ADD_PSP:
s[dst] = state->psp + val;
break;
- case UNW_INSN_LOAD_SPREL:
+ case UNW_INSN_ADD_SP:
s[dst] = state->sp + val;
break;
- case UNW_INSN_SETNAT_PRI_UNAT:
- if (!state->pri_unat)
- state->pri_unat = &state->sw->caller_unat;
- s[dst+1] = ((*state->pri_unat - s[dst]) << 32) | UNW_NAT_PRI_UNAT;
+ case UNW_INSN_SETNAT_MEMSTK:
+ if (!state->pri_unat_loc)
+ state->pri_unat_loc = &state->sw->ar_unat;
+ /* register off. is a multiple of 8, so the least 3 bits (type) are 0 */
+ s[dst+1] = (*state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;
break;
case UNW_INSN_SETNAT_TYPE:
s[dst+1] = val;
break;
+
+ case UNW_INSN_LOAD:
+#if UNW_DEBUG
+ if ((s[val] & (my_cpu_data.unimpl_va_mask | 0x7)) || s[val] < TASK_SIZE) {
+ debug(1, "unwind: rejecting bad psp=0x%lx\n", s[val]);
+ break;
+ }
+#endif
+ s[dst] = *(unsigned long *) s[val];
+ break;
}
}
STAT(unw.stat.script.run_time += ia64_get_itc() - start);
@@ -1587,13 +1625,14 @@ run_script (struct unw_script *script, struct unw_frame_info *state)
lazy_init:
off = unw.sw_off[val];
s[val] = (unsigned long) state->sw + off;
- if (off >= struct_offset (struct unw_frame_info, r4)
- && off <= struct_offset (struct unw_frame_info, r7))
+ if (off >= struct_offset(struct switch_stack, r4)
+ && off <= struct_offset(struct switch_stack, r7))
/*
- * We're initializing a general register: init NaT info, too. Note that we
- * rely on the fact that call_unat is the first field in struct switch_stack:
+ * We're initializing a general register: init NaT info, too. Note that
+ * the offset is a multiple of 8 which gives us the 3 bits needed for
+ * the type field.
*/
- s[val+1] = (-off << 32) | UNW_NAT_PRI_UNAT;
+ s[val+1] = (struct_offset(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK;
goto redo;
}
@@ -1603,11 +1642,10 @@ find_save_locs (struct unw_frame_info *info)
int have_write_lock = 0;
struct unw_script *scr;
- if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || rgn_index(info->ip) != RGN_KERNEL)
- {
+ if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) {
/* don't let obviously bad addresses pollute the cache */
debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip);
- info->rp = 0;
+ info->rp_loc = 0;
return -1;
}
@@ -1648,12 +1686,12 @@ unw_unwind (struct unw_frame_info *info)
prev_bsp = info->bsp;
/* restore the ip */
- if (!info->rp) {
+ if (!info->rp_loc) {
debug(1, "unwind: failed to locate return link (ip=0x%lx)!\n", info->ip);
STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
return -1;
}
- ip = info->ip = *info->rp;
+ ip = info->ip = *info->rp_loc;
if (ip < GATE_ADDR + PAGE_SIZE) {
/*
* We don't have unwind info for the gate page, so we consider that part
@@ -1665,23 +1703,23 @@ unw_unwind (struct unw_frame_info *info)
}
/* restore the cfm: */
- if (!info->pfs) {
+ if (!info->pfs_loc) {
dprintk("unwind: failed to locate ar.pfs!\n");
STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
return -1;
}
- info->cfm = info->pfs;
+ info->cfm_loc = info->pfs_loc;
/* restore the bsp: */
- pr = info->pr_val;
+ pr = info->pr;
num_regs = 0;
if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) {
if ((pr & (1UL << pNonSys)) != 0)
- num_regs = *info->cfm & 0x7f; /* size of frame */
- info->pfs =
+ num_regs = *info->cfm_loc & 0x7f; /* size of frame */
+ info->pfs_loc =
(unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs));
} else
- num_regs = (*info->cfm >> 7) & 0x7f; /* size of locals */
+ num_regs = (*info->cfm_loc >> 7) & 0x7f; /* size of locals */
info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs);
if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) {
dprintk("unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n",
@@ -1694,7 +1732,7 @@ unw_unwind (struct unw_frame_info *info)
info->sp = info->psp;
if (info->sp < info->memstk.top || info->sp > info->memstk.limit) {
dprintk("unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n",
- info->sp, info->regstk.top, info->regstk.limit);
+ info->sp, info->memstk.top, info->memstk.limit);
STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
return -1;
}
@@ -1705,8 +1743,11 @@ unw_unwind (struct unw_frame_info *info)
return -1;
}
+ /* as we unwind, the saved ar.unat becomes the primary unat: */
+ info->pri_unat_loc = info->unat_loc;
+
/* finally, restore the predicates: */
- unw_get_pr(info, &info->pr_val);
+ unw_get_pr(info, &info->pr);
retval = find_save_locs(info);
STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
@@ -1773,11 +1814,11 @@ unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct
info->task = t;
info->sw = sw;
info->sp = info->psp = (unsigned long) (sw + 1) - 16;
- info->cfm = &sw->ar_pfs;
- sol = (*info->cfm >> 7) & 0x7f;
+ info->cfm_loc = &sw->ar_pfs;
+ sol = (*info->cfm_loc >> 7) & 0x7f;
info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
info->ip = sw->b0;
- info->pr_val = sw->pr;
+ info->pr = sw->pr;
find_save_locs(info);
STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
@@ -1808,7 +1849,7 @@ unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t)
info->regstk.top = top;
info->sw = sw;
info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
- info->cfm = &sw->ar_pfs;
+ info->cfm_loc = &sw->ar_pfs;
info->ip = sw->b0;
#endif
}
@@ -1845,7 +1886,7 @@ unw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs)
info->regstk.top = top;
info->sw = sw;
info->bsp = (unsigned long) ia64_rse_skip_regs(bsp, -sof);
- info->cfm = &regs->cr_ifs;
+ info->cfm_loc = &regs->cr_ifs;
info->ip = regs->cr_iip;
#endif
}
@@ -1881,7 +1922,7 @@ read_reg (struct unw_frame_info *info, int regnum, int *is_nat)
int
unw_unwind (struct unw_frame_info *info)
{
- unsigned long sol, cfm = *info->cfm;
+ unsigned long sol, cfm = *info->cfm_loc;
int is_nat;
sol = (cfm >> 7) & 0x7f; /* size of locals */
@@ -1903,7 +1944,7 @@ unw_unwind (struct unw_frame_info *info)
/* reject let obviously bad addresses */
return -1;
- info->cfm = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1);
+ info->cfm_loc = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1);
cfm = read_reg(info, sol - 1, &is_nat);
if (is_nat)
return -1;
@@ -2006,7 +2047,7 @@ unw_remove_unwind_table (void *handle)
if (prevt->next == table)
break;
if (!prevt) {
- dprintk("unwind: failed to find unwind table %p\n", table);
+ dprintk("unwind: failed to find unwind table %p\n", (void *) table);
spin_unlock_irqrestore(&unw.lock, flags);
return;
}
@@ -2070,9 +2111,9 @@ unw_init (void)
for (i = UNW_REG_F16, off = SW(F16); i <= UNW_REG_F31; ++i, off += 16)
unw.sw_off[unw.preg_index[i]] = off;
- unw.cache[0].coll_chain = -1;
- for (i = 1; i < UNW_CACHE_SIZE; ++i) {
- unw.cache[i].lru_chain = (i - 1);
+ for (i = 0; i < UNW_CACHE_SIZE; ++i) {
+ if (i > 0)
+ unw.cache[i].lru_chain = (i - 1);
unw.cache[i].coll_chain = -1;
unw.cache[i].lock = RW_LOCK_UNLOCKED;
}
diff --git a/arch/ia64/kernel/unwind_i.h b/arch/ia64/kernel/unwind_i.h
index fea655efd..383d65eff 100644
--- a/arch/ia64/kernel/unwind_i.h
+++ b/arch/ia64/kernel/unwind_i.h
@@ -115,21 +115,21 @@ struct unw_state_record {
enum unw_nat_type {
UNW_NAT_NONE, /* NaT not represented */
UNW_NAT_VAL, /* NaT represented by NaT value (fp reg) */
- UNW_NAT_PRI_UNAT, /* NaT value is in unat word at offset OFF */
- UNW_NAT_SCRATCH, /* NaT value is in scratch.pri_unat */
- UNW_NAT_STACKED /* NaT is in rnat */
+ UNW_NAT_MEMSTK, /* NaT value is in unat word at offset OFF */
+ UNW_NAT_REGSTK /* NaT is in rnat */
};
enum unw_insn_opcode {
UNW_INSN_ADD, /* s[dst] += val */
+ UNW_INSN_ADD_PSP, /* s[dst] = (s.psp + val) */
+ UNW_INSN_ADD_SP, /* s[dst] = (s.sp + val) */
UNW_INSN_MOVE, /* s[dst] = s[val] */
UNW_INSN_MOVE2, /* s[dst] = s[val]; s[dst+1] = s[val+1] */
UNW_INSN_MOVE_STACKED, /* s[dst] = ia64_rse_skip(*s.bsp, val) */
- UNW_INSN_LOAD_PSPREL, /* s[dst] = *(*s.psp + 8*val) */
- UNW_INSN_LOAD_SPREL, /* s[dst] = *(*s.sp + 8*val) */
- UNW_INSN_SETNAT_PRI_UNAT, /* s[dst+1].nat.type = PRI_UNAT;
+ UNW_INSN_SETNAT_MEMSTK, /* s[dst+1].nat.type = MEMSTK;
s[dst+1].nat.off = *s.pri_unat - s[dst] */
- UNW_INSN_SETNAT_TYPE /* s[dst+1].nat.type = val */
+ UNW_INSN_SETNAT_TYPE, /* s[dst+1].nat.type = val */
+ UNW_INSN_LOAD /* s[dst] = *s[val] */
};
struct unw_insn {