summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile7
-rw-r--r--arch/ppc/kernel/entry.S50
-rw-r--r--arch/ppc/kernel/gemini_pci.c6
-rw-r--r--arch/ppc/kernel/gemini_setup.c4
-rw-r--r--arch/ppc/kernel/head.S8
-rw-r--r--arch/ppc/kernel/head_4xx.S183
-rw-r--r--arch/ppc/kernel/head_8xx.S36
-rw-r--r--arch/ppc/kernel/irq.c6
-rw-r--r--arch/ppc/kernel/oak_setup.c237
-rw-r--r--arch/ppc/kernel/oak_setup.h26
-rw-r--r--arch/ppc/kernel/open_pic.c11
-rw-r--r--arch/ppc/kernel/open_pic.h1
-rw-r--r--arch/ppc/kernel/pci.c80
-rw-r--r--arch/ppc/kernel/pmac_nvram.c1
-rw-r--r--arch/ppc/kernel/pmac_time.c1
-rw-r--r--arch/ppc/kernel/ppc4xx_pic.c204
-rw-r--r--arch/ppc/kernel/ppc4xx_pic.h36
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c3
-rw-r--r--arch/ppc/kernel/process.c8
-rw-r--r--arch/ppc/kernel/setup.c139
-rw-r--r--arch/ppc/kernel/smp.c2
-rw-r--r--arch/ppc/kernel/time.c3
-rw-r--r--arch/ppc/kernel/time.h18
-rw-r--r--arch/ppc/kernel/traps.c1
24 files changed, 809 insertions, 262 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index a41473fa5..7aaacfadb 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -57,8 +57,11 @@ ifdef CONFIG_SMP
O_OBJS += smp.o
endif
-ifeq ($(CONFIG_OAK),y)
- O_OBJS += oak_setup.o
+ifeq ($(CONFIG_4xx),y)
+ O_OBJS += ppc4xx_pic.o
+ ifeq ($(CONFIG_OAK),y)
+ O_OBJS += oak_setup.o
+ endif
endif
ifeq ($(CONFIG_8xx),y)
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 5ed04344e..cb92163d6 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -265,37 +265,29 @@ _GLOBAL(_switch)
SYNC
rfi
-/*
- * ret_from_int():
- *
- * Return from an interrupt (external interrupt and
- * decrementer). This checks the first argument so
- * we know if rtl_intercept wants us to check for
- * a bottom half, signals and so on (normal return) or
- * we're returning from a real-time interrupt or have
- * interrupts soft disabled so we cannot enter Linux.
- * -- Cort
- */
- .globl ret_from_int
-ret_from_int:
- cmpi 0,r3,0
- beq 10f
- /* we're allowed to do signal/bh checks */
- b ret_from_syscall
#ifdef __SMP__
.globl ret_from_smpfork
ret_from_smpfork:
bl schedule_tail
+ b ret_from_except
#endif
- .globl ret_from_syscall
-ret_from_syscall:
+ .globl ret_from_intercept
+ret_from_intercept:
+ /*
+ * We may be returning from RTL and cannot do the normal checks
+ * -- Cort
+ */
+ cmpi 0,r3,0
+ beq 10f
.globl ret_from_except
ret_from_except:
-0: mfmsr r30 /* Disable interrupts */
- rlwinm r30,r30,0,17,15 /* clear MSR_EE */
- SYNC /* Some chip revs need this... */
- mtmsr r30
- SYNC
+0: /* disable interrupts */
+ lis r30,int_control@h
+ ori r30,r30,int_control@l
+ lwz r30,0(r30)
+ mtlr r30
+ blrl
+
lwz r5,_MSR(r1)
andi. r5,r5,MSR_EE
beq 2f
@@ -317,9 +309,13 @@ lost_irq_ret:
bl do_bottom_half
.globl do_bottom_half_ret
do_bottom_half_ret:
-2: SYNC
- mtmsr r30 /* disable interrupts again */
- SYNC
+2: /* disable interrupts */
+ lis r30,int_control@h
+ ori r30,r30,int_control@l
+ lwz r30,0(r30)
+ mtlr r30
+ blrl
+
lwz r3,_MSR(r1) /* Returning to user mode? */
andi. r3,r3,MSR_PR
beq+ 10f /* if so, check need_resched and signals */
diff --git a/arch/ppc/kernel/gemini_pci.c b/arch/ppc/kernel/gemini_pci.c
index 3d6feed13..fb80dc493 100644
--- a/arch/ppc/kernel/gemini_pci.c
+++ b/arch/ppc/kernel/gemini_pci.c
@@ -229,13 +229,11 @@ __init void layout_bus( struct pci_bus *bus )
{
struct pci_dev *dev;
- if (!bus->devices && !bus->children)
- return;
-
io_base = ALIGN(io_base, 4*KB);
mem_base = ALIGN(mem_base, 4*KB);
- for( dev = bus->devices; dev; dev = dev->sibling ) {
+ pci_for_each_dev(dev)
+ {
if (((dev->class >> 16) != PCI_BASE_CLASS_BRIDGE) ||
((dev->class >> 8) == PCI_CLASS_BRIDGE_OTHER))
layout_dev( dev );
diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c
index fadddda8b..d7ca91780 100644
--- a/arch/ppc/kernel/gemini_setup.c
+++ b/arch/ppc/kernel/gemini_setup.c
@@ -330,7 +330,7 @@ void __init gemini_init_IRQ(void)
int i;
/* gemini has no 8259 */
- open_pic.irq_offset = 0;
+ open_pic_irq_offset = 0;
for( i=0; i < NR_IRQS; i++ )
irq_desc[i].handler = &open_pic;
openpic_init(1);
@@ -515,7 +515,7 @@ void gemini_post_irq(int irq)
* We do it this way since our irq_desc[irq].handler can change
* with RTL and no longer be open_pic -- Cort
*/
- if ( irq >= open_pic.irq_offset)
+ if ( irq >= open_pic_irq_offset)
openpic_eoi( smp_processor_id() );
}
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 451a1cad4..a70ba8bfd 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -287,7 +287,8 @@ turn_on_mmu:
stw r2,GPR2(r21); \
stw r1,0(r21); \
tovirt(r1,r21); /* set new kernel sp */ \
- SAVE_4GPRS(3, r21);
+ SAVE_4GPRS(3, r21); \
+ SAVE_GPR(7, r21);
/*
* Note: code which follows this uses cr0.eq (set if from kernel),
* r21, r22 (SRR0), and r23 (SRR1).
@@ -374,7 +375,7 @@ HardwareInterrupt:
.globl do_IRQ_intercept
do_IRQ_intercept:
.long do_IRQ;
- .long ret_from_except
+ .long ret_from_intercept
#else
bl apus_interrupt_entry
#endif /* CONFIG_APUS */
@@ -424,7 +425,7 @@ Decrementer:
.globl timer_interrupt_intercept
timer_interrupt_intercept:
.long timer_interrupt
- .long ret_from_except
+ .long ret_from_intercept
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
@@ -674,7 +675,6 @@ DataStoreTLBMiss:
transfer_to_handler:
stw r22,_NIP(r21)
stw r23,_MSR(r21)
- SAVE_GPR(7, r21)
SAVE_4GPRS(8, r21)
SAVE_8GPRS(12, r21)
SAVE_8GPRS(24, r21)
diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
index abc651218..ba3284ad8 100644
--- a/arch/ppc/kernel/head_4xx.S
+++ b/arch/ppc/kernel/head_4xx.S
@@ -27,10 +27,8 @@
#include <linux/config.h>
#include <asm/processor.h>
-#include <asm/4xx.h>
-#include <asm/403gcx.h>
-#include <asm/405gp.h>
#include <asm/page.h>
+#include <asm/pgtable.h>
#include <asm/mmu.h>
#include "ppc_asm.h"
@@ -58,7 +56,7 @@
### execution begins here, the following registers contain valid, yet
### optional, information:
###
-### r3 - ???
+### r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
### r4 - Starting address of the init RAM disk
### r5 - Ending address of the init RAM disk
### r6 - Start of kernel command line string (e.g. "mem=96m")
@@ -80,17 +78,55 @@ _GLOBAL(_start)
li r24,0
- ## Establish exception vector base
+ ## We should still be executing code at physical address 0x0000xxxx
+ ## at this point. However, start_here is at virtual address
+ ## 0xC000xxxx. So, set up a TLB mapping to cover this once
+ ## translation is enabled.
+
+ lis r3,KERNELBASE@h # Load the kernel virtual address
+ addis r3,r3,KERNELBASE@l
+ tophys(r4,r3) # Load the kernel physical address
+
+ ## Save the existing PID and load the kernel PID.
+
+ mfspr r7,SPRN_PID # Save the old PID
+ li r0,0
+ mtspr SPRN_PID,r0 # Load the kernel PID
+
+ ## Configure and load entry into TLB slot 0.
- lis r0,KERNELBASE@h
- mtspr SPRN_EVPR,r0
+ clrrwi r4,r4,10 # Mask off the real page number
- ## Jump to the main PowerPC kernel start-up code
+ ## XXX - Temporarily set the TLB_I bit because of cache issues that
+ ## seem to foul-up the exception handling code.
+
+ ori r4,r4,(TLB_WR | TLB_EX | TLB_I) # Set the write and execute bits
-1: lis r7,start_here@ha
- addi r7,r7,start_here@l
- mtlr r7
- blr
+ clrrwi r3,r3,10 # Mask off the effective page number
+ ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
+
+ tlbwe r4,r0,TLB_DATA # Load the data portion of the entry
+ tlbwe r3,r0,TLB_TAG # Load the tag portion of the entry
+ isync
+
+ mtspr SPRN_PID,r7 # Restore the existing PID
+
+ ## Establish the exception vector base
+
+ lis r4,KERNELBASE@h # EVPR only uses the high 16-bits
+ tophys(r0,r4) # Use the physical address
+ mtspr SPRN_EVPR,r0
+
+ ## Enable the MMU and jump to the main PowerPC kernel start-up code
+
+ mfmsr r0 # Get the machine state register
+ ori r0,r0,(MSR_DR | MSR_IR) # Enable data and instr. translation
+ mtspr SPRN_SRR1,r0 # Set up the new machine state register
+ lis r0,start_here@h
+ ori r0,r0,start_here@l
+ mtspr SPRN_SRR0,r0 # Set up the new instruction pointer
+ rfi # Jump to start_here w/ translation on
+
###
### Exception vector entry code. This code runs with address translation
@@ -129,7 +165,8 @@ _GLOBAL(_start)
stw r2,GPR2(r21); /* Save r2 on the stack */\
stw r1,0(r21); \
tovirt(r1,r21); /* Set-up new kernel stack pointer */\
- SAVE_4GPRS(3, r21); /* Save r3 through r6 on the stack */
+ SAVE_4GPRS(3, r21); /* Save r3 through r6 on the stack */\
+ SAVE_GPR(7, r21); /* Save r7 on the stack */
## Common exception code for standard (non-critical) exceptions.
@@ -166,7 +203,7 @@ label:
START_EXCEPTION(n, label); \
STND_EXCEPTION_PROLOG; \
addi r3,r1,STACK_FRAME_OVERHEAD; \
- li r0,STND_EXC; \
+ li r7,STND_EXC; \
li r20,MSR_KERNEL; \
FINISH_EXCEPTION(func)
@@ -175,23 +212,10 @@ label:
START_EXCEPTION(n, label); \
CRIT_EXCEPTION_PROLOG; \
addi r3,r1,STACK_FRAME_OVERHEAD; \
- li r0,CRIT_EXC; \
+ li r7,CRIT_EXC; \
li r20,MSR_KERNEL; \
FINISH_EXCEPTION(func)
-
-#define INTR_EXCEPTION(n, label, func) \
- START_EXCEPTION(n, label); \
- STND_EXCEPTION_PROLOG; \
- addi r3,r1,STACK_FRAME_OVERHEAD; \
- li r0,STND_EXC; \
- li r20,MSR_KERNEL; \
- li r4,0; \
- bl transfer_to_handler; \
-_GLOBAL(do_IRQ_intercept); \
- .long func; \
- .long ret_from_except
-
###
### Exception vectors.
@@ -214,7 +238,7 @@ _GLOBAL(do_IRQ_intercept); \
mfspr r4,SPRN_DEAR # Grab the DEAR, save it, pass as arg2
stw r4,_DEAR(r21)
addi r3,r1,STACK_FRAME_OVERHEAD
- li r0,STND_EXC # This is a standard exception
+ li r7,STND_EXC # This is a standard exception
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
FINISH_EXCEPTION(do_page_fault) # do_page_fault(regs, ESR, DEAR)
@@ -226,15 +250,24 @@ _GLOBAL(do_IRQ_intercept); \
mr r4,r22 # Pass SRR0 as arg2
mr r5,r23 # Pass SRR1 as arg3
addi r3,r1,STACK_FRAME_OVERHEAD
- li r0,STND_EXC # This is a standard exception
+ li r7,STND_EXC # This is a standard exception
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
FINISH_EXCEPTION(do_page_fault) # do_page_fault(regs, SRR0, SRR1)
### 0x0500 - External Interrupt Exception
- INTR_EXCEPTION(0x0500, HardwareInterrupt, do_IRQ)
-
+ START_EXCEPTION(0x0500, HardwareInterrupt)
+ STND_EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r7,STND_EXC
+ li r20,MSR_KERNEL
+ li r4,0
+ bl transfer_to_handler
+_GLOBAL(do_IRQ_intercept)
+ .long do_IRQ
+ .long ret_from_intercept
+
### 0x0600 - Alignment Exception
START_EXCEPTION(0x0600, Alignment)
@@ -242,7 +275,7 @@ _GLOBAL(do_IRQ_intercept); \
mfspr r4,SPRN_DEAR # Grab the DEAR and save it
stw r4,_DEAR(r21)
addi r3,r1,STACK_FRAME_OVERHEAD
- li r0,STND_EXC # This is a standard exception
+ li r7,STND_EXC # This is a standard exception
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
FINISH_EXCEPTION(AlignmentException)
@@ -252,7 +285,7 @@ _GLOBAL(do_IRQ_intercept); \
START_EXCEPTION(0x0700, ProgramCheck)
STND_EXCEPTION_PROLOG
addi r3,r1,STACK_FRAME_OVERHEAD
- li r0,STND_EXC # This is a standard exception
+ li r7,STND_EXC # This is a standard exception
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
FINISH_EXCEPTION(ProgramCheckException)
@@ -266,7 +299,7 @@ _GLOBAL(do_IRQ_intercept); \
START_EXCEPTION(0x0C00, SystemCall)
STND_EXCEPTION_PROLOG
stw r3,ORIG_GPR3(r21)
- li r0,STND_EXC # This is a standard exception
+ li r7,STND_EXC # This is a standard exception
li r20,MSR_KERNEL
rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
FINISH_EXCEPTION(DoSyscall)
@@ -275,11 +308,21 @@ _GLOBAL(do_IRQ_intercept); \
STND_EXCEPTION(0x0E00, Trap_0E, UnknownException)
STND_EXCEPTION(0x0F00, Trap_0F, UnknownException)
-#if 0
### 0x1000 - Programmable Interval Timer (PIT) Exception
- STND_EXCEPTION(0x1000, PITException, UnknownException)
+ START_EXCEPTION(0x1000, Decrementer)
+ STND_EXCEPTION_PROLOG
+ lis r0,TSR_PIS@h # Set-up the PIT exception mask
+ mtspr SPRN_TSR,r0 # Clear the PIT exception
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r7,STND_EXC # This is a standard exception
+ li r20,MSR_KERNEL
+ bl transfer_to_handler
+_GLOBAL(timer_interrupt_intercept)
+ .long timer_interrupt
+ .long ret_from_intercept
+#if 0
### 0x1010 - Fixed Interval Timer (FIT) Exception
STND_EXCEPTION(0x1010, FITException, UnknownException)
@@ -294,7 +337,7 @@ _GLOBAL(do_IRQ_intercept); \
START_EXCEPTION(0x1100, DTLBMiss)
STND_EXCEPTION_PROLOG
addi r3,r1,STACK_FRAME_OVERHEAD
- li r0,STND_EXC
+ li r7,STND_EXC
li r20,MSR_KERNEL
FINISH_EXCEPTION(UnknownException)
@@ -303,7 +346,7 @@ _GLOBAL(do_IRQ_intercept); \
START_EXCEPTION(0x1200, ITLBMiss)
STND_EXCEPTION_PROLOG
addi r3,r1,STACK_FRAME_OVERHEAD
- li r0,STND_EXC
+ li r7,STND_EXC
li r20,MSR_KERNEL
FINISH_EXCEPTION(UnknownException)
@@ -341,7 +384,6 @@ _GLOBAL(do_IRQ_intercept); \
_GLOBAL(transfer_to_handler)
stw r22,_NIP(r21) # Save the faulting IP on the stack
stw r23,_MSR(r21) # Save the exception MSR on the stack
- SAVE_GPR(7, r21) # Save r7 on the stack
SAVE_4GPRS(8, r21) # Save r8 through r11 on the stack
SAVE_8GPRS(12, r21) # Save r12 through r19 on the stack
SAVE_8GPRS(24, r21) # Save r24 through r31 on the stack
@@ -367,7 +409,7 @@ _GLOBAL(transfer_to_handler)
bgt- stack_ovf # If r2 < r1 < r2 + TASK_STRUCT_SIZE
lwz r24,0(r23) # Virtual address of the handler
lwz r23,4(r23) # Handler return pointer
- cmpwi cr0,r0,STND_EXC # What type of exception is this?
+ cmpwi cr0,r7,STND_EXC # What type of exception is this?
bne 3f # It is a critical exception...
## Standard exception jump path
@@ -432,67 +474,10 @@ _GLOBAL(giveup_fpu)
_GLOBAL(abort)
mfspr r13,SPRN_DBCR
- ori r13,r13,DBCR_RST(SYSTEM)@h
+ oris r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h
mtspr SPRN_DBCR,r13
-
-###
-### This code is jumped-to from the startup code. It copies the kernel
-### image from wherever it happens to be currently running at in physical
-### address space to physical address 0.
-###
-### In general, for a running Linux/PPC system:
-### Kernel Physical Address (KPA) = 0x00000000
-### Kernel Virtual Address (KVA) = 0xC0000000
-###
-
-#if 0
-relocate_kernel:
- lis r9,0x426f /* if booted from BootX, don't */
- addi r9,r9,0x6f58 /* translate source addr */
- cmpw r31,r9 /* (we have to on chrp) */
- beq 7f
- rlwinm r4,r4,0,8,31 /* translate source address */
- add r4,r4,r3 /* to region mapped with BATs */
-7: addis r9,r26,klimit@ha /* fetch klimit */
- lwz r25,klimit@l(r9)
- addis r25,r25,-KERNELBASE@h
- li r6,0 /* Destination offset */
- li r5,0x4000 /* # bytes of memory to copy */
- bl copy_and_flush /* copy the first 0x4000 bytes */
- addi r0,r3,4f@l /* jump to the address of 4f */
- mtctr r0 /* in copy and do the rest. */
- bctr /* jump to the copy */
-4: mr r5,r25
- bl copy_and_flush /* copy the rest */
- b turn_on_mmu
-/*
- * Copy routine used to copy the kernel to start at physical address 0
- * and flush and invalidate the caches as needed.
- * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
- * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
- */
-copy_and_flush:
- addi r5,r5,-4
- addi r6,r6,-4
-4: li r0,8
- mtctr r0
-3: addi r6,r6,4 /* copy a cache line */
- lwzx r0,r6,r4
- stwx r0,r6,r3
- bdnz 3b
- dcbst r6,r3 /* write it to memory */
- sync
- icbi r6,r3 /* flush the icache line */
- cmplw 0,r6,r5
- blt 4b
- isync
- addi r5,r5,4
- addi r6,r6,4
- blr
-#endif
-
###
### This is where the main kernel code starts.
###
diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
index c5a55c6a2..94cd67d3b 100644
--- a/arch/ppc/kernel/head_8xx.S
+++ b/arch/ppc/kernel/head_8xx.S
@@ -197,7 +197,8 @@ turn_on_mmu:
stw r2,GPR2(r21); \
stw r1,0(r21); \
tovirt(r1,r21); /* set new kernel sp */ \
- SAVE_4GPRS(3, r21);
+ SAVE_4GPRS(3, r21); \
+ SAVE_GPR(7, r21);
/*
* Note: code which follows this uses cr0.eq (set if from kernel),
* r21, r22 (SRR0), and r23 (SRR1).
@@ -265,34 +266,6 @@ InstructionAccess:
. = 0x500;
HardwareInterrupt:
EXCEPTION_PROLOG;
-#ifdef CONFIG_APUS
- /* This is horrible, but there's no way around it. Enable the
- data cache so the IRQ hardware register can be accessed
- without cache intervention. Then disable interrupts and get
- the current emulated m68k IPL value. */
-
- mfmsr 20
- xori r20,r20,MSR_DR
- sync
- mtmsr r20
- sync
-
- lis r3,APUS_IPL_EMU@h
-
- li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT)
- stb r20,APUS_IPL_EMU@l(r3)
- eieio
-
- lbz r3,APUS_IPL_EMU@l(r3)
-
- mfmsr r20
- xori r20,r20,MSR_DR
- sync
- mtmsr r20
- sync
-
- stw r3,(_CCR+4)(r21);
-#endif
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
li r4,0
@@ -300,7 +273,7 @@ HardwareInterrupt:
.globl do_IRQ_intercept
do_IRQ_intercept:
.long do_IRQ;
- .long ret_from_except
+ .long ret_from_intercept
/* Alignment exception */
@@ -342,7 +315,7 @@ Decrementer:
.globl timer_interrupt_intercept
timer_interrupt_intercept:
.long timer_interrupt
- .long ret_from_except
+ .long ret_from_intercept
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
@@ -591,7 +564,6 @@ transfer_to_handler:
lis r22,MSR_POW@h
andc r23,r23,r22
stw r23,_MSR(r21)
- SAVE_GPR(7, r21)
SAVE_4GPRS(8, r21)
SAVE_8GPRS(12, r21)
SAVE_8GPRS(24, r21)
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index a09d6ad98..c2f2d1c11 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -294,11 +294,10 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
}
}
-asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
+asmlinkage int do_IRQ(struct pt_regs *regs, int isfake)
{
int cpu = smp_processor_id();
int irq;
-
hardirq_enter( cpu );
/* every arch is required to have a get_irq -- Cort */
@@ -320,10 +319,9 @@ asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
out:
hardirq_exit( cpu );
+ return 1; /* lets ret_from_int know we can do checks */
}
-
-
unsigned long probe_irq_on (void)
{
return 0;
diff --git a/arch/ppc/kernel/oak_setup.c b/arch/ppc/kernel/oak_setup.c
index a9c9137a0..ad2c224bb 100644
--- a/arch/ppc/kernel/oak_setup.c
+++ b/arch/ppc/kernel/oak_setup.c
@@ -7,26 +7,74 @@
* Description:
* Architecture- / platform-specific boot-time initialization code for
* the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- * <dmalek@jlc.net>.
+ * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ * <dan@net4x.com>.
*
*/
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/param.h>
#include <linux/string.h>
+#include <asm/processor.h>
+#include <asm/board.h>
#include <asm/machdep.h>
#include <asm/page.h>
+#include "local_irq.h"
+#include "ppc4xx_pic.h"
+#include "time.h"
#include "oak_setup.h"
+/* Function Prototypes */
+extern void abort(void);
+
+/* Global Variables */
+
+unsigned char __res[sizeof(bd_t)];
+
+
+/*
+ * void __init oak_init()
+ *
+ * Description:
+ * This routine...
+ *
+ * Input(s):
+ * r3 - Optional pointer to a board information structure.
+ * r4 - Optional pointer to the physical starting address of the init RAM
+ * disk.
+ * r5 - Optional pointer to the physical ending address of the init RAM
+ * disk.
+ * r6 - Optional pointer to the physical starting address of any kernel
+ * command-line parameters.
+ * r7 - Optional pointer to the physical ending address of any kernel
+ * command-line parameters.
+ *
+ * Output(s):
+ * N/A
+ *
+ * Returns:
+ * N/A
+ *
+ */
void __init
oak_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
-#if 0
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+ }
+
#if defined(CONFIG_BLK_DEV_INITRD)
/*
* If the init RAM disk has been configured in, and there's a valid
@@ -44,24 +92,25 @@ oak_init(unsigned long r3, unsigned long r4, unsigned long r5,
*(char *)(r7 + KERNELBASE) = 0;
strcpy(cmd_line, (char *)(r6 + KERNELBASE));
}
-#endif /* 0 */
+
+ /* Initialize machine-dependency vectors */
ppc_md.setup_arch = oak_setup_arch;
- ppc_md.setup_residual = NULL;
+ ppc_md.setup_residual = oak_setup_residual;
ppc_md.get_cpuinfo = NULL;
ppc_md.irq_cannonicalize = NULL;
- ppc_md.init_IRQ = NULL;
- ppc_md.get_irq = NULL;
+ ppc_md.init_IRQ = oak_init_IRQ;
+ ppc_md.get_irq = oak_get_irq;
ppc_md.init = NULL;
- ppc_md.restart = NULL;
- ppc_md.power_off = NULL;
- ppc_md.halt = NULL;
+ ppc_md.restart = oak_restart;
+ ppc_md.power_off = oak_power_off;
+ ppc_md.halt = oak_halt;
- ppc_md.time_init = NULL;
- ppc_md.set_rtc_time = NULL;
- ppc_md.get_rtc_time = NULL;
- ppc_md.calibrate_decr = NULL;
+ ppc_md.time_init = oak_time_init;
+ ppc_md.set_rtc_time = oak_set_rtc_time;
+ ppc_md.get_rtc_time = oak_get_rtc_time;
+ ppc_md.calibrate_decr = oak_calibrate_decr;
ppc_md.kbd_setkeycode = NULL;
ppc_md.kbd_getkeycode = NULL;
@@ -77,8 +126,168 @@ oak_init(unsigned long r3, unsigned long r4, unsigned long r5,
return;
}
+/*
+ * Document me.
+ */
void __init
oak_setup_arch(void)
{
+ /* XXX - Implement me */
+}
+
+/*
+ * int oak_setup_residual()
+ *
+ * Description:
+ * This routine pretty-prints the platform's internal CPU and bus clock
+ * frequencies into the buffer for usage in /proc/cpuinfo.
+ *
+ * Input(s):
+ * *buffer - Buffer into which CPU and bus clock frequencies are to be
+ * printed.
+ *
+ * Output(s):
+ * *buffer - Buffer with the CPU and bus clock frequencies.
+ *
+ * Returns:
+ * The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ * on error.
+ */
+int
+oak_setup_residual(char *buffer)
+{
+ int len = 0;
+ bd_t *bp = (bd_t *)__res;
+
+ len += sprintf(len + buffer,
+ "clock\t\t: %dMHz\n"
+ "bus clock\t\t: %dMHz\n",
+ bp->bi_intfreq / 1000000,
+ bp->bi_busfreq / 1000000);
+
+ return (len);
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_init_IRQ(void)
+{
+ int i;
+
+ ppc4xx_pic_init();
+
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc[i].handler = ppc4xx_pic;
+ }
+
+ return;
+}
+
+/*
+ * Document me.
+ */
+int
+oak_get_irq(struct pt_regs *regs)
+{
+ return (ppc4xx_pic_get_irq(regs));
+}
+
+/*
+ * Document me.
+ */
+void
+oak_restart(char *cmd)
+{
+ abort();
+}
+
+/*
+ * Document me.
+ */
+void
+oak_power_off(void)
+{
+ oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void
+oak_halt(void)
+{
+ oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_time_init(void)
+{
+ /* XXX - Implement me */
+}
+
+/*
+ * Document me.
+ */
+int __init
+oak_set_rtc_time(unsigned long time)
+{
+ /* XXX - Implement me */
+
+ return (0);
+}
+
+/*
+ * Document me.
+ */
+unsigned long __init
+oak_get_rtc_time(void)
+{
+ /* XXX - Implement me */
+
+ return (0);
+}
+
+/*
+ * void __init oak_calibrate_decr()
+ *
+ * Description:
+ * This routine retrieves the internal processor frequency from the board
+ * information structure, sets up the kernel timer decrementer based on
+ * that value, enables the 403 programmable interval timer (PIT) and sets
+ * it up for auto-reload.
+ *
+ * Input(s):
+ * N/A
+ *
+ * Output(s):
+ * N/A
+ *
+ * Returns:
+ * N/A
+ *
+ */
+void __init
+oak_calibrate_decr(void)
+{
+ unsigned int freq;
+ bd_t *bip = (bd_t *)__res;
+
+ freq = bip->bi_intfreq;
+
+ decrementer_count = freq / HZ;
+ count_period_num = 1;
+ count_period_den = freq;
+
+ /* Enable the PIT and set auto-reload of its value */
+
+ mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+ /* Clear any pending timer interrupts */
+ mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
}
diff --git a/arch/ppc/kernel/oak_setup.h b/arch/ppc/kernel/oak_setup.h
index 10f7d7354..62cfac906 100644
--- a/arch/ppc/kernel/oak_setup.h
+++ b/arch/ppc/kernel/oak_setup.h
@@ -15,14 +15,32 @@
#ifndef __OAK_SETUP_H__
#define __OAK_SETUP_H__
+#include <asm/ptrace.h>
+#include <asm/board.h>
+
+
#ifdef __cplusplus
extern "C" {
#endif
-extern void oak_init(unsigned long r3,
- unsigned long ird_start, unsigned long ird_end,
- unsigned long cline_start, unsigned long cline_end);
-extern void oak_setup_arch(void);
+extern unsigned char __res[sizeof(bd_t)];
+
+extern void oak_init(unsigned long r3,
+ unsigned long ird_start,
+ unsigned long ird_end,
+ unsigned long cline_start,
+ unsigned long cline_end);
+extern void oak_setup_arch(void);
+extern int oak_setup_residual(char *buffer);
+extern void oak_init_IRQ(void);
+extern int oak_get_irq(struct pt_regs *regs);
+extern void oak_restart(char *cmd);
+extern void oak_power_off(void);
+extern void oak_halt(void);
+extern void oak_time_init(void);
+extern int oak_set_rtc_time(unsigned long now);
+extern unsigned long oak_get_rtc_time(void);
+extern void oak_calibrate_decr(void);
#ifdef __cplusplus
diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
index 02e276729..6857aa36f 100644
--- a/arch/ppc/kernel/open_pic.c
+++ b/arch/ppc/kernel/open_pic.c
@@ -38,6 +38,7 @@ struct hw_interrupt_type open_pic = {
0,
0
};
+int open_pic_irq_offset;
/*
* Accesses to the current processor's registers
@@ -69,7 +70,7 @@ struct hw_interrupt_type open_pic = {
* -- Cort
*/
#define check_arg_irq(irq) \
- /*if (irq < 0 || irq >= (NumSources+open_pic.irq_offset)) \
+ /*if (irq < 0 || irq >= (NumSources+open_pic_irq_offset)) \
printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);*/
#define check_arg_cpu(cpu) \
if (cpu < 0 || cpu >= NumProcessors) \
@@ -212,11 +213,11 @@ void __init openpic_init(int main_pic)
/* Initialize external interrupts */
if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc);
/* SIOint (8259 cascade) is special */
- openpic_initirq(0, 8, open_pic.irq_offset, 1, 1);
+ openpic_initirq(0, 8, open_pic_irq_offset, 1, 1);
openpic_mapirq(0, 1<<0);
for (i = 1; i < NumSources; i++) {
/* Enabled, Priority 8 */
- openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
+ openpic_initirq(i, 8, open_pic_irq_offset+i, 0,
i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
/* Processor 0 */
openpic_mapirq(i, 1<<0);
@@ -416,13 +417,13 @@ void openpic_maptimer(u_int timer, u_int cpumask)
void openpic_enable_irq(u_int irq)
{
check_arg_irq(irq);
- openpic_clearfield(&OpenPIC->Source[irq-irq_desc[irq].handler->irq_offset].Vector_Priority, OPENPIC_MASK);
+ openpic_clearfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK);
}
void openpic_disable_irq(u_int irq)
{
check_arg_irq(irq);
- openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].handler->irq_offset].Vector_Priority, OPENPIC_MASK);
+ openpic_setfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK);
}
/*
diff --git a/arch/ppc/kernel/open_pic.h b/arch/ppc/kernel/open_pic.h
index 2673263cf..3e51ffba3 100644
--- a/arch/ppc/kernel/open_pic.h
+++ b/arch/ppc/kernel/open_pic.h
@@ -7,4 +7,5 @@ void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
void openpic_enable_IPI(u_int ipi);
void do_openpic_setup_cpu(void);
+extern int open_pic_irq_offset;
#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index ec1ff3565..6c98bbf2c 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -9,6 +9,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/openpic.h>
+#include <linux/errno.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -21,7 +22,7 @@
#include "pci.h"
-static void __init pcibios_claim_resources(struct pci_bus *);
+static void __init pcibios_claim_resources(struct list_head *);
unsigned long isa_io_base = 0;
unsigned long isa_mem_base = 0;
@@ -69,10 +70,9 @@ struct pci_ops generic_pci_ops =
void __init pcibios_init(void)
{
printk("PCI: Probing PCI hardware\n");
- ioport_resource.end = ~0L;
pci_scan_bus(0, &generic_pci_ops, NULL);
- pcibios_claim_resources(pci_root);
- if ( ppc_md.pcibios_fixup )
+ pcibios_claim_resources(&pci_root_buses);
+ if (ppc_md.pcibios_fixup)
ppc_md.pcibios_fixup();
}
@@ -162,3 +162,75 @@ void __init
pcibios_align_resource(void *data, struct resource *res, unsigned long size)
{
}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for (idx=0; idx<6; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n",
+ dev->slot_name, old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+/*
+ * Assign new address to PCI resource. We hope our resource information
+ * is complete. We don't re-assign resources unless we are
+ * forced to do so.
+ *
+ * Expects start=0, end=size-1, flags=resource type.
+ */
+
+int pci_assign_resource(struct pci_dev *dev, int i)
+{
+ struct resource *r = &dev->resource[i];
+ struct resource *pr = pci_find_parent_resource(dev, r);
+ unsigned long size = r->end + 1;
+ u32 new, check;
+
+ if (!pr) {
+ printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name);
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO) {
+ if (allocate_resource(pr, r, size, 0x100, ~0, size, NULL, NULL)) {
+ printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
+ return -EBUSY;
+ }
+ } else {
+ if (allocate_resource(pr, r, size, 0x10000, ~0, size, NULL, NULL)) {
+ printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
+ return -EBUSY;
+ }
+ }
+ if (i < 6) {
+ int reg = PCI_BASE_ADDRESS_0 + 4*i;
+ new = r->start | (r->flags & PCI_REGION_FLAG_MASK);
+ pci_write_config_dword(dev, reg, new);
+ pci_read_config_dword(dev, reg, &check);
+ if (new != check)
+ printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check);
+ } else if (i == PCI_ROM_RESOURCE) {
+ r->flags |= PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK));
+ }
+ printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i);
+ return 0;
+}
diff --git a/arch/ppc/kernel/pmac_nvram.c b/arch/ppc/kernel/pmac_nvram.c
index 99bfa4f8b..ea3338aef 100644
--- a/arch/ppc/kernel/pmac_nvram.c
+++ b/arch/ppc/kernel/pmac_nvram.c
@@ -10,6 +10,7 @@
#include <asm/io.h>
#include <asm/system.h>
#include <asm/prom.h>
+#include <asm/machdep.h>
#include <linux/adb.h>
#include <linux/pmu.h>
diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c
index 60b497cd6..3b7dd283f 100644
--- a/arch/ppc/kernel/pmac_time.c
+++ b/arch/ppc/kernel/pmac_time.c
@@ -24,6 +24,7 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/pgtable.h>
+#include <asm/machdep.h>
#include "time.h"
diff --git a/arch/ppc/kernel/ppc4xx_pic.c b/arch/ppc/kernel/ppc4xx_pic.c
new file mode 100644
index 000000000..8b40080b4
--- /dev/null
+++ b/arch/ppc/kernel/ppc4xx_pic.c
@@ -0,0 +1,204 @@
+/*
+ *
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: ppc4xx_pic.c
+ *
+ * Description:
+ * Interrupt controller driver for PowerPC 4xx-based processors.
+ */
+
+/*
+ * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
+ * 32 possible interrupts, a majority of which are not implemented on
+ * all cores. There are six configurable, external interrupt pins and
+ * there are eight internal interrupts for the on-chip serial port
+ * (SPU), DMA controller, and JTAG controller.
+ *
+ * The PowerPC 405 cores' Universal Interrupt Controller (UIC) has 32
+ * possible interrupts as well. There are seven, configurable external
+ * interrupt pins and there are 17 internal interrupts for the on-chip
+ * serial port, DMA controller, on-chip Ethernet controller, PCI, etc.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include "local_irq.h"
+#include "ppc4xx_pic.h"
+
+
+/* Global Variables */
+
+struct hw_interrupt_type *ppc4xx_pic;
+
+
+/* Function Prototypes */
+
+static void ppc403_aic_enable(unsigned int irq);
+static void ppc403_aic_disable(unsigned int irq);
+static void ppc403_aic_disable_and_ack(unsigned int irq);
+
+static void ppc405_uic_enable(unsigned int irq);
+static void ppc405_uic_disable(unsigned int irq);
+static void ppc405_uic_disable_and_ack(unsigned int irq);
+
+static struct hw_interrupt_type ppc403_aic = {
+ "403GC AIC",
+ NULL,
+ NULL,
+ ppc403_aic_enable,
+ ppc403_aic_disable,
+ ppc403_aic_disable_and_ack,
+ 0
+};
+
+static struct hw_interrupt_type ppc405_uic = {
+ "405GP UIC",
+ NULL,
+ NULL,
+ ppc405_uic_enable,
+ ppc405_uic_disable,
+ ppc405_uic_disable_and_ack,
+ 0
+};
+
+/*
+ * Document me.
+ */
+void __init
+ppc4xx_pic_init(void)
+{
+ unsigned long ver = PVR_VER(mfspr(SPRN_PVR));
+
+ switch (ver) {
+
+ case PVR_VER(PVR_403GC):
+ /*
+ * Disable all external interrupts until they are
+ * explicity requested.
+ */
+ ppc_cached_irq_mask[0] = 0;
+ mtdcr(DCRN_EXIER, 0);
+
+ ppc4xx_pic = &ppc403_aic;
+ break;
+
+ case PVR_VER(PVR_405GP):
+ ppc4xx_pic = &ppc405_uic;
+ break;
+ }
+
+ return;
+}
+
+/*
+ * XXX - Currently 403-specific!
+ *
+ * Document me.
+ */
+int
+ppc4xx_pic_get_irq(struct pt_regs *regs)
+{
+ int irq;
+ unsigned long bits, mask = (1 << 31);
+
+ /*
+ * Only report the status of those interrupts that are actually
+ * enabled.
+ */
+
+ bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER);
+
+ /*
+ * Walk through the interrupts from highest priority to lowest, and
+ * report the first pending interrupt found.
+ */
+
+ for (irq = 0; irq < NR_IRQS; irq++, mask >>= 1) {
+ if (bits & mask)
+ break;
+ }
+
+ return (irq);
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc403_aic_enable(unsigned int irq)
+{
+ int bit, word;
+
+ bit = irq & 0x1f;
+ word = irq >> 5;
+
+ ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+ mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc403_aic_disable(unsigned int irq)
+{
+ int bit, word;
+
+ bit = irq & 0x1f;
+ word = irq >> 5;
+
+ ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+ mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc403_aic_disable_and_ack(unsigned int irq)
+{
+ int bit, word;
+
+ bit = irq & 0x1f;
+ word = irq >> 5;
+
+ ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+ mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+ mtdcr(DCRN_EXISR, (1 << (31 - bit)));
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc405_uic_enable(unsigned int irq)
+{
+ /* XXX - Implement me. */
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc405_uic_disable(unsigned int irq)
+{
+ /* XXX - Implement me. */
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc405_uic_disable_and_ack(unsigned int irq)
+{
+ /* XXX - Implement me. */
+}
diff --git a/arch/ppc/kernel/ppc4xx_pic.h b/arch/ppc/kernel/ppc4xx_pic.h
new file mode 100644
index 000000000..6de862a46
--- /dev/null
+++ b/arch/ppc/kernel/ppc4xx_pic.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: ppc4xx_pic.h
+ *
+ * Description:
+ * Interrupt controller driver for PowerPC 4xx-based processors.
+ */
+
+#ifndef __PPC4XX_PIC_H__
+#define __PPC4XX_PIC_H__
+
+#include <asm/ptrace.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* External Global Variables */
+
+extern struct hw_interrupt_type *ppc4xx_pic;
+
+
+/* Function Prototypes */
+
+extern void ppc4xx_pic_init(void);
+extern int ppc4xx_pic_get_irq(struct pt_regs *regs);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PPC4XX_PIC_H__ */
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 397685d43..65e925034 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -260,10 +260,8 @@ EXPORT_SYMBOL(screen_info);
#endif
EXPORT_SYMBOL(int_control);
-#if !defined(CONFIG_4xx)
EXPORT_SYMBOL(timer_interrupt_intercept);
EXPORT_SYMBOL(timer_interrupt);
-#endif
extern unsigned long do_IRQ_intercept;
EXPORT_SYMBOL(do_IRQ_intercept);
EXPORT_SYMBOL(irq_desc);
@@ -272,3 +270,4 @@ EXPORT_SYMBOL(ppc_irq_dispatch_handler);
EXPORT_SYMBOL(decrementer_count);
EXPORT_SYMBOL(get_wchan);
EXPORT_SYMBOL(console_drivers);
+EXPORT_SYMBOL(do_bottom_half);
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 64b171042..241b7c33c 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -287,11 +287,12 @@ int
copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
+ unsigned long msr;
struct pt_regs * childregs, *kregs;
#ifdef __SMP__
extern void ret_from_smpfork(void);
#else
- extern void ret_from_syscall(void);
+ extern void ret_from_except(void);
#endif
/* Copy registers */
childregs = ((struct pt_regs *)
@@ -308,9 +309,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
#ifdef __SMP__
kregs->nip = (unsigned long)ret_from_smpfork;
#else
- kregs->nip = (unsigned long)ret_from_syscall;
+ kregs->nip = (unsigned long)ret_from_except;
#endif
- kregs->msr = MSR_KERNEL;
+ asm volatile("mfmsr %0" : "=r" (msr):);
+ kregs->msr = msr;
kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
kregs->gpr[2] = (unsigned long)p;
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index caffdcf99..dccb066ff 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -29,8 +29,9 @@
#endif
#include <asm/bootx.h>
#include <asm/machdep.h>
-
+#ifdef CONFIG_OAK
#include "oak_setup.h"
+#endif /* CONFIG_OAK */
extern void pmac_init(unsigned long r3,
unsigned long r4,
@@ -71,7 +72,13 @@ extern void gemini_init(unsigned long r3,
extern boot_infos_t *boot_infos;
char saved_command_line[256];
unsigned char aux_device_present;
-struct int_control_struct int_control;
+struct int_control_struct int_control =
+{
+ __no_use_cli,
+ __no_use_sti,
+ __no_use_restore_flags,
+ __no_use_save_flags
+};
struct ide_machdep_calls ppc_ide_md;
int parse_bootinfo(void);
@@ -89,20 +96,13 @@ unsigned long SYSRQ_KEY;
struct machdep_calls ppc_md;
-/* copy of the residual data */
-#ifndef CONFIG_8xx
-extern unsigned char __res[sizeof(RESIDUAL)];
-#else
-extern unsigned char __res[sizeof(bd_t)];
-#endif
-
/*
* Perhaps we can put the pmac screen_info[] here
* on pmac as well so we don't need the ifdef's.
* Until we get multiple-console support in here
* that is. -- Cort
*/
-#ifndef CONFIG_8xx
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
struct screen_info screen_info = {
0, 25, /* orig-x, orig-y */
0, /* unused */
@@ -126,7 +126,7 @@ void __init pmac_find_display(void)
{
}
-#else /* CONFIG_8xx */
+#else /* CONFIG_4xx || CONFIG_8xx */
/* We need this to satisfy some external references until we can
* strip the kernel down.
@@ -142,7 +142,7 @@ struct screen_info screen_info = {
0, /* orig-video-isVGA */
16 /* orig-video-points */
};
-#endif /* CONFIG_8xx */
+#endif /* !CONFIG_4xx && !CONFIG_8xx */
void machine_restart(char *cmd)
{
@@ -193,6 +193,7 @@ int get_cpuinfo(char *buffer)
unsigned long len = 0;
unsigned long bogosum = 0;
unsigned long i;
+ unsigned int pvr;
unsigned short maj, min;
#ifdef __SMP__
@@ -215,45 +216,75 @@ int get_cpuinfo(char *buffer)
len += sprintf(len+buffer,"processor\t: %lu\n",i);
len += sprintf(len+buffer,"cpu\t\t: ");
- switch (GET_PVR >> 16)
+ pvr = GET_PVR;
+
+ switch (PVR_VER(pvr))
{
- case 1:
+ case 0x0001:
len += sprintf(len+buffer, "601\n");
break;
- case 3:
+ case 0x0003:
len += sprintf(len+buffer, "603\n");
break;
- case 4:
+ case 0x0004:
len += sprintf(len+buffer, "604\n");
break;
- case 6:
+ case 0x0006:
len += sprintf(len+buffer, "603e\n");
break;
- case 7:
- len += sprintf(len+buffer, "603ev\n");
+ case 0x0007:
+ len += sprintf(len+buffer, "603");
+ if (((pvr >> 12) & 0xF) == 1) {
+ pvr ^= 0x00001000; /* revision fix-up */
+ len += sprintf(len+buffer, "r\n");
+ } else {
+ len += sprintf(len+buffer, "ev\n");
+ }
break;
- case 8:
- len += sprintf(len+buffer, "750\n");
+ case 0x0008: /* 740/750(P) */
+ case 0x1008:
+ len += sprintf(len+buffer, "750%s\n",
+ PVR_VER(pvr) == 0x1008 ? "P" : "");
len += sprintf(len+buffer, "temperature \t: %lu C\n",
cpu_temp());
break;
- case 9:
- len += sprintf(len+buffer, "604e\n");
+ case 0x0009: /* 604e/604r */
+ case 0x000A:
+ len += sprintf(len+buffer, "604");
+
+ if (PVR_VER(pvr) == 0x000A ||
+ ((pvr >> 12) & 0xF) != 0) {
+ pvr &= ~0x00003000; /* revision fix-up */
+ len += sprintf(len+buffer, "r\n");
+ } else {
+ len += sprintf(len+buffer, "e\n");
+ }
break;
- case 10:
- len += sprintf(len+buffer, "604ev5 (MachV)\n");
+ case 0x000C:
+ len += sprintf(len+buffer, "7400\n");
break;
- case 12:
- len += sprintf(len+buffer, "7400 (G4)\n");
+ case 0x0020:
+ len += sprintf(len+buffer, "403G");
+ switch ((pvr >> 8) & 0xFF) {
+ case 0x02:
+ len += sprintf(len+buffer, "C\n");
+ break;
+ case 0x14:
+ len += sprintf(len+buffer, "CX\n");
+ break;
+ }
break;
- case 50:
+ case 0x0050:
len += sprintf(len+buffer, "821\n");
- case 80:
- len += sprintf(len+buffer, "860\n");
+ break;
+ case 0x0081:
+ len += sprintf(len+buffer, "8240\n");
+ break;
+ case 0x4011:
+ len += sprintf(len+buffer, "405GP\n");
break;
default:
- len += sprintf(len+buffer, "unknown (%lx)\n",
- GET_PVR>>16);
+ len += sprintf(len+buffer, "unknown (%08x)\n", pvr);
break;
}
@@ -292,6 +323,22 @@ int get_cpuinfo(char *buffer)
len += ppc_md.setup_residual(buffer + len);
}
+ switch (PVR_VER(pvr))
+ {
+ case 0x0020:
+ maj = PVR_MAJ(pvr) + 1;
+ min = PVR_MIN(pvr);
+ break;
+ case 0x1008:
+ maj = ((pvr >> 8) & 0xFF) - 1;
+ min = pvr & 0xFF;
+ break;
+ default:
+ maj = (pvr >> 8) & 0xFF;
+ min = pvr & 0xFF;
+ break;
+ }
+
len += sprintf(len+buffer, "revision\t: %hd.%hd\n", maj, min);
len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
@@ -362,11 +409,6 @@ unsigned long __init
identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
- int_control.int_sti = __no_use_sti;
- int_control.int_cli = __no_use_cli;
- int_control.int_save_flags = __no_use_save_flags;
- int_control.int_restore_flags = __no_use_restore_flags;
-
parse_bootinfo();
if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
@@ -674,25 +716,25 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
id->word72 = __le16_to_cpu(id->word72);
id->word73 = __le16_to_cpu(id->word73);
id->word74 = __le16_to_cpu(id->word74);
- id->word75 = __le16_to_cpu(id->word75);
+ id->queue_depth = __le16_to_cpu(id->queue_depth);
id->word76 = __le16_to_cpu(id->word76);
id->word77 = __le16_to_cpu(id->word77);
id->word78 = __le16_to_cpu(id->word78);
id->word79 = __le16_to_cpu(id->word79);
- id->word80 = __le16_to_cpu(id->word80);
- id->word81 = __le16_to_cpu(id->word81);
- id->command_sets = __le16_to_cpu(id->command_sets);
- id->word83 = __le16_to_cpu(id->word83);
- id->word84 = __le16_to_cpu(id->word84);
- id->word85 = __le16_to_cpu(id->word85);
- id->word86 = __le16_to_cpu(id->word86);
- id->word87 = __le16_to_cpu(id->word87);
+ id->major_rev_num = __le16_to_cpu(id->major_rev_num);
+ id->minor_rev_num = __le16_to_cpu(id->minor_rev_num);
+ id->command_set_1 = __le16_to_cpu(id->command_set_1);
+ id->command_set_2 = __le16_to_cpu(id->command_set_2);
+ id->cfsse = __le16_to_cpu(id->cfsse);
+ id->cfs_enable_1 = __le16_to_cpu(id->cfs_enable_1);
+ id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2);
+ id->csf_default = __le16_to_cpu(id->csf_default);
id->dma_ultra = __le16_to_cpu(id->dma_ultra);
id->word89 = __le16_to_cpu(id->word89);
id->word90 = __le16_to_cpu(id->word90);
- id->word91 = __le16_to_cpu(id->word91);
+ id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues);
id->word92 = __le16_to_cpu(id->word92);
- id->word93 = __le16_to_cpu(id->word93);
+ id->hw_config = __le16_to_cpu(id->hw_config);
id->word94 = __le16_to_cpu(id->word94);
id->word95 = __le16_to_cpu(id->word95);
id->word96 = __le16_to_cpu(id->word96);
@@ -727,7 +769,6 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
id->word125 = __le16_to_cpu(id->word125);
id->word126 = __le16_to_cpu(id->word126);
id->word127 = __le16_to_cpu(id->word127);
- id->security = __le16_to_cpu(id->security);
for (i=0; i<127; i++)
id->reserved[i] = __le16_to_cpu(id->reserved[i]);
}
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index c2891e21f..386764ddd 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -446,6 +446,8 @@ void __init smp_callin(void)
*/
if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
do_openpic_setup_cpu();
+ if ( _machine == _MACH_gemini )
+ gemini_init_l2();
while(!smp_commenced)
barrier();
__sti();
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index e21c30e14..b695da797 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -68,7 +68,7 @@ unsigned count_period_den; /* count_period_num / count_period_den us */
* with interrupts disabled.
* We set it up to overflow again in 1/HZ seconds.
*/
-void timer_interrupt(struct pt_regs * regs)
+int timer_interrupt(struct pt_regs * regs)
{
int dval, d;
unsigned long cpu = smp_processor_id();
@@ -141,6 +141,7 @@ void timer_interrupt(struct pt_regs * regs)
ppc_md.heartbeat();
hardirq_exit(cpu);
+ return 1; /* lets ret_from_int know we can do checks */
}
/*
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
index a0a5c62d2..05d791546 100644
--- a/arch/ppc/kernel/time.h
+++ b/arch/ppc/kernel/time.h
@@ -6,8 +6,11 @@
* Paul Mackerras' version and mine for PReP and Pmac.
*/
+#include <linux/config.h>
#include <linux/mc146818rtc.h>
+#include <asm/processor.h>
+
/* time.c */
extern unsigned decrementer_count;
extern unsigned count_period_num;
@@ -22,13 +25,18 @@ int via_calibrate_decr(void);
/* Accessor functions for the decrementer register. */
static __inline__ unsigned int get_dec(void)
{
- unsigned int ret;
-
- asm volatile("mfspr %0,22" : "=r" (ret) :);
- return ret;
+#if defined(CONFIG_4xx)
+ return (mfspr(SPRN_PIT));
+#else
+ return (mfspr(SPRN_DEC));
+#endif
}
static __inline__ void set_dec(unsigned int val)
{
- asm volatile("mtspr 22,%0" : : "r" (val));
+#if defined(CONFIG_4xx)
+ mtspr(SPRN_PIT, val);
+#else
+ mtspr(SPRN_DEC, val);
+#endif
}
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 47fef50d4..04b4e2d36 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -194,7 +194,6 @@ void
ProgramCheckException(struct pt_regs *regs)
{
#if defined(CONFIG_4xx)
- unsigned int instr;
unsigned int esr = mfspr(SPRN_ESR);
if (esr & ESR_PTR) {