diff options
Diffstat (limited to 'arch/sparc64/prom')
-rw-r--r-- | arch/sparc64/prom/Makefile | 12 | ||||
-rw-r--r-- | arch/sparc64/prom/init.c | 5 | ||||
-rw-r--r-- | arch/sparc64/prom/map.S | 70 | ||||
-rw-r--r-- | arch/sparc64/prom/misc.c | 99 | ||||
-rw-r--r-- | arch/sparc64/prom/p1275.c | 18 | ||||
-rw-r--r-- | arch/sparc64/prom/ranges.c | 192 |
6 files changed, 173 insertions, 223 deletions
diff --git a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile index 1cec2111e..42906da28 100644 --- a/arch/sparc64/prom/Makefile +++ b/arch/sparc64/prom/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.2 1997/02/25 12:40:25 jj Exp $ +# $Id: Makefile,v 1.5 1999/12/21 04:02:26 davem Exp $ # Makefile for the Sun Boot PROM interface library under # Linux. # @@ -9,7 +9,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... OBJS = bootstr.o devops.o init.o memory.o misc.o \ - ranges.o tree.o console.o printf.o p1275.o + tree.o console.o printf.o p1275.o map.o all: promlib.a @@ -17,7 +17,13 @@ promlib.a: $(OBJS) $(AR) rcs promlib.a $(OBJS) sync +.S.s: + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o + dep: - $(CPP) -M *.c > .depend + $(CPP) $(CPPFLAGS) -M *.c > .depend include $(TOPDIR)/Rules.make diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c index 17166a72c..dad2f8302 100644 --- a/arch/sparc64/prom/init.c +++ b/arch/sparc64/prom/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.9 1999/08/31 06:55:03 davem Exp $ +/* $Id: init.c,v 1.10 1999/09/21 14:35:59 davem Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * @@ -28,7 +28,6 @@ int prom_chosen_node; */ extern void prom_meminit(void); -extern void prom_ranges_init(void); extern void prom_cif_init(void *, void *); void __init prom_init(void *cif_handler, void *cif_stack) @@ -82,8 +81,6 @@ void __init prom_init(void *cif_handler, void *cif_stack) prom_meminit(); - prom_ranges_init(); - /* Initialization successful. */ return; diff --git a/arch/sparc64/prom/map.S b/arch/sparc64/prom/map.S new file mode 100644 index 000000000..509f7b4ab --- /dev/null +++ b/arch/sparc64/prom/map.S @@ -0,0 +1,70 @@ +/* $Id: map.S,v 1.2 1999/11/19 05:53:02 davem Exp $ + * map.S: Tricky coding required to fixup the kernel OBP maps + * properly. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + + .text + .align 8192 + .globl prom_boot_page +prom_boot_page: +call_method: + .asciz "call-method" + .align 8 +map: + .asciz "map" + .align 8 + + /* When we are invoked, our caller has remapped us to + * page zero, therefore we must use PC relative addressing + * for everything after we begin performing the unmap/map + * calls. + */ + .globl prom_remap +prom_remap: /* %o0 = physpage, %o1 = virtpage, %o2 = mmu_ihandle */ + rd %pc, %g1 + srl %o2, 0, %o2 ! kill sign extension + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x10], %g3 ! prom_cif_stack + save %g3, -(192 + 128), %sp + ldx [%g2 + 0x08], %l0 ! prom_cif_handler + mov %g6, %i3 + mov %g4, %i4 + flushw + + sethi %hi(prom_remap - call_method), %g7 + or %g7, %lo(prom_remap - call_method), %g7 + sub %g1, %g7, %l2 ! call-method string + sethi %hi(prom_remap - map), %g7 + or %g7, %lo(prom_remap - map), %g7 + sub %g1, %g7, %l4 ! map string + + /* OK, map the 4MB region we really live at. */ + stx %l2, [%sp + 2047 + 128 + 0x00] ! call-method + mov 7, %l5 + stx %l5, [%sp + 2047 + 128 + 0x08] ! num_args + mov 1, %l5 + stx %l5, [%sp + 2047 + 128 + 0x10] ! num_rets + stx %l4, [%sp + 2047 + 128 + 0x18] ! map + stx %i2, [%sp + 2047 + 128 + 0x20] ! mmu_ihandle + mov -1, %l5 + stx %l5, [%sp + 2047 + 128 + 0x28] ! mode == default + sethi %hi(4 * 1024 * 1024), %l5 + stx %l5, [%sp + 2047 + 128 + 0x30] ! size + stx %i1, [%sp + 2047 + 128 + 0x38] ! vaddr + stx %g0, [%sp + 2047 + 128 + 0x40] ! filler + stx %i0, [%sp + 2047 + 128 + 0x48] ! paddr + call %l0 + add %sp, (2047 + 128), %o0 ! argument array + + /* Restore hard-coded globals. */ + mov %i3, %g6 + mov %i4, %g4 + + /* Wheee.... we are done. */ + ret + restore + + .align 8192 diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 2a45a4bb5..8d6404fea 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.15 1999/08/31 19:25:41 davem Exp $ +/* $Id: misc.c,v 1.16 1999/11/19 05:53:04 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -10,6 +10,8 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/delay.h> #include <asm/openprom.h> #include <asm/oplib.h> @@ -37,6 +39,11 @@ extern void (*prom_palette)(int); extern int serial_console; #endif +#ifdef __SMP__ +extern void smp_capture(void); +extern void smp_release(void); +#endif + /* Drop into the prom, with the chance to continue with the 'go' * prom command. */ @@ -44,26 +51,57 @@ void prom_cmdline(void) { unsigned long flags; - + + __save_and_cli(flags); + #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) prom_palette (1); #endif - __save_and_cli(flags); + + /* We always arrive here via a serial interrupt. + * So in order for everything to work reliably, even + * on SMP, we need to drop the IRQ locks we hold. + */ +#ifdef __SMP__ + hardirq_exit(smp_processor_id()); + smp_capture(); +#else + local_irq_count--; +#endif + p1275_cmd ("enter", P1275_INOUT(0,0)); - __restore_flags(flags); + +#ifdef __SMP__ + smp_release(); + hardirq_enter(smp_processor_id()); + spin_unlock_wait(&global_irq_lock); +#else + local_irq_count++; +#endif + #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) prom_palette (0); #endif + + __restore_flags(flags); } +#ifdef __SMP__ +extern void smp_promstop_others(void); +#endif + /* Drop into the prom, but completely terminate the program. * No chance of continuing. */ void prom_halt(void) { +#ifdef __SMP__ + smp_promstop_others(); + udelay(8000); +#endif again: p1275_cmd ("exit", P1275_INOUT(0,0)); goto again; /* PROM is out to get me -DaveM */ @@ -122,10 +160,10 @@ void prom_set_trap_table(unsigned long tba) p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba); } -/* This is only used internally below. */ -static int prom_get_mmu_ihandle(void) +int mmu_ihandle_cache = 0; + +int prom_get_mmu_ihandle(void) { - static int mmu_ihandle_cache = 0; int node, ret; if (mmu_ihandle_cache != 0) @@ -165,7 +203,10 @@ long prom_itlb_load(unsigned long index, unsigned long vaddr) { return p1275_cmd("call-method", - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)), + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(5, 1)), "SUNW,itlb-load", prom_get_mmu_ihandle(), /* And then our actual args are pushed backwards. */ @@ -179,7 +220,10 @@ long prom_dtlb_load(unsigned long index, unsigned long vaddr) { return p1275_cmd("call-method", - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)), + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(5, 1)), "SUNW,dtlb-load", prom_get_mmu_ihandle(), /* And then our actual args are pushed backwards. */ @@ -188,6 +232,41 @@ long prom_dtlb_load(unsigned long index, index); } +int prom_map(int mode, unsigned long size, + unsigned long vaddr, unsigned long paddr) +{ + int ret = p1275_cmd("call-method", + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_ARG(4, P1275_ARG_IN_64B) | + P1275_ARG(6, P1275_ARG_IN_64B) | + P1275_INOUT(7, 1)), + "map", + prom_get_mmu_ihandle(), + mode, + size, + vaddr, + 0, + paddr); + + if (ret == 0) + ret = -1; + return ret; +} + +void prom_unmap(unsigned long size, unsigned long vaddr) +{ + p1275_cmd("call-method", + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(2, P1275_ARG_IN_64B) | + P1275_ARG(3, P1275_ARG_IN_64B) | + P1275_INOUT(4, 0)), + "unmap", + prom_get_mmu_ihandle(), + size, + vaddr); +} + /* Set aside physical memory which is not touched or modified * across soft resets. */ @@ -226,7 +305,7 @@ int prom_getunumber(int syndrome_code, return p1275_cmd("call-method", (P1275_ARG(0, P1275_ARG_IN_STRING) | P1275_ARG(3, P1275_ARG_OUT_BUF) | - P1275_ARG(5, P1275_ARG_IN_64B) | + P1275_ARG(6, P1275_ARG_IN_64B) | P1275_INOUT(8, 2)), "SUNW,get-unumber", prom_get_memory_ihandle(), buflen, buf, P1275_SIZE(buflen), diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c index f30bdd3a8..5a4e4b693 100644 --- a/arch/sparc64/prom/p1275.c +++ b/arch/sparc64/prom/p1275.c @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.18 1999/09/10 10:40:53 davem Exp $ +/* $Id: p1275.c,v 1.20 1999/11/23 23:47:56 davem Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -252,11 +252,7 @@ void prom_cif_callback(void) * the counter is needed. -DaveM */ static int prom_entry_depth = 0; -static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED; -#ifdef __SMP__ -extern void smp_capture(void); -extern void smp_release(void); -#endif +spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED; static __inline__ unsigned long prom_get_lock(void) { @@ -270,9 +266,6 @@ static __inline__ unsigned long prom_get_lock(void) if (prom_entry_depth != 0) panic("prom_get_lock"); #endif -#ifdef __SMP__ - smp_capture(); -#endif } prom_entry_depth++; @@ -281,12 +274,9 @@ static __inline__ unsigned long prom_get_lock(void) static __inline__ void prom_release_lock(unsigned long flags) { - if (--prom_entry_depth == 0) { -#ifdef __SMP__ - smp_release(); -#endif + if (--prom_entry_depth == 0) spin_unlock(&prom_entry_lock); - } + __restore_flags(flags); } diff --git a/arch/sparc64/prom/ranges.c b/arch/sparc64/prom/ranges.c deleted file mode 100644 index 048e3412a..000000000 --- a/arch/sparc64/prom/ranges.c +++ /dev/null @@ -1,192 +0,0 @@ -/* $Id: ranges.c,v 1.12 1999/08/31 06:55:05 davem Exp $ - * ranges.c: Handle ranges in newer proms for obio/sbus. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -#include <linux/config.h> -#include <linux/init.h> -#include <asm/openprom.h> -#include <asm/oplib.h> -#include <asm/sbus.h> -#include <asm/fhc.h> -#include <asm/system.h> -#ifdef CONFIG_PCI -#include <asm/pbm.h> -#include <asm/ebus.h> -#endif - -struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX]; -int num_obio_ranges; - -/* Adjust register values based upon the ranges parameters. */ -inline void -prom_adjust_regs(struct linux_prom_registers *regp, int nregs, - struct linux_prom_ranges *rangep, int nranges) -{ - int regc, rngc; - - for(regc=0; regc < nregs; regc++) { - for(rngc=0; rngc < nranges; rngc++) - if(regp[regc].which_io == rangep[rngc].ot_child_space) - break; /* Fount it */ - if(rngc==nranges) /* oops */ - prom_printf("adjust_regs: Could not find range with matching bus type...\n"); - regp[regc].which_io = rangep[rngc].ot_parent_space; - regp[regc].phys_addr += rangep[rngc].ot_parent_base; - } -} - -inline void -prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1, - struct linux_prom_ranges *ranges2, int nranges2) -{ - int rng1c, rng2c; - - for(rng1c=0; rng1c < nranges1; rng1c++) { - for(rng2c=0; rng2c < nranges2; rng2c++) - if(ranges1[rng1c].ot_child_space == - ranges2[rng2c].ot_child_space) break; - if(rng2c == nranges2) /* oops */ - prom_printf("adjust_ranges: Could not find matching bus type...\n"); - ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space; - ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base; - } -} - -/* Apply probed sbus ranges to registers passed, if no ranges return. */ -void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs, - int nregs, struct linux_sbus_device *sdev) -{ - if(sbus->num_sbus_ranges) { - if(sdev && (sdev->ranges_applied == 0)) { - sdev->ranges_applied = 1; - prom_adjust_regs(regs, nregs, sbus->sbus_ranges, - sbus->num_sbus_ranges); - } - } -} - -/* Apply probed fhc ranges to registers passed, if no ranges return. */ -void prom_apply_fhc_ranges(struct linux_fhc *fhc, - struct linux_prom_registers *regs, - int nregs) -{ - if(fhc->num_fhc_ranges) - prom_adjust_regs(regs, nregs, fhc->fhc_ranges, - fhc->num_fhc_ranges); -} - -/* Apply probed central ranges to registers passed, if no ranges return. */ -void prom_apply_central_ranges(struct linux_central *central, - struct linux_prom_registers *regs, int nregs) -{ - if(central->num_central_ranges) - prom_adjust_regs(regs, nregs, central->central_ranges, - central->num_central_ranges); -} - -void __init prom_ranges_init(void) -{ -} - -void __init prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus) -{ - int success; - - sbus->num_sbus_ranges = 0; - success = prom_getproperty(sbus->prom_node, "ranges", - (char *) sbus->sbus_ranges, - sizeof (sbus->sbus_ranges)); - if (success != -1) - sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); -} - -void __init prom_central_ranges_init(int cnode, struct linux_central *central) -{ - int success; - - central->num_central_ranges = 0; - success = prom_getproperty(central->prom_node, "ranges", - (char *) central->central_ranges, - sizeof (central->central_ranges)); - if (success != -1) - central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); -} - -void __init prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc) -{ - int success; - - fhc->num_fhc_ranges = 0; - success = prom_getproperty(fhc->prom_node, "ranges", - (char *) fhc->fhc_ranges, - sizeof (fhc->fhc_ranges)); - if (success != -1) - fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges)); -} - -#ifdef CONFIG_PCI -void __init prom_ebus_ranges_init(struct linux_ebus *ebus) -{ - int success; - - ebus->num_ebus_ranges = 0; - success = prom_getproperty(ebus->prom_node, "ranges", - (char *)ebus->ebus_ranges, - sizeof(ebus->ebus_ranges)); - if (success != -1) - ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); -} - -void __init prom_ebus_intmap_init(struct linux_ebus *ebus) -{ - int success; - - ebus->num_ebus_intmap = 0; - success = prom_getproperty(ebus->prom_node, "interrupt-map", - (char *)ebus->ebus_intmap, - sizeof(ebus->ebus_intmap)); - if (success == -1) - return; - - ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap)); - - success = prom_getproperty(ebus->prom_node, "interrupt-map-mask", - (char *)&ebus->ebus_intmask, - sizeof(ebus->ebus_intmask)); - if (success == -1) { - prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); - prom_halt(); - } -} -#endif - -void -prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs) -{ - int success; - int num_ranges; - struct linux_prom_ranges ranges[PROMREG_MAX]; - - success = prom_getproperty(node, "ranges", - (char *) ranges, - sizeof (ranges)); - if (success != -1) { - num_ranges = (success/sizeof(struct linux_prom_ranges)); - if (parent) { - struct linux_prom_ranges parent_ranges[PROMREG_MAX]; - int num_parent_ranges; - - success = prom_getproperty(parent, "ranges", - (char *) parent_ranges, - sizeof (parent_ranges)); - if (success != -1) { - num_parent_ranges = (success/sizeof(struct linux_prom_ranges)); - prom_adjust_ranges (ranges, num_ranges, parent_ranges, num_parent_ranges); - } - } - prom_adjust_regs(regs, nregs, ranges, num_ranges); - } -} |