summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
commit86464aed71025541805e7b1515541aee89879e33 (patch)
treee01a457a4912a8553bc65524aa3125d51f29f810 /arch/ppc/kernel
parent88f99939ecc6a95a79614574cb7d95ffccfc3466 (diff)
Merge with Linux 2.2.1.
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile9
-rw-r--r--arch/ppc/kernel/apus_setup.c4
-rw-r--r--arch/ppc/kernel/head.S162
-rw-r--r--arch/ppc/kernel/idle.c21
-rw-r--r--arch/ppc/kernel/irq.c75
-rw-r--r--arch/ppc/kernel/mbx_setup.c28
-rw-r--r--arch/ppc/kernel/misc.S185
-rw-r--r--arch/ppc/kernel/pci.c33
-rw-r--r--arch/ppc/kernel/ppc_htab.c3
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c19
-rw-r--r--arch/ppc/kernel/prep_pci.c20
-rw-r--r--arch/ppc/kernel/prep_setup.c5
-rw-r--r--arch/ppc/kernel/process.c24
-rw-r--r--arch/ppc/kernel/ptrace.c4
-rw-r--r--arch/ppc/kernel/setup.c31
-rw-r--r--arch/ppc/kernel/smp.c60
-rw-r--r--arch/ppc/kernel/time.c53
-rw-r--r--arch/ppc/kernel/traps.c3
18 files changed, 573 insertions, 166 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 4846d5ebb..d047c2086 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -15,8 +15,7 @@ OX_OBJS := ppc_ksyms.o setup.o
O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \
- bitops.o ptrace.o align.o ppc_htab.o feature.o
-
+ bitops.o ptrace.o align.o ppc_htab.o
ifdef CONFIG_PCI
O_OBJS += pci.o
endif
@@ -33,15 +32,17 @@ else
ifeq ($(CONFIG_APUS),y)
O_OBJS += apus_setup.o prom.o openpic.o
else
+ifneq ($(CONFIG_MBX),y)
O_OBJS += prep_time.o pmac_time.o chrp_time.o \
pmac_setup.o pmac_support.o \
prep_pci.o pmac_pci.o chrp_pci.o \
- residual.o prom.o openpic.o
+ residual.o prom.o openpic.o feature.o
OX_OBJS += chrp_setup.o prep_setup.o
endif
endif
+endif
-ifdef SMP
+ifdef CONFIG_SMP
O_OBJS += smp.o
endif
diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c
index 93c2fe2d1..c3a81ad3e 100644
--- a/arch/ppc/kernel/apus_setup.c
+++ b/arch/ppc/kernel/apus_setup.c
@@ -329,9 +329,9 @@ unsigned long mm_ptov (unsigned long paddr)
int i;
for (i = 0; i < kmap_chunk_count;){
- unsigned long virt = kmap_chunks[i++];
- unsigned long size = kmap_chunks[i++];
unsigned long phys = kmap_chunks[i++];
+ unsigned long size = kmap_chunks[i++];
+ unsigned long virt = kmap_chunks[i++];
if (paddr >= phys
&& paddr < (phys + size)){
ret = virt + paddr - phys;
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 4c528beb8..d7b791387 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -1,7 +1,7 @@
/*
* arch/ppc/kernel/head.S
*
- * $Id: head.S,v 1.111 1998/11/10 01:10:32 paulus Exp $
+ * $Id: head.S,v 1.114 1998/12/28 10:28:45 paulus Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -148,6 +148,10 @@ _start:
* r4: virtual address of boot_infos_t
* r5: 0
*
+ * APUS
+ * r3: 'APUS'
+ * Linux/m68k style BootInfo structure at &_end.
+ *
* PREP
* This is jumped to on prep systems right after the kernel is relocated
* to its proper place in memory by the boot loader. The expected layout
@@ -528,9 +532,10 @@ HardwareInterrupt:
stw r3,(_CCR+4)(r21);
#endif
- addi r3,r1,STACK_FRAME_OVERHEAD;
- li r20,MSR_KERNEL;
- bl transfer_to_handler;
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ li r4,0
+ bl transfer_to_handler
.long do_IRQ;
.long int_return
@@ -1195,18 +1200,34 @@ stack_ovf:
* physical address of the hash table are known. These definitions
* of Hash_base and Hash_bits below are just an example.
*/
-/*
- * Note that the 603s won't come here, since the 603
- * loads tlb directly into the tlb from the linux tables, while
- * others (601, 604, etc.) call hash_page() to load entries from
- * the linux tables into the hash table. -- Cort
- */
Hash_base = 0x180000
Hash_bits = 12 /* e.g. 256kB hash table */
Hash_msk = (((1 << Hash_bits) - 1) * 64)
-
+
+ .globl hash_table_lock
+hash_table_lock:
+.long 0
+
.globl hash_page
hash_page:
+#ifdef __SMP__
+ lis r2,hash_table_lock@h
+ ori r2,r2,hash_table_lock@l
+ tophys(r2,r2,r6)
+ lis r6,100000000@h
+ mtctr r6
+ lwz r0,PROCESSOR-TSS(r5)
+ or r0,r0,r6
+10: lwarx r6,0,r2
+ cmpi 0,r6,0
+ bne- 12f
+ stwcx. r0,0,r2
+ beq+ 11f
+12: cmpw r6,r0
+ bdnzf 2,10b
+ tw 31,31,31
+11:
+#endif
/* Get PTE (linux-style) and check access */
lwz r5,PG_TABLES(r5)
tophys(r5,r5,r2) /* convert to phys addr */
@@ -1253,6 +1274,9 @@ hash_page_patch_A:
li r2,8 /* PTEs/group */
bne 10f /* no PTE: go look for an empty slot */
tlbie r3 /* invalidate TLB entry */
+#ifdef __SMP__
+ tlbsync
+#endif
/* Search the primary PTEG for a PTE whose 1st word matches r5 */
mtctr r2
@@ -1297,7 +1321,6 @@ hash_page_patch_C:
bdnzf 2,2b
beq+ found_empty
-#if 1
/*
* Choose an arbitrary slot in the primary PTEG to overwrite.
* Since both the primary and secondary PTEGs are full, and we
@@ -1313,26 +1336,6 @@ hash_page_patch_C:
andi. r2,r2,0x38
stw r2,next_slot@l(0)
add r3,r4,r2
-#else
- /* now, allow 2nd hash as well as 1st */
- lwz r2,next_slot@l(0)
- addi r2,r2,8
- andi. r2,r2,0x78
- stw r2,next_slot@l(0)
- cmpi 0,0,r2,0x38 /* if it's the 2nd hash */
- bgt second_evict
-first_evict:
- xori r5,r5,0x40 /* clear H bit again */
- add r3,r4,r2
- b 11f
-second_evict:
- .globl hash_page_patch_D
-hash_page_patch_D:
- xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
- xori r3,r3,0xffc0
- subi r2,r2,0x40
- addi r3,r3,r2
-#endif
11:
/* update counter of evicted pages */
lis r2,htab_evicts@h
@@ -1372,6 +1375,13 @@ found_slot:
addi r3,r3,1
stw r3,0(r2)
+#ifdef __SMP__
+ lis r2,hash_table_lock@ha
+ tophys(r2,r2,r6)
+ li r0,0
+ stw r0,hash_table_lock@l(r2)
+#endif
+
/* Return from the exception */
lwz r3,_CCR(r21)
lwz r4,_LINK(r21)
@@ -1392,6 +1402,12 @@ found_slot:
rfi
hash_page_out:
+#ifdef __SMP__
+ lis r2,hash_table_lock@ha
+ tophys(r2,r2,r6)
+ li r0,0
+ stw r0,hash_table_lock@l(r2)
+#endif
blr
next_slot:
.long 0
@@ -1709,6 +1725,9 @@ start_here:
2:
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
+#ifdef __SMP__
+ tlbsync
+#endif
#ifndef CONFIG_8xx
mtspr SDR1,r6
li r0,16 /* load up segment register values */
@@ -1980,16 +1999,13 @@ _GLOBAL(_switch)
/* FALL THROUGH into int_return */
#ifdef __SMP__
- /* drop scheduler_lock since we weren't called by schedule() */
+ /* call schedule_tail if this is the first time for a child process */
lwz r5,TSS_SMP_FORK_RET(r4)
cmpi 0,r5,0
beq+ int_return
li r3,0
- lis r5,scheduler_lock@ha
stw r3,TSS_SMP_FORK_RET(r4)
- stw r3,scheduler_lock@l+4(r5) /* owner_pc */
- stw r3,scheduler_lock@l+8(r5) /* owner_cpu */
- stw r3,scheduler_lock@l(r5) /* lock */
+ bl schedule_tail
#endif /* __SMP__ */
/*
@@ -2089,6 +2105,7 @@ _GLOBAL(fake_interrupt)
li r0,0x0fac
stw r0,TRAP(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
+ li r4,1
bl do_IRQ
addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
lwz r0,4(r1)
@@ -2206,8 +2223,31 @@ _GLOBAL(flush_hash_segments)
rlwinm r0,r0,16,27,31
lis r9,PVR_603_LIKE@h
rlwnm. r0,r9,r0,0,0
- bne 99f
+ beq+ 99f
+ tlbia
+ isync
+ blr
+99:
#endif /* NO_RELOAD_HTAB */
+#ifdef __SMP__
+ /* Note - we had better not do anything which could generate
+ a hash table miss while we have the hash table locked,
+ or we'll get a deadlock. -paulus */
+ mfmsr r10
+ sync
+ rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
+ mtmsr r0
+ SYNC
+ lis r9,hash_table_lock@h
+ ori r9,r9,hash_table_lock@l
+ lwz r8,PROCESSOR(r2)
+ oris r8,r8,8
+10: lwarx r6,0,r9
+ cmpi 0,r6,0
+ bne- 10b
+ stwcx. r8,0,r9
+ bne- 10b
+#endif
rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
oris r3,r3,0x8000 /* set V bit */
rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
@@ -2229,8 +2269,16 @@ _GLOBAL(flush_hash_segments)
stw r0,0(r5) /* invalidate entry */
2: bdnz 1b /* continue with loop */
sync
-99: tlbia
+ tlbia
isync
+#ifdef __SMP__
+ tlbsync
+ lis r3,hash_table_lock@ha
+ li r0,0
+ stw r0,hash_table_lock@l(r3)
+ mtmsr r10
+ SYNC
+#endif
blr
/*
@@ -2244,8 +2292,31 @@ _GLOBAL(flush_hash_page)
rlwinm r0,r0,16,27,31
lis r9,PVR_603_LIKE@h
rlwnm. r0,r9,r0,0,0
- bne 99f
+ beq+ 99f
+ tlbie r4 /* in hw tlb too */
+ isync
+ blr
+99:
#endif /* NO_RELOAD_HTAB */
+#ifdef __SMP__
+ /* Note - we had better not do anything which could generate
+ a hash table miss while we have the hash table locked,
+ or we'll get a deadlock. -paulus */
+ mfmsr r10
+ sync
+ rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
+ mtmsr r0
+ SYNC
+ lis r9,hash_table_lock@h
+ ori r9,r9,hash_table_lock@l
+ lwz r8,PROCESSOR(r2)
+ oris r8,r8,9
+10: lwarx r6,0,r9
+ cmpi 0,r6,0
+ bne- 10b
+ stwcx. r8,0,r9
+ bne- 10b
+#endif
rlwinm r3,r3,11,1,20 /* put context into vsid */
rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
oris r3,r3,0x8000 /* set V (valid) bit */
@@ -2278,10 +2349,19 @@ _GLOBAL(flush_hash_page)
3: li r0,0
stw r0,0(r7) /* invalidate entry */
4: sync
-99: tlbie r4 /* in hw tlb too */
+ tlbie r4 /* in hw tlb too */
isync
+#ifdef __SMP__
+ tlbsync
+ lis r3,hash_table_lock@h
+ li r0,0
+ stw r0,hash_table_lock@l(r3)
+ mtmsr r10
+ SYNC
+#endif
blr
#endif /* CONFIG_8xx */
+
/*
* This routine is just here to keep GCC happy - sigh...
*/
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index b6c338946..af163699b 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -1,5 +1,5 @@
/*
- * $Id: idle.c,v 1.56 1998/10/13 19:14:36 paulus Exp $
+ * $Id: idle.c,v 1.57 1998/12/28 10:28:46 paulus Exp $
*
* Idle daemon for PowerPC. Idle daemon will handle any action
* that needs to be taken when the system becomes idle.
@@ -41,26 +41,25 @@ unsigned long powersave_nap = 0;
int idled(void *unused)
{
- int ret = -EPERM;
-
+ /* endless loop with no priority at all */
+ current->priority = 0;
+ current->counter = -100;
for (;;)
{
__sti();
- /* endless loop with no priority at all */
- current->priority = 0;
- current->counter = 0;
-
check_pgt_cache();
if ( !current->need_resched && zero_paged_on ) zero_paged();
if ( !current->need_resched && htab_reclaim_on ) htab_reclaim();
if ( !current->need_resched ) power_save();
- run_task_queue(&tq_scheduler);
- schedule();
+
+#ifdef __SMP__
+ if (current->need_resched)
+#endif
+ schedule();
}
- ret = 0;
- return ret;
+ return 0;
}
#ifdef __SMP__
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index a180e5f0a..f4a7c7143 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -1,4 +1,6 @@
/*
+ * $Id: irq.c,v 1.91 1998/12/28 10:28:47 paulus Exp $
+ *
* arch/ppc/kernel/irq.c
*
* Derived from arch/i386/kernel/irq.c
@@ -6,6 +8,7 @@
* Adapted from arch/i386 by Gary Thomas
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
* Updated and modified by Cort Dougan (cort@cs.nmt.edu)
+ * Copyright (C) 1996 Cort Dougan
* Adapted for Power Macintosh by Paul Mackerras
* Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
* Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
@@ -309,14 +312,14 @@ static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
static void mbx_mask_irq(unsigned int irq_nr)
{
cached_irq_mask[0] &= ~(1 << (31-irq_nr));
- ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_simask =
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
cached_irq_mask[0];
}
static void mbx_unmask_irq(unsigned int irq_nr)
{
cached_irq_mask[0] |= (1 << (31-irq_nr));
- ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_simask =
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
cached_irq_mask[0];
}
#endif /* CONFIG_8xx */
@@ -454,7 +457,6 @@ static inline void wait_on_bh(void)
}
-#define MAXCOUNT 100000000
static inline void wait_on_irq(int cpu)
{
int count = MAXCOUNT;
@@ -507,7 +509,7 @@ static inline void wait_on_irq(int cpu)
void synchronize_bh(void)
{
if (atomic_read(&global_bh_count) && !in_interrupt())
- wait_on_bh();
+ wait_on_bh();
}
@@ -529,6 +531,8 @@ void synchronize_irq(void)
static inline void get_irqlock(int cpu)
{
+ unsigned int loops = MAXCOUNT;
+
if (test_and_set_bit(0,&global_irq_lock)) {
/* do we already hold the lock? */
if ((unsigned char) cpu == global_irq_holder)
@@ -536,12 +540,17 @@ static inline void get_irqlock(int cpu)
/* Uhhuh.. Somebody else got it. Wait.. */
do {
do {
-
+ if (loops-- == 0) {
+ printk("get_irqlock(%d) waiting, global_irq_holder=%d\n", cpu, global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
} while (test_bit(0,&global_irq_lock));
} while (test_and_set_bit(0,&global_irq_lock));
}
/*
- * We also to make sure that nobody else is running
+ * We also need to make sure that nobody else is running
* in an interrupt context.
*/
wait_on_irq(cpu);
@@ -637,7 +646,7 @@ void __global_restore_flags(unsigned long flags)
#endif /* __SMP__ */
-asmlinkage void do_IRQ(struct pt_regs *regs)
+asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
{
int irq;
unsigned long bits;
@@ -656,9 +665,14 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
#ifdef __SMP__
if ( cpu != 0 )
{
- if (!atomic_read(&n_lost_interrupts))
+ if (!isfake)
{
extern void smp_message_recv(void);
+#ifdef CONFIG_XMON
+ static int xmon_2nd;
+ if (xmon_2nd)
+ xmon(regs);
+#endif
smp_message_recv();
goto out;
}
@@ -666,6 +680,25 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
mess with the controller from the second cpu -- Cort */
goto out;
}
+
+ {
+ unsigned int loops = MAXCOUNT;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
#endif /* __SMP__ */
switch ( _machine )
@@ -799,9 +832,13 @@ apus_out:
}
if (irq < 0) {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- spurious_interrupts++;
+ /* we get here with Gatwick but the 'bogus' isn't correct in that case -- Cort */
+ if ( irq != second_irq )
+ {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ spurious_interrupts++;
+ }
goto out;
}
@@ -809,7 +846,7 @@ apus_out:
/* For MPC8xx, read the SIVEC register and shift the bits down
* to get the irq number.
*/
- bits = ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sivec;
+ bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
irq = bits >> 26;
#endif /* CONFIG_8xx */
mask_and_ack_irq(irq);
@@ -1089,17 +1126,6 @@ __initfunc(void init_IRQ(void))
*/
if ( _prep_type == _PREP_IBM )
irq_mode2 |= 0xa0;
- /*
- * Sound on the Powerstack reportedly needs to be edge triggered
- */
- if ( _prep_type == _PREP_Motorola )
- {
- irq_mode2 &= ~0x04L;
- irq_mode2 = 0xca;
- outb( irq_mode1 , 0x4d0 );
- outb( irq_mode2 , 0x4d1 );
- }
-
}
break;
#ifdef CONFIG_APUS
@@ -1116,8 +1142,7 @@ __initfunc(void init_IRQ(void))
/* This routine will fix some missing interrupt values in the device tree
* on the gatwick mac-io controller used by some PowerBooks
*/
-__pmac
-static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
{
struct device_node *node;
static struct interrupt_info int_pool[4];
diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c
index 9d26e27d1..90647dcd9 100644
--- a/arch/ppc/kernel/mbx_setup.c
+++ b/arch/ppc/kernel/mbx_setup.c
@@ -1,4 +1,6 @@
/*
+ * $Id: mbx_setup.c,v 1.5 1998/12/29 18:55:07 cort Exp $
+ *
* linux/arch/ppc/kernel/setup.c
*
* Copyright (C) 1995 Linus Torvalds
@@ -51,17 +53,27 @@ extern int rd_image_start; /* starting block # of image */
extern char saved_command_line[256];
extern unsigned long find_available_memory(void);
-extern void mbx_cpm_reset(uint);
-
+extern void m8xx_cpm_reset(uint);
-void mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+/* this really does make things cleaner -- Cort */
+void __init powermac_init(void)
{
+}
- *p = 0;
- *irq = 0;
+void __init adbdev_init(void)
+{
+}
- if (base != 0) /* Only map the first ATA flash drive */
- return;
+void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = base + 0x206;
+ if (irq != NULL)
+ *irq = 0;
#ifdef ATA_FLASH
base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
for (i = 0; i < 8; ++i)
@@ -88,7 +100,7 @@ mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
/* Reset the Communication Processor Module.
*/
- mbx_cpm_reset(cpm_page);
+ m8xx_cpm_reset(cpm_page);
#ifdef notdef
ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index f13508d96..e4589b1e0 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -383,6 +383,177 @@ _GLOBAL(_set_THRM3)
mtspr THRM3,r3
blr
+_GLOBAL(_get_PVR)
+ mfspr r3,PVR
+ blr
+/*
+ L2CR functions
+ Copyright © 1997-1998 by PowerLogix R & D, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+ Thur, Dec. 12, 1998.
+ - First public release, contributed by PowerLogix.
+
+ Author: Terry Greeniaus (tgree@phys.ualberta.ca)
+ Please e-mail updates to this file to me, thanks!
+*/
+
+_GLOBAL(_set_L2CR)
+ /* Usage:
+
+ When setting the L2CR register, you must do a few special things. If you are enabling the
+ cache, you must perform a global invalidate. If you are disabling the cache, you must
+ flush the cache contents first. This routine takes care of doing these things. When first
+ enabling the cache, make sure you pass in the L2CR you want, as well as passing in the
+ global invalidate bit set. A global invalidate will only be performed if the L2I bit is set
+ in applyThis. When enabling the cache, you should also set the L2E bit in applyThis. If you
+ want to modify the L2CR contents after the cache has been enabled, the recommended
+ procedure is to first call __setL2CR(0) to disable the cache and then call it again with
+ the new values for L2CR. Examples:
+
+ _setL2CR(0) - disables the cache
+ _setL2CR(0xB3A04000) - enables my G3 upgrade card:
+ - L2E set to turn on the cache
+ - L2SIZ set to 1MB
+ - L2CLK set to 1:1
+ - L2RAM set to pipelined syncronous late-write
+ - L2I set to perform a global invalidation
+ - L2OH set to 0.5 nS
+ - L2DF set because this upgrade card requires it
+
+ A similar call should work for your card. You need to know the correct setting for your
+ card and then place them in the fields I have outlined above. Other fields support optional
+ features, such as L2DO which caches only data, or L2TS which causes cache pushes from
+ the L1 cache to go to the L2 cache instead of to main memory.
+ */
+
+ /* Make sure this is a 750 chip */
+ mfspr r4,PVR
+ rlwinm r4,r4,16,16,31
+ cmplwi r4,0x0008
+ beq thisIs750
+ li r3,-1
+ blr
+
+thisIs750:
+ /* Get the current enable bit of the L2CR into r4 */
+ mfspr r4,L2CR
+ rlwinm r4,r4,0,0,0
+
+ /* See if we want to perform a global inval this time. */
+ rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */
+ rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */
+ rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */
+ rlwinm r3,r3,0,1,31 /* Turn off the enable bit */
+ or r3,r3,r4 /* Keep the enable bit the same as it was for now. */
+ bne dontDisableCache /* Only disable the cache if L2CRApply has the enable bit off */
+
+disableCache:
+ /* Disable the cache. First, we turn off data relocation. */
+ mfmsr r7
+ rlwinm r4,r7,0,28,26 /* Turn off DR bit */
+ rlwinm r4,r4,0,17,15 /* Turn off EE bit - an external exception while we are flushing
+ the cache is fatal (comment this line and see!) */
+ sync
+ mtmsr r4
+ sync
+
+ /*
+ Now, read the first 2MB of memory to put new data in the cache.
+ (Actually we only need the size of the L2 cache plus
+ the size of the L1 cache, but 2MB will cover everything just to be safe).
+ */
+ lis r4,0x0001
+ mtctr r4
+ li r4,0
+loadLoop:
+ lwzx r0,r0,r4
+ addi r4,r4,0x0020 /* Go to start of next cache line */
+ bdnz loadLoop
+
+ /* Now, flush the first 2MB of memory */
+ lis r4,0x0001
+ mtctr r4
+ li r4,0
+ sync
+flushLoop:
+ dcbf r0,r4
+ addi r4,r4,0x0020 /* Go to start of next cache line */
+ bdnz flushLoop
+
+ /* Turn off the L2CR enable bit. */
+ rlwinm r3,r3,0,1,31
+
+ /* Reenable data relocation. */
+ sync
+ mtmsr r7
+ sync
+
+dontDisableCache:
+ /* Set up the L2CR configuration bits */
+ sync
+ mtspr L2CR,r3
+ sync
+ cmplwi r6,0
+ beq noInval
+
+ /* Perform a global invalidation */
+ oris r3,r3,0x0020
+ sync
+ mtspr 1017,r3
+ sync
+invalCompleteLoop: /* Wait for the invalidation to complete */
+ mfspr r3,1017
+ rlwinm. r4,r3,0,31,31
+ bne invalCompleteLoop
+
+ rlwinm r3,r3,0,11,9; /* Turn off the L2I bit */
+ sync
+ mtspr L2CR,r3
+ sync
+
+noInval:
+ /* See if we need to enable the cache */
+ cmplwi r5,0
+ beqlr
+
+enableCache:
+ /* Enable the cache */
+ oris r3,r3,0x8000
+ mtspr L2CR,r3
+ sync
+ blr
+
+_GLOBAL(_get_L2CR)
+ /* Make sure this is a 750 chip */
+ mfspr r3,PVR
+ rlwinm r3,r3,16,16,31
+ cmplwi r3,0x0008
+ li r3,0
+ bnelr
+
+ /* Return the L2CR contents */
+ mfspr r3,L2CR
+ blr
+
+/* --- End of PowerLogix code ---
+ */
+
+/*
_GLOBAL(_get_L2CR)
mfspr r3,L2CR
blr
@@ -391,9 +562,7 @@ _GLOBAL(_set_L2CR)
mtspr L2CR,r3
blr
-_GLOBAL(_get_PVR)
- mfspr r3,PVR
- blr
+*/
/*
* These are used in the alignment trap handler when emulating
@@ -441,16 +610,6 @@ _GLOBAL(__kernel_thread)
bnelr /* return if parent */
mtlr r4 /* fn addr in lr */
mr r3,r5 /* load arg and call fn */
-#if 0/*def __SMP__*/
- /* drop scheduler_lock since schedule() called us */
- lis r4,scheduler_lock@ha
- li r5,0
- stw r5,scheduler_lock@l+4(r4) /* owner_pc */
- stw r5,scheduler_lock@l+8(r4) /* owner_cpu */
- stw r5,scheduler_lock@l(r4)
- sync
- isync
-#endif /* __SMP__ */
blrl
li r0,__NR_exit /* exit after child exits */
li r3,0
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 359446f4f..1dfa3a6c8 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: pci.c,v 1.39 1998/10/13 20:59:04 cort Exp $
+ * $Id: pci.c,v 1.43 1998/12/29 18:55:11 cort Exp $
* Common pmac/prep/chrp pci routines. -- Cort
*/
@@ -123,8 +123,8 @@ __initfunc(void pcibios_init(void))
__initfunc(void
setup_pci_ptrs(void))
{
- PPC_DEVICE *hostbridge;
#ifndef CONFIG_MBX
+ PPC_DEVICE *hostbridge;
switch (_machine) {
case _MACH_prep:
hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
@@ -188,13 +188,8 @@ __initfunc(void pcibios_fixup(void))
extern struct bridge_data **bridges;
extern unsigned char *Motherboard_map;
extern unsigned char *Motherboard_routes;
-
- /*
- * FIXME: This is broken: We should not assign IRQ's to IRQless
- * devices (look at PCI_INTERRUPT_PIN) and we also should
- * honor the existence of multi-function devices where
- * different functions have different interrupt pins. [mj]
- */
+ unsigned char i;
+#ifndef CONFIG_MBX
switch (_machine )
{
case _MACH_prep:
@@ -208,6 +203,21 @@ __initfunc(void pcibios_fixup(void))
*/
unsigned char d = PCI_SLOT(dev->devfn);
dev->irq = Motherboard_routes[Motherboard_map[d]];
+ for ( i = 0 ; i <= 5 ; i++ )
+ {
+ if ( dev->base_address[i] > 0x10000000 )
+ {
+ printk("Relocating PCI address %x -> %x\n",
+ dev->base_address[i],
+ (dev->base_address[i] & 0x00FFFFFF)
+ | 0x01000000);
+ dev->base_address[i] =
+ (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
+ pci_write_config_dword(dev,
+ PCI_BASE_ADDRESS_0+(i*0x4),
+ dev->base_address[i] );
+ }
+ }
#if 0
/*
* If we have residual data and if it knows about this
@@ -255,6 +265,11 @@ __initfunc(void pcibios_fixup(void))
}
break;
}
+#else /* CONFIG_MBX */
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ }
+#endif /* CONFIG_MBX */
}
__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index 3aa0534ea..30123c076 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -1,5 +1,5 @@
/*
- * $Id: ppc_htab.c,v 1.25 1998/08/26 10:28:26 davem Exp $
+ * $Id: ppc_htab.c,v 1.26 1998/12/10 00:24:23 cort Exp $
*
* PowerPC hash table management proc entry. Will show information
* about the current hash table and will allow changes to it.
@@ -569,6 +569,7 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
break;
buffer += len;
left -= len;
+ _set_L2CR(0);
_set_L2CR(val);
while ( _get_L2CR() & 0x1 )
/* wait for invalidate to finish */;
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index ea5f6db0d..1b7753dd0 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -25,6 +25,7 @@
#include <asm/pci-bridge.h>
#include <asm/irq.h>
#include <asm/feature.h>
+#include <asm/spinlock.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -32,7 +33,7 @@
extern void transfer_to_handler(void);
extern void int_return(void);
extern void syscall_trace(void);
-extern void do_IRQ(struct pt_regs *regs);
+extern void do_IRQ(struct pt_regs *regs, int isfake);
extern void MachineCheckException(struct pt_regs *regs);
extern void AlignmentException(struct pt_regs *regs);
extern void ProgramCheckException(struct pt_regs *regs);
@@ -156,6 +157,19 @@ EXPORT_SYMBOL(_get_PVR);
EXPORT_SYMBOL(giveup_fpu);
EXPORT_SYMBOL(flush_icache_range);
EXPORT_SYMBOL(xchg_u32);
+#ifdef __SMP__
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(_spin_lock);
+EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(spin_trylock);
+EXPORT_SYMBOL(_read_lock);
+EXPORT_SYMBOL(_read_unlock);
+EXPORT_SYMBOL(_write_lock);
+EXPORT_SYMBOL(_write_unlock);
+#endif
#ifndef CONFIG_MACH_SPECIFIC
EXPORT_SYMBOL(_machine);
@@ -180,12 +194,15 @@ EXPORT_SYMBOL(find_compatible_devices);
EXPORT_SYMBOL(find_path_device);
EXPORT_SYMBOL(find_phandle);
EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(device_is_compatible);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(feature_set);
EXPORT_SYMBOL(feature_clear);
EXPORT_SYMBOL(feature_test);
+#ifdef CONFIG_SCSI
EXPORT_SYMBOL(note_scsi_host);
+#endif
EXPORT_SYMBOL(kd_mksound);
#ifdef CONFIG_PMAC
EXPORT_SYMBOL(nvram_read_byte);
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
index b7d94d208..b48f7a1fc 100644
--- a/arch/ppc/kernel/prep_pci.c
+++ b/arch/ppc/kernel/prep_pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: prep_pci.c,v 1.23 1998/10/21 10:52:24 cort Exp $
+ * $Id: prep_pci.c,v 1.24 1998/12/10 02:39:51 cort Exp $
* PReP pci functions.
* Originally by Gary Thomas
* rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -107,7 +107,7 @@ static char Omaha_pci_IRQ_routes[] __prepdata =
};
/* Motorola PowerStack */
-static char Blackhawk_pci_IRQ_map[16] __prepdata =
+static char Blackhawk_pci_IRQ_map[19] __prepdata =
{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
@@ -125,6 +125,9 @@ static char Blackhawk_pci_IRQ_map[16] __prepdata =
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
+ 1, /* Slot P7 */
+ 2, /* Slot P6 */
+ 3, /* Slot P5 */
};
static char Blackhawk_pci_IRQ_routes[] __prepdata =
@@ -132,7 +135,7 @@ static char Blackhawk_pci_IRQ_routes[] __prepdata =
0, /* Line 0 - Unused */
9, /* Line 1 */
11, /* Line 2 */
- 14, /* Line 3 */
+ 15, /* Line 3 */
15 /* Line 4 */
};
@@ -226,6 +229,7 @@ static char ibm8xx_pci_IRQ_map[23] __prepdata = {
0, /* Slot 21 - unused */
2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
};
+
static char ibm8xx_pci_IRQ_routes[] __prepdata = {
0, /* Line 0 - unused */
13, /* Line 1 */
@@ -440,6 +444,8 @@ __initfunc(unsigned long route_pci_interrupts(void))
if ( _prep_type == _PREP_Motorola)
{
+ unsigned short irq_mode;
+
switch (inb(0x800) & 0xF0)
{
case 0x10: /* MVME16xx */
@@ -474,6 +480,14 @@ __initfunc(unsigned long route_pci_interrupts(void))
Motherboard_routes = Blackhawk_pci_IRQ_routes;
break;
}
+ /* AJF adjust level/edge control according to routes */
+ irq_mode = 0;
+ for (i = 1; i <= 4; i++)
+ {
+ irq_mode |= ( 1 << Motherboard_routes[i] );
+ }
+ outb( irq_mode & 0xff, 0x4d0 );
+ outb( (irq_mode >> 8) & 0xff, 0x4d1 );
} else if ( _prep_type == _PREP_IBM )
{
unsigned char pl_id;
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index e596f9ea5..72752e11f 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -189,11 +189,6 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
/* Enable L2. Assume we don't need to flush -- Cort*/
*(unsigned char *)(0x8000081c) = *(unsigned char *)(0x8000081c)|3;
- /* make the serial port the console */
- /* strcat(cmd_line,"console=ttyS0,9600n8"); */
- /* use the normal console but send output to the serial port, too */
- /*strcat(cmd_line,"console=tty0 console=ttyS0,9600n8");*/
- sprintf(cmd_line,"%s console=tty0 console=ttyS0,9600n8", cmd_line);
printk("Boot arguments: %s\n", cmd_line);
#ifdef CONFIG_SOUND_CS4232
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 5ea55cee9..ebe64a429 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -1,4 +1,6 @@
/*
+ * $Id: process.c,v 1.70 1999/01/07 16:28:59 cort Exp $
+ *
* linux/arch/ppc/kernel/process.c
*
* Derived from "arch/i386/kernel/process.c"
@@ -180,13 +182,6 @@ switch_to(struct task_struct *prev, struct task_struct *new)
if ( prev->tss.regs->msr & MSR_FP )
smp_giveup_fpu(prev);
- /* be noisy about processor changes for debugging -- Cort */
- if ( (new->last_processor != NO_PROC_ID) &&
- (new->last_processor != new->processor) )
- printk("switch_to(): changing cpu's %d -> %d %s/%d\n",
- new->last_processor,new->processor,
- new->comm,new->pid);
-
prev->last_processor = prev->processor;
current_set[smp_processor_id()] = new;
#endif /* __SMP__ */
@@ -236,6 +231,19 @@ void show_regs(struct pt_regs * regs)
out:
}
+void instruction_dump (unsigned long *pc)
+{
+ int i;
+
+ if((((unsigned long) pc) & 3))
+ return;
+
+ printk("Instruction DUMP:");
+ for(i = -3; i < 6; i++)
+ printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+ printk("\n");
+}
+
void exit_thread(void)
{
if (last_task_used_math == current)
@@ -450,6 +458,7 @@ print_backtrace(unsigned long *sp)
printk("\n");
}
+#if 0
/*
* Low level print for debugging - Cort
*/
@@ -537,3 +546,4 @@ __initfunc(void ll_puts(const char *s))
orig_x = x;
orig_y = y;
}
+#endif
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index 62b2b03af..e2c6b13a0 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -362,7 +362,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKDATA: {
unsigned long tmp;
+ down(&child->mm->mmap_sem);
ret = read_long(child, addr, &tmp);
+ up(&child->mm->mmap_sem);
if (ret < 0)
goto out;
ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
@@ -410,7 +412,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
/* If I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
+ down(&child->mm->mmap_sem);
ret = write_long(child,addr,data);
+ up(&child->mm->mmap_sem);
goto out;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 706c1dde2..50cd70889 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,5 +1,5 @@
/*
- * $Id: setup.c,v 1.117 1998/11/09 19:55:53 geert Exp $
+ * $Id: setup.c,v 1.122 1998/12/31 20:51:19 cort Exp $
* Common prep/pmac/chrp boot and setup code.
*/
@@ -35,7 +35,7 @@ extern unsigned long m68k_machtype;
extern int parse_bootinfo(const struct bi_record *);
extern char _end[];
#ifdef CONFIG_APUS
-struct mem_info ramdisk;
+extern struct mem_info ramdisk;
unsigned long isa_io_base;
unsigned long isa_mem_base;
unsigned long pci_dram_offset;
@@ -259,6 +259,9 @@ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
break;
}
#endif
+#if defined(CONFIG_MBX)
+ mbx_ide_init_hwif_ports(p,base,irq);
+#endif
}
EXPORT_SYMBOL(ide_init_hwif_ports);
#endif
@@ -464,9 +467,9 @@ int get_cpuinfo(char *buffer)
* Find out what kind of machine we're on and save any data we need
* from the early boot process (devtree is copied on pmac by prom_init() )
*/
-__initfunc(unsigned long
+unsigned long __init
identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7))
+ unsigned long r6, unsigned long r7)
{
extern void setup_pci_ptrs(void);
@@ -491,6 +494,9 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
char *model;
have_of = 1;
+
+ /* prom_init has already been called from __start */
+ finish_device_tree();
/* ask the OF info if we're a chrp or pmac */
model = get_property(find_path_device("/"), "device_type", NULL);
if ( model && !strncmp("chrp",model,4) )
@@ -510,8 +516,10 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
if ( have_of )
{
+#ifdef CONFIG_MACH_SPECIFIC
/* prom_init has already been called from __start */
finish_device_tree();
+#endif /* CONFIG_MACH_SPECIFIC */
/*
* If we were booted via quik, r3 points to the physical
* address of the command-line parameters.
@@ -665,7 +673,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
#else /* CONFIG_MBX */
if ( r3 )
- memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+ memcpy( (void *)res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
#ifdef CONFIG_PCI
setup_pci_ptrs();
@@ -693,9 +701,22 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
extern int __map_without_bats;
__map_without_bats = 1;
}
+
return 0;
}
+/* Checks "l2cr=xxxx" command-line option */
+void ppc_setup_l2cr(char *str, int *ints)
+{
+ if ( (_get_PVR() >> 16) == 8)
+ {
+ unsigned long val = simple_strtoul(str, NULL, 0);
+ printk(KERN_INFO "l2cr set to %lx\n", val);
+ _set_L2CR(0);
+ _set_L2CR(val);
+ }
+}
+
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 75445925f..ba505e133 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -1,5 +1,5 @@
/*
- * $Id: smp.c,v 1.36 1998/10/08 01:17:48 cort Exp $
+ * $Id: smp.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
*
* Smp support for ppc.
*
@@ -43,6 +43,7 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
int first_cpu_booted = 0;
+cycles_t cacheflush_time;
/* all cpu mappings are 1-1 -- Cort */
int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
@@ -144,7 +145,14 @@ void smp_message_recv(void)
void smp_send_reschedule(int cpu)
{
- smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);
+ /* This is only used if `cpu' is running an idle task,
+ so it will reschedule itself anyway... */
+ /*smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);*/
+}
+
+void smp_send_stop(void)
+{
+ smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
}
spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
@@ -152,7 +160,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
if ( _machine != _MACH_Pmac )
return;
- /*printk("SMP %d: sending smp message\n", current->processor);*/
+printk("SMP %d: sending smp message %x\n", current->processor, msg);
if (smp_processor_id() ) printk("pass from cpu 1\n");
spin_lock(&mesg_pass_lock);
#define OTHER (~smp_processor_id() & 1)
@@ -179,17 +187,18 @@ if (smp_processor_id() ) printk("pass from cpu 1\n");
spin_unlock(&mesg_pass_lock);
}
-__initfunc(void smp_boot_cpus(void))
+void __init smp_boot_cpus(void)
{
extern struct task_struct *current_set[NR_CPUS];
extern void __secondary_start(void);
int i;
struct task_struct *p;
-
+ unsigned long a;
+
printk("Entering SMP Mode...\n");
first_cpu_booted = 1;
- dcbf(&first_cpu_booted);
+ /*dcbf(&first_cpu_booted);*/
for (i = 0; i < NR_CPUS; i++) {
prof_counter[i] = 1;
@@ -200,7 +209,13 @@ __initfunc(void smp_boot_cpus(void))
smp_store_cpu_info(0);
active_kernel_processor = 0;
current->processor = 0;
-
+
+ /*
+ * XXX very rough, assumes 20 bus cycles to read a cache line,
+ * timebase increments every 4 bus cycles, 32kB L1 data cache.
+ */
+ cacheflush_time = 5 * 1024;
+
if ( _machine != _MACH_Pmac )
{
printk("SMP not supported on this machine.\n");
@@ -213,10 +228,16 @@ __initfunc(void smp_boot_cpus(void))
if ( !p )
panic("No idle task for secondary processor\n");
p->processor = 1;
+ p->has_cpu = 1;
current_set[1] = p;
/* need to flush here since secondary bat's aren't setup */
- dcbf((void *)&current_set[1]);
+ /* XXX ??? */
+ for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+ asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+ asm volatile("sync");
+
+ /*dcbf((void *)&current_set[1]);*/
/* setup entry point of secondary processor */
*(volatile unsigned long *)(0xf2800000) =
(unsigned long)__secondary_start-KERNELBASE;
@@ -238,7 +259,7 @@ __initfunc(void smp_boot_cpus(void))
if(cpu_callin_map[1]) {
printk("Processor %d found.\n", smp_num_cpus);
smp_num_cpus++;
-#if 0 /* this sync's the decr's, but we don't want this now -- Cort */
+#if 1 /* this sync's the decr's, but we don't want this now -- Cort */
set_dec(decrementer_count);
#endif
} else {
@@ -251,19 +272,17 @@ __initfunc(void smp_boot_cpus(void))
smp_message_pass(1,0xf0f0, 0, 0);
}
-__initfunc(void smp_commence(void))
+void __init smp_commence(void)
{
printk("SMP %d: smp_commence()\n",current->processor);
/*
* Lets the callin's below out of their loop.
*/
- local_flush_tlb_all();
smp_commenced = 1;
- local_flush_tlb_all();
}
/* intel needs this */
-__initfunc(void initialize_secondary(void))
+void __init initialize_secondary(void)
{
}
@@ -275,33 +294,34 @@ asmlinkage int __init start_secondary(void *unused)
return cpu_idle(NULL);
}
-__initfunc(void smp_callin(void))
+void __init smp_callin(void)
{
printk("SMP %d: smp_callin()\n",current->processor);
smp_store_cpu_info(current->processor);
set_dec(decrementer_count);
-
+#if 0
current->mm->mmap->vm_page_prot = PAGE_SHARED;
current->mm->mmap->vm_start = PAGE_OFFSET;
current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
-
- cpu_callin_map[current->processor] = current->processor;
+#endif
+ cpu_callin_map[current->processor] = 1;
while(!smp_commenced)
barrier();
__sti();
+ printk("SMP %d: smp_callin done\n", current->processor);
}
-__initfunc(void smp_setup(char *str, int *ints))
+void __init smp_setup(char *str, int *ints)
{
printk("SMP %d: smp_setup()\n",current->processor);
}
-__initfunc(int setup_profiling_timer(unsigned int multiplier))
+int __init setup_profiling_timer(unsigned int multiplier)
{
return 0;
}
-__initfunc(void smp_store_cpu_info(int id))
+void __init smp_store_cpu_info(int id)
{
struct cpuinfo_PPC *c = &cpu_data[id];
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 8bada0e69..32f60a236 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -1,5 +1,5 @@
/*
- * $Id: time.c,v 1.36 1998/10/10 12:16:08 geert Exp $
+ * $Id: time.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
* Common time routines among all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -17,6 +17,9 @@
* This is then divided by 4, providing a 8192 Hz clock into the PIT.
* Since it is not possible to get a nice 100 Hz clock out of this, without
* creating a software PLL, I have set HZ to 128. -- Dan
+ *
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h>
@@ -78,6 +81,26 @@ void timer_interrupt(struct pt_regs * regs)
unsigned dcache_locked = unlock_dcache();
hardirq_enter(cpu);
+#ifdef __SMP__
+ {
+ unsigned int loops = 100000000;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
+#endif /* __SMP__ */
while ((dval = get_dec()) < 0) {
/*
@@ -133,9 +156,9 @@ void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
static int
mbx_set_rtc_time(unsigned long time)
{
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+ ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+ ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
+ ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
return(0);
}
#endif /* CONFIG_MBX */
@@ -150,12 +173,15 @@ void do_gettimeofday(struct timeval *tv)
save_flags(flags);
cli();
*tv = xtime;
+ /* XXX we don't seem to have the decrementers synced properly yet */
+#ifndef __SMP__
tv->tv_usec += (decrementer_count - get_dec())
* count_period_num / count_period_den;
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
+#endif
restore_flags(flags);
}
@@ -172,6 +198,11 @@ void do_settimeofday(struct timeval *tv)
xtime.tv_sec = tv->tv_sec;
xtime.tv_usec = tv->tv_usec - frac_tick;
set_dec(frac_tick * count_period_den / count_period_num);
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_state = TIME_ERROR; /* p. 24, (a) */
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
restore_flags(flags);
}
@@ -227,13 +258,13 @@ __initfunc(void time_init(void))
* modify these registers we have to write the key value to
* the key location associated with the register.
*/
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+ ((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+ ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
/* Disable the RTC one second and alarm interrupts.
*/
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
+ ((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
~(RTCSC_SIE | RTCSC_ALE);
/* Enabling the decrementer also enables the timebase interrupts
@@ -241,7 +272,7 @@ __initfunc(void time_init(void))
* we have to enable the timebase). The decrementer interrupt
* is wired into the vector table, nothing to do here for that.
*/
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
+ ((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
((mk_int_int_mask(DEC_INTERRUPT) << 8) |
(TBSCR_TBF | TBSCR_TBE));
if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
@@ -249,7 +280,7 @@ __initfunc(void time_init(void))
/* Get time from the RTC.
*/
- xtime.tv_sec = ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
+ xtime.tv_sec = ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc;
xtime.tv_usec = 0;
#endif /* CONFIG_MBX */
@@ -343,10 +374,10 @@ __initfunc(void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *
*/
__initfunc(void mbx_calibrate_decr(void))
{
- bd_t *binfo = (bd_t *)&res;
+ bd_t *binfo = (bd_t *)res;
int freq, fp, divisor;
- if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
+ if ((((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
printk("WARNING: Wrong decrementer source clock.\n");
/* The manual says the frequency is in Hz, but it is really
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index af02252f9..fa5184af2 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -79,6 +79,7 @@ _exception(int signr, struct pt_regs *regs)
debugger(regs);
#endif
print_backtrace((unsigned long *)regs->gpr[1]);
+ instruction_dump((unsigned long *)regs->nip);
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
force_sig(signr, current);
@@ -126,6 +127,7 @@ MachineCheckException(struct pt_regs *regs)
debugger(regs);
#endif
print_backtrace((unsigned long *)regs->gpr[1]);
+ instruction_dump((unsigned long *)regs->nip);
panic("machine check");
}
_exception(SIGSEGV, regs);
@@ -219,6 +221,7 @@ StackOverflow(struct pt_regs *regs)
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
+ instruction_dump((unsigned long *)regs->nip);
panic("kernel stack overflow");
}