| From 2a6515d8d708846591ef0c4bce0e226f75aa01a7 Mon Sep 17 00:00:00 2001 |
| From: David S. Miller <davem@davemloft.net> |
| Date: Sun, 19 Sep 2010 17:50:44 -0700 |
| Subject: sparc64: Get rid of indirect p1275 PROM call buffer. |
| |
| From: David S. Miller <davem@davemloft.net> |
| |
| [ Upstream commit 25edd6946a1d74e5e77813c2324a0908c68bcf9e ] |
| |
| This is based upon a report by Meelis Roos showing that it's possible |
| that we'll try to fetch a property that is 32K in size with some |
| devices. With the current fixed 3K buffer we use for moving data in |
| and out of the firmware during PROM calls, that simply won't work. |
| |
| In fact, it will scramble random kernel data during bootup. |
| |
| The reasoning behind the temporary buffer is entirely historical. It |
| used to be the case that we had problems referencing dynamic kernel |
| memory (including the stack) early in the boot process before we |
| explicitly told the firwmare to switch us over to the kernel trap |
| table. |
| |
| So what we did was always give the firmware buffers that were locked |
| into the main kernel image. |
| |
| But we no longer have problems like that, so get rid of all of this |
| indirect bounce buffering. |
| |
| Besides fixing Meelis's bug, this also makes the kernel data about 3K |
| smaller. |
| |
| It was also discovered during these conversions that the |
| implementation of prom_retain() was completely wrong, so that was |
| fixed here as well. Currently that interface is not in use. |
| |
| Reported-by: Meelis Roos <mroos@linux.ee> |
| Tested-by: Meelis Roos <mroos@linux.ee> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| arch/sparc/include/asm/oplib_64.h | 27 --- |
| arch/sparc/prom/cif.S | 16 - |
| arch/sparc/prom/console_64.c | 48 ++++- |
| arch/sparc/prom/devops_64.c | 36 +++- |
| arch/sparc/prom/misc_64.c | 314 ++++++++++++++++++++++++++------------ |
| arch/sparc/prom/p1275.c | 102 ------------ |
| arch/sparc/prom/tree_64.c | 210 ++++++++++++++++++------- |
| 7 files changed, 456 insertions(+), 297 deletions(-) |
| |
| --- a/arch/sparc/include/asm/oplib_64.h |
| +++ b/arch/sparc/include/asm/oplib_64.h |
| @@ -185,9 +185,8 @@ extern int prom_getunumber(int syndrome_ |
| char *buf, int buflen); |
| |
| /* Retain physical memory to the caller across soft resets. */ |
| -extern unsigned long prom_retain(const char *name, |
| - unsigned long pa_low, unsigned long pa_high, |
| - long size, long align); |
| +extern int prom_retain(const char *name, unsigned long size, |
| + unsigned long align, unsigned long *paddr); |
| |
| /* Load explicit I/D TLB entries into the calling processor. */ |
| extern long prom_itlb_load(unsigned long index, |
| @@ -287,26 +286,6 @@ extern void prom_sun4v_guest_soft_state( |
| extern int prom_ihandle2path(int handle, char *buffer, int bufsize); |
| |
| /* Client interface level routines. */ |
| -extern long p1275_cmd(const char *, long, ...); |
| - |
| -#if 0 |
| -#define P1275_SIZE(x) ((((long)((x) / 32)) << 32) | (x)) |
| -#else |
| -#define P1275_SIZE(x) x |
| -#endif |
| - |
| -/* We support at most 16 input and 1 output argument */ |
| -#define P1275_ARG_NUMBER 0 |
| -#define P1275_ARG_IN_STRING 1 |
| -#define P1275_ARG_OUT_BUF 2 |
| -#define P1275_ARG_OUT_32B 3 |
| -#define P1275_ARG_IN_FUNCTION 4 |
| -#define P1275_ARG_IN_BUF 5 |
| -#define P1275_ARG_IN_64B 6 |
| - |
| -#define P1275_IN(x) ((x) & 0xf) |
| -#define P1275_OUT(x) (((x) << 4) & 0xf0) |
| -#define P1275_INOUT(i,o) (P1275_IN(i)|P1275_OUT(o)) |
| -#define P1275_ARG(n,x) ((x) << ((n)*3 + 8)) |
| +extern void p1275_cmd_direct(unsigned long *); |
| |
| #endif /* !(__SPARC64_OPLIB_H) */ |
| --- a/arch/sparc/prom/cif.S |
| +++ b/arch/sparc/prom/cif.S |
| @@ -9,18 +9,18 @@ |
| #include <asm/thread_info.h> |
| |
| .text |
| - .globl prom_cif_interface |
| -prom_cif_interface: |
| - sethi %hi(p1275buf), %o0 |
| - or %o0, %lo(p1275buf), %o0 |
| - ldx [%o0 + 0x010], %o1 ! prom_cif_stack |
| - save %o1, -192, %sp |
| - ldx [%i0 + 0x008], %l2 ! prom_cif_handler |
| + .globl prom_cif_direct |
| +prom_cif_direct: |
| + sethi %hi(p1275buf), %o1 |
| + or %o1, %lo(p1275buf), %o1 |
| + ldx [%o1 + 0x0010], %o2 ! prom_cif_stack |
| + save %o2, -192, %sp |
| + ldx [%i1 + 0x0008], %l2 ! prom_cif_handler |
| mov %g4, %l0 |
| mov %g5, %l1 |
| mov %g6, %l3 |
| call %l2 |
| - add %i0, 0x018, %o0 ! prom_args |
| + mov %i0, %o0 ! prom_args |
| mov %l0, %g4 |
| mov %l1, %g5 |
| mov %l3, %g6 |
| --- a/arch/sparc/prom/console_64.c |
| +++ b/arch/sparc/prom/console_64.c |
| @@ -21,14 +21,22 @@ extern int prom_stdin, prom_stdout; |
| inline int |
| prom_nbgetchar(void) |
| { |
| + unsigned long args[7]; |
| char inc; |
| |
| - if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)| |
| - P1275_INOUT(3,1), |
| - prom_stdin, &inc, P1275_SIZE(1)) == 1) |
| + args[0] = (unsigned long) "read"; |
| + args[1] = 3; |
| + args[2] = 1; |
| + args[3] = (unsigned int) prom_stdin; |
| + args[4] = (unsigned long) &inc; |
| + args[5] = 1; |
| + args[6] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + if (args[6] == 1) |
| return inc; |
| - else |
| - return -1; |
| + return -1; |
| } |
| |
| /* Non blocking put character to console device, returns -1 if |
| @@ -37,12 +45,22 @@ prom_nbgetchar(void) |
| inline int |
| prom_nbputchar(char c) |
| { |
| + unsigned long args[7]; |
| char outc; |
| |
| outc = c; |
| - if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| |
| - P1275_INOUT(3,1), |
| - prom_stdout, &outc, P1275_SIZE(1)) == 1) |
| + |
| + args[0] = (unsigned long) "write"; |
| + args[1] = 3; |
| + args[2] = 1; |
| + args[3] = (unsigned int) prom_stdout; |
| + args[4] = (unsigned long) &outc; |
| + args[5] = 1; |
| + args[6] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + if (args[6] == 1) |
| return 0; |
| else |
| return -1; |
| @@ -68,7 +86,15 @@ prom_putchar(char c) |
| void |
| prom_puts(const char *s, int len) |
| { |
| - p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| |
| - P1275_INOUT(3,1), |
| - prom_stdout, s, P1275_SIZE(len)); |
| + unsigned long args[7]; |
| + |
| + args[0] = (unsigned long) "write"; |
| + args[1] = 3; |
| + args[2] = 1; |
| + args[3] = (unsigned int) prom_stdout; |
| + args[4] = (unsigned long) s; |
| + args[5] = len; |
| + args[6] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| } |
| --- a/arch/sparc/prom/devops_64.c |
| +++ b/arch/sparc/prom/devops_64.c |
| @@ -18,16 +18,32 @@ |
| int |
| prom_devopen(const char *dstr) |
| { |
| - return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)| |
| - P1275_INOUT(1,1), |
| - dstr); |
| + unsigned long args[5]; |
| + |
| + args[0] = (unsigned long) "open"; |
| + args[1] = 1; |
| + args[2] = 1; |
| + args[3] = (unsigned long) dstr; |
| + args[4] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[4]; |
| } |
| |
| /* Close the device described by device handle 'dhandle'. */ |
| int |
| prom_devclose(int dhandle) |
| { |
| - p1275_cmd ("close", P1275_INOUT(1,0), dhandle); |
| + unsigned long args[4]; |
| + |
| + args[0] = (unsigned long) "close"; |
| + args[1] = 1; |
| + args[2] = 0; |
| + args[3] = (unsigned int) dhandle; |
| + |
| + p1275_cmd_direct(args); |
| + |
| return 0; |
| } |
| |
| @@ -37,5 +53,15 @@ prom_devclose(int dhandle) |
| void |
| prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) |
| { |
| - p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo); |
| + unsigned long args[7]; |
| + |
| + args[0] = (unsigned long) "seek"; |
| + args[1] = 3; |
| + args[2] = 1; |
| + args[3] = (unsigned int) dhandle; |
| + args[4] = seekhi; |
| + args[5] = seeklo; |
| + args[6] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| } |
| --- a/arch/sparc/prom/misc_64.c |
| +++ b/arch/sparc/prom/misc_64.c |
| @@ -20,10 +20,17 @@ |
| |
| int prom_service_exists(const char *service_name) |
| { |
| - int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | |
| - P1275_INOUT(1, 1), service_name); |
| + unsigned long args[5]; |
| |
| - if (err) |
| + args[0] = (unsigned long) "test"; |
| + args[1] = 1; |
| + args[2] = 1; |
| + args[3] = (unsigned long) service_name; |
| + args[4] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + if (args[4]) |
| return 0; |
| return 1; |
| } |
| @@ -31,30 +38,47 @@ int prom_service_exists(const char *serv |
| void prom_sun4v_guest_soft_state(void) |
| { |
| const char *svc = "SUNW,soft-state-supported"; |
| + unsigned long args[3]; |
| |
| if (!prom_service_exists(svc)) |
| return; |
| - p1275_cmd(svc, P1275_INOUT(0, 0)); |
| + args[0] = (unsigned long) svc; |
| + args[1] = 0; |
| + args[2] = 0; |
| + p1275_cmd_direct(args); |
| } |
| |
| /* Reset and reboot the machine with the command 'bcommand'. */ |
| void prom_reboot(const char *bcommand) |
| { |
| + unsigned long args[4]; |
| + |
| #ifdef CONFIG_SUN_LDOMS |
| if (ldom_domaining_enabled) |
| ldom_reboot(bcommand); |
| #endif |
| - p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) | |
| - P1275_INOUT(1, 0), bcommand); |
| + args[0] = (unsigned long) "boot"; |
| + args[1] = 1; |
| + args[2] = 0; |
| + args[3] = (unsigned long) bcommand; |
| + |
| + p1275_cmd_direct(args); |
| } |
| |
| /* Forth evaluate the expression contained in 'fstring'. */ |
| void prom_feval(const char *fstring) |
| { |
| + unsigned long args[5]; |
| + |
| if (!fstring || fstring[0] == 0) |
| return; |
| - p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) | |
| - P1275_INOUT(1, 1), fstring); |
| + args[0] = (unsigned long) "interpret"; |
| + args[1] = 1; |
| + args[2] = 1; |
| + args[3] = (unsigned long) fstring; |
| + args[4] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| } |
| EXPORT_SYMBOL(prom_feval); |
| |
| @@ -68,6 +92,7 @@ extern void smp_release(void); |
| */ |
| void prom_cmdline(void) |
| { |
| + unsigned long args[3]; |
| unsigned long flags; |
| |
| local_irq_save(flags); |
| @@ -76,7 +101,11 @@ void prom_cmdline(void) |
| smp_capture(); |
| #endif |
| |
| - p1275_cmd("enter", P1275_INOUT(0, 0)); |
| + args[0] = (unsigned long) "enter"; |
| + args[1] = 0; |
| + args[2] = 0; |
| + |
| + p1275_cmd_direct(args); |
| |
| #ifdef CONFIG_SMP |
| smp_release(); |
| @@ -90,22 +119,32 @@ void prom_cmdline(void) |
| */ |
| void notrace prom_halt(void) |
| { |
| + unsigned long args[3]; |
| + |
| #ifdef CONFIG_SUN_LDOMS |
| if (ldom_domaining_enabled) |
| ldom_power_off(); |
| #endif |
| again: |
| - p1275_cmd("exit", P1275_INOUT(0, 0)); |
| + args[0] = (unsigned long) "exit"; |
| + args[1] = 0; |
| + args[2] = 0; |
| + p1275_cmd_direct(args); |
| goto again; /* PROM is out to get me -DaveM */ |
| } |
| |
| void prom_halt_power_off(void) |
| { |
| + unsigned long args[3]; |
| + |
| #ifdef CONFIG_SUN_LDOMS |
| if (ldom_domaining_enabled) |
| ldom_power_off(); |
| #endif |
| - p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); |
| + args[0] = (unsigned long) "SUNW,power-off"; |
| + args[1] = 0; |
| + args[2] = 0; |
| + p1275_cmd_direct(args); |
| |
| /* if nothing else helps, we just halt */ |
| prom_halt(); |
| @@ -114,10 +153,15 @@ void prom_halt_power_off(void) |
| /* Set prom sync handler to call function 'funcp'. */ |
| void prom_setcallback(callback_func_t funcp) |
| { |
| + unsigned long args[5]; |
| if (!funcp) |
| return; |
| - p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) | |
| - P1275_INOUT(1, 1), funcp); |
| + args[0] = (unsigned long) "set-callback"; |
| + args[1] = 1; |
| + args[2] = 1; |
| + args[3] = (unsigned long) funcp; |
| + args[4] = (unsigned long) -1; |
| + p1275_cmd_direct(args); |
| } |
| |
| /* Get the idprom and stuff it into buffer 'idbuf'. Returns the |
| @@ -173,57 +217,61 @@ static int prom_get_memory_ihandle(void) |
| } |
| |
| /* Load explicit I/D TLB entries. */ |
| +static long tlb_load(const char *type, unsigned long index, |
| + unsigned long tte_data, unsigned long vaddr) |
| +{ |
| + unsigned long args[9]; |
| + |
| + args[0] = (unsigned long) prom_callmethod_name; |
| + args[1] = 5; |
| + args[2] = 1; |
| + args[3] = (unsigned long) type; |
| + args[4] = (unsigned int) prom_get_mmu_ihandle(); |
| + args[5] = vaddr; |
| + args[6] = tte_data; |
| + args[7] = index; |
| + args[8] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (long) args[8]; |
| +} |
| + |
| long prom_itlb_load(unsigned long index, |
| unsigned long tte_data, |
| unsigned long vaddr) |
| { |
| - return p1275_cmd(prom_callmethod_name, |
| - (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. */ |
| - vaddr, |
| - tte_data, |
| - index); |
| + return tlb_load("SUNW,itlb-load", index, tte_data, vaddr); |
| } |
| |
| long prom_dtlb_load(unsigned long index, |
| unsigned long tte_data, |
| unsigned long vaddr) |
| { |
| - return p1275_cmd(prom_callmethod_name, |
| - (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. */ |
| - vaddr, |
| - tte_data, |
| - index); |
| + return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr); |
| } |
| |
| int prom_map(int mode, unsigned long size, |
| unsigned long vaddr, unsigned long paddr) |
| { |
| - int ret = p1275_cmd(prom_callmethod_name, |
| - (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)), |
| - prom_map_name, |
| - prom_get_mmu_ihandle(), |
| - mode, |
| - size, |
| - vaddr, |
| - 0, |
| - paddr); |
| + unsigned long args[11]; |
| + int ret; |
| |
| + args[0] = (unsigned long) prom_callmethod_name; |
| + args[1] = 7; |
| + args[2] = 1; |
| + args[3] = (unsigned long) prom_map_name; |
| + args[4] = (unsigned int) prom_get_mmu_ihandle(); |
| + args[5] = (unsigned int) mode; |
| + args[6] = size; |
| + args[7] = vaddr; |
| + args[8] = 0; |
| + args[9] = paddr; |
| + args[10] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + ret = (int) args[10]; |
| if (ret == 0) |
| ret = -1; |
| return ret; |
| @@ -231,40 +279,51 @@ int prom_map(int mode, unsigned long siz |
| |
| void prom_unmap(unsigned long size, unsigned long vaddr) |
| { |
| - p1275_cmd(prom_callmethod_name, |
| - (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)), |
| - prom_unmap_name, |
| - prom_get_mmu_ihandle(), |
| - size, |
| - vaddr); |
| + unsigned long args[7]; |
| + |
| + args[0] = (unsigned long) prom_callmethod_name; |
| + args[1] = 4; |
| + args[2] = 0; |
| + args[3] = (unsigned long) prom_unmap_name; |
| + args[4] = (unsigned int) prom_get_mmu_ihandle(); |
| + args[5] = size; |
| + args[6] = vaddr; |
| + |
| + p1275_cmd_direct(args); |
| } |
| |
| /* Set aside physical memory which is not touched or modified |
| * across soft resets. |
| */ |
| -unsigned long prom_retain(const char *name, |
| - unsigned long pa_low, unsigned long pa_high, |
| - long size, long align) |
| -{ |
| - /* XXX I don't think we return multiple values correctly. |
| - * XXX OBP supposedly returns pa_low/pa_high here, how does |
| - * XXX it work? |
| - */ |
| +int prom_retain(const char *name, unsigned long size, |
| + unsigned long align, unsigned long *paddr) |
| +{ |
| + unsigned long args[11]; |
| |
| - /* If align is zero, the pa_low/pa_high args are passed, |
| - * else they are not. |
| + args[0] = (unsigned long) prom_callmethod_name; |
| + args[1] = 5; |
| + args[2] = 3; |
| + args[3] = (unsigned long) "SUNW,retain"; |
| + args[4] = (unsigned int) prom_get_memory_ihandle(); |
| + args[5] = align; |
| + args[6] = size; |
| + args[7] = (unsigned long) name; |
| + args[8] = (unsigned long) -1; |
| + args[9] = (unsigned long) -1; |
| + args[10] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + if (args[8]) |
| + return (int) args[8]; |
| + |
| + /* Next we get "phys_high" then "phys_low". On 64-bit |
| + * the phys_high cell is don't care since the phys_low |
| + * cell has the full value. |
| */ |
| - if (align == 0) |
| - return p1275_cmd("SUNW,retain", |
| - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), |
| - name, pa_low, pa_high, size, align); |
| - else |
| - return p1275_cmd("SUNW,retain", |
| - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), |
| - name, size, align); |
| + *paddr = args[10]; |
| + |
| + return 0; |
| } |
| |
| /* Get "Unumber" string for the SIMM at the given |
| @@ -277,62 +336,129 @@ int prom_getunumber(int syndrome_code, |
| unsigned long phys_addr, |
| char *buf, int buflen) |
| { |
| - return p1275_cmd(prom_callmethod_name, |
| - (P1275_ARG(0, P1275_ARG_IN_STRING) | |
| - P1275_ARG(3, P1275_ARG_OUT_BUF) | |
| - P1275_ARG(6, P1275_ARG_IN_64B) | |
| - P1275_INOUT(8, 2)), |
| - "SUNW,get-unumber", prom_get_memory_ihandle(), |
| - buflen, buf, P1275_SIZE(buflen), |
| - 0, phys_addr, syndrome_code); |
| + unsigned long args[12]; |
| + |
| + args[0] = (unsigned long) prom_callmethod_name; |
| + args[1] = 7; |
| + args[2] = 2; |
| + args[3] = (unsigned long) "SUNW,get-unumber"; |
| + args[4] = (unsigned int) prom_get_memory_ihandle(); |
| + args[5] = buflen; |
| + args[6] = (unsigned long) buf; |
| + args[7] = 0; |
| + args[8] = phys_addr; |
| + args[9] = (unsigned int) syndrome_code; |
| + args[10] = (unsigned long) -1; |
| + args[11] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[10]; |
| } |
| |
| /* Power management extensions. */ |
| void prom_sleepself(void) |
| { |
| - p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); |
| + unsigned long args[3]; |
| + |
| + args[0] = (unsigned long) "SUNW,sleep-self"; |
| + args[1] = 0; |
| + args[2] = 0; |
| + p1275_cmd_direct(args); |
| } |
| |
| int prom_sleepsystem(void) |
| { |
| - return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); |
| + unsigned long args[4]; |
| + |
| + args[0] = (unsigned long) "SUNW,sleep-system"; |
| + args[1] = 0; |
| + args[2] = 1; |
| + args[3] = (unsigned long) -1; |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[3]; |
| } |
| |
| int prom_wakeupsystem(void) |
| { |
| - return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); |
| + unsigned long args[4]; |
| + |
| + args[0] = (unsigned long) "SUNW,wakeup-system"; |
| + args[1] = 0; |
| + args[2] = 1; |
| + args[3] = (unsigned long) -1; |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[3]; |
| } |
| |
| #ifdef CONFIG_SMP |
| void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg) |
| { |
| - p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg); |
| + unsigned long args[6]; |
| + |
| + args[0] = (unsigned long) "SUNW,start-cpu"; |
| + args[1] = 3; |
| + args[2] = 0; |
| + args[3] = (unsigned int) cpunode; |
| + args[4] = pc; |
| + args[5] = arg; |
| + p1275_cmd_direct(args); |
| } |
| |
| void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg) |
| { |
| - p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0), |
| - cpuid, pc, arg); |
| + unsigned long args[6]; |
| + |
| + args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid"; |
| + args[1] = 3; |
| + args[2] = 0; |
| + args[3] = (unsigned int) cpuid; |
| + args[4] = pc; |
| + args[5] = arg; |
| + p1275_cmd_direct(args); |
| } |
| |
| void prom_stopcpu_cpuid(int cpuid) |
| { |
| - p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0), |
| - cpuid); |
| + unsigned long args[4]; |
| + |
| + args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid"; |
| + args[1] = 1; |
| + args[2] = 0; |
| + args[3] = (unsigned int) cpuid; |
| + p1275_cmd_direct(args); |
| } |
| |
| void prom_stopself(void) |
| { |
| - p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); |
| + unsigned long args[3]; |
| + |
| + args[0] = (unsigned long) "SUNW,stop-self"; |
| + args[1] = 0; |
| + args[2] = 0; |
| + p1275_cmd_direct(args); |
| } |
| |
| void prom_idleself(void) |
| { |
| - p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); |
| + unsigned long args[3]; |
| + |
| + args[0] = (unsigned long) "SUNW,idle-self"; |
| + args[1] = 0; |
| + args[2] = 0; |
| + p1275_cmd_direct(args); |
| } |
| |
| void prom_resumecpu(int cpunode) |
| { |
| - p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); |
| + unsigned long args[4]; |
| + |
| + args[0] = (unsigned long) "SUNW,resume-cpu"; |
| + args[1] = 1; |
| + args[2] = 0; |
| + args[3] = (unsigned int) cpunode; |
| + p1275_cmd_direct(args); |
| } |
| #endif |
| --- a/arch/sparc/prom/p1275.c |
| +++ b/arch/sparc/prom/p1275.c |
| @@ -22,13 +22,11 @@ struct { |
| long prom_callback; /* 0x00 */ |
| void (*prom_cif_handler)(long *); /* 0x08 */ |
| unsigned long prom_cif_stack; /* 0x10 */ |
| - unsigned long prom_args [23]; /* 0x18 */ |
| - char prom_buffer [3000]; |
| } p1275buf; |
| |
| extern void prom_world(int); |
| |
| -extern void prom_cif_interface(void); |
| +extern void prom_cif_direct(unsigned long *args); |
| extern void prom_cif_callback(void); |
| |
| /* |
| @@ -36,114 +34,20 @@ extern void prom_cif_callback(void); |
| */ |
| DEFINE_SPINLOCK(prom_entry_lock); |
| |
| -long p1275_cmd(const char *service, long fmt, ...) |
| +void p1275_cmd_direct(unsigned long *args) |
| { |
| - char *p, *q; |
| unsigned long flags; |
| - int nargs, nrets, i; |
| - va_list list; |
| - long attrs, x; |
| - |
| - p = p1275buf.prom_buffer; |
| |
| raw_local_save_flags(flags); |
| raw_local_irq_restore(PIL_NMI); |
| spin_lock(&prom_entry_lock); |
| |
| - p1275buf.prom_args[0] = (unsigned long)p; /* service */ |
| - strcpy (p, service); |
| - p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); |
| - p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ |
| - p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ |
| - attrs = fmt >> 8; |
| - va_start(list, fmt); |
| - for (i = 0; i < nargs; i++, attrs >>= 3) { |
| - switch (attrs & 0x7) { |
| - case P1275_ARG_NUMBER: |
| - p1275buf.prom_args[i + 3] = |
| - (unsigned)va_arg(list, long); |
| - break; |
| - case P1275_ARG_IN_64B: |
| - p1275buf.prom_args[i + 3] = |
| - va_arg(list, unsigned long); |
| - break; |
| - case P1275_ARG_IN_STRING: |
| - strcpy (p, va_arg(list, char *)); |
| - p1275buf.prom_args[i + 3] = (unsigned long)p; |
| - p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); |
| - break; |
| - case P1275_ARG_OUT_BUF: |
| - (void) va_arg(list, char *); |
| - p1275buf.prom_args[i + 3] = (unsigned long)p; |
| - x = va_arg(list, long); |
| - i++; attrs >>= 3; |
| - p = (char *)(((long)(p + (int)x + 7)) & ~7); |
| - p1275buf.prom_args[i + 3] = x; |
| - break; |
| - case P1275_ARG_IN_BUF: |
| - q = va_arg(list, char *); |
| - p1275buf.prom_args[i + 3] = (unsigned long)p; |
| - x = va_arg(list, long); |
| - i++; attrs >>= 3; |
| - memcpy (p, q, (int)x); |
| - p = (char *)(((long)(p + (int)x + 7)) & ~7); |
| - p1275buf.prom_args[i + 3] = x; |
| - break; |
| - case P1275_ARG_OUT_32B: |
| - (void) va_arg(list, char *); |
| - p1275buf.prom_args[i + 3] = (unsigned long)p; |
| - p += 32; |
| - break; |
| - case P1275_ARG_IN_FUNCTION: |
| - p1275buf.prom_args[i + 3] = |
| - (unsigned long)prom_cif_callback; |
| - p1275buf.prom_callback = va_arg(list, long); |
| - break; |
| - } |
| - } |
| - va_end(list); |
| - |
| prom_world(1); |
| - prom_cif_interface(); |
| + prom_cif_direct(args); |
| prom_world(0); |
| |
| - attrs = fmt >> 8; |
| - va_start(list, fmt); |
| - for (i = 0; i < nargs; i++, attrs >>= 3) { |
| - switch (attrs & 0x7) { |
| - case P1275_ARG_NUMBER: |
| - (void) va_arg(list, long); |
| - break; |
| - case P1275_ARG_IN_STRING: |
| - (void) va_arg(list, char *); |
| - break; |
| - case P1275_ARG_IN_FUNCTION: |
| - (void) va_arg(list, long); |
| - break; |
| - case P1275_ARG_IN_BUF: |
| - (void) va_arg(list, char *); |
| - (void) va_arg(list, long); |
| - i++; attrs >>= 3; |
| - break; |
| - case P1275_ARG_OUT_BUF: |
| - p = va_arg(list, char *); |
| - x = va_arg(list, long); |
| - memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x); |
| - i++; attrs >>= 3; |
| - break; |
| - case P1275_ARG_OUT_32B: |
| - p = va_arg(list, char *); |
| - memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32); |
| - break; |
| - } |
| - } |
| - va_end(list); |
| - x = p1275buf.prom_args [nargs + 3]; |
| - |
| spin_unlock(&prom_entry_lock); |
| raw_local_irq_restore(flags); |
| - |
| - return x; |
| } |
| |
| void prom_cif_init(void *cif_handler, void *cif_stack) |
| --- a/arch/sparc/prom/tree_64.c |
| +++ b/arch/sparc/prom/tree_64.c |
| @@ -16,22 +16,39 @@ |
| #include <asm/oplib.h> |
| #include <asm/ldc.h> |
| |
| +static int prom_node_to_node(const char *type, int node) |
| +{ |
| + unsigned long args[5]; |
| + |
| + args[0] = (unsigned long) type; |
| + args[1] = 1; |
| + args[2] = 1; |
| + args[3] = (unsigned int) node; |
| + args[4] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[4]; |
| +} |
| + |
| /* Return the child of node 'node' or zero if no this node has no |
| * direct descendent. |
| */ |
| inline int __prom_getchild(int node) |
| { |
| - return p1275_cmd ("child", P1275_INOUT(1, 1), node); |
| + return prom_node_to_node("child", node); |
| } |
| |
| inline int prom_getchild(int node) |
| { |
| int cnode; |
| |
| - if(node == -1) return 0; |
| + if (node == -1) |
| + return 0; |
| cnode = __prom_getchild(node); |
| - if(cnode == -1) return 0; |
| - return (int)cnode; |
| + if (cnode == -1) |
| + return 0; |
| + return cnode; |
| } |
| EXPORT_SYMBOL(prom_getchild); |
| |
| @@ -39,10 +56,12 @@ inline int prom_getparent(int node) |
| { |
| int cnode; |
| |
| - if(node == -1) return 0; |
| - cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node); |
| - if(cnode == -1) return 0; |
| - return (int)cnode; |
| + if (node == -1) |
| + return 0; |
| + cnode = prom_node_to_node("parent", node); |
| + if (cnode == -1) |
| + return 0; |
| + return cnode; |
| } |
| |
| /* Return the next sibling of node 'node' or zero if no more siblings |
| @@ -50,7 +69,7 @@ inline int prom_getparent(int node) |
| */ |
| inline int __prom_getsibling(int node) |
| { |
| - return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node); |
| + return prom_node_to_node(prom_peer_name, node); |
| } |
| |
| inline int prom_getsibling(int node) |
| @@ -72,11 +91,21 @@ EXPORT_SYMBOL(prom_getsibling); |
| */ |
| inline int prom_getproplen(int node, const char *prop) |
| { |
| - if((!node) || (!prop)) return -1; |
| - return p1275_cmd ("getproplen", |
| - P1275_ARG(1,P1275_ARG_IN_STRING)| |
| - P1275_INOUT(2, 1), |
| - node, prop); |
| + unsigned long args[6]; |
| + |
| + if (!node || !prop) |
| + return -1; |
| + |
| + args[0] = (unsigned long) "getproplen"; |
| + args[1] = 2; |
| + args[2] = 1; |
| + args[3] = (unsigned int) node; |
| + args[4] = (unsigned long) prop; |
| + args[5] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[5]; |
| } |
| EXPORT_SYMBOL(prom_getproplen); |
| |
| @@ -87,19 +116,25 @@ EXPORT_SYMBOL(prom_getproplen); |
| inline int prom_getproperty(int node, const char *prop, |
| char *buffer, int bufsize) |
| { |
| + unsigned long args[8]; |
| int plen; |
| |
| plen = prom_getproplen(node, prop); |
| - if ((plen > bufsize) || (plen == 0) || (plen == -1)) { |
| + if ((plen > bufsize) || (plen == 0) || (plen == -1)) |
| return -1; |
| - } else { |
| - /* Ok, things seem all right. */ |
| - return p1275_cmd(prom_getprop_name, |
| - P1275_ARG(1,P1275_ARG_IN_STRING)| |
| - P1275_ARG(2,P1275_ARG_OUT_BUF)| |
| - P1275_INOUT(4, 1), |
| - node, prop, buffer, P1275_SIZE(plen)); |
| - } |
| + |
| + args[0] = (unsigned long) prom_getprop_name; |
| + args[1] = 4; |
| + args[2] = 1; |
| + args[3] = (unsigned int) node; |
| + args[4] = (unsigned long) prop; |
| + args[5] = (unsigned long) buffer; |
| + args[6] = bufsize; |
| + args[7] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[7]; |
| } |
| EXPORT_SYMBOL(prom_getproperty); |
| |
| @@ -110,7 +145,7 @@ inline int prom_getint(int node, const c |
| { |
| int intprop; |
| |
| - if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) |
| + if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) |
| return intprop; |
| |
| return -1; |
| @@ -126,7 +161,8 @@ int prom_getintdefault(int node, const c |
| int retval; |
| |
| retval = prom_getint(node, property); |
| - if(retval == -1) return deflt; |
| + if (retval == -1) |
| + return deflt; |
| |
| return retval; |
| } |
| @@ -138,7 +174,8 @@ int prom_getbool(int node, const char *p |
| int retval; |
| |
| retval = prom_getproplen(node, prop); |
| - if(retval == -1) return 0; |
| + if (retval == -1) |
| + return 0; |
| return 1; |
| } |
| EXPORT_SYMBOL(prom_getbool); |
| @@ -152,7 +189,8 @@ void prom_getstring(int node, const char |
| int len; |
| |
| len = prom_getproperty(node, prop, user_buf, ubuf_size); |
| - if(len != -1) return; |
| + if (len != -1) |
| + return; |
| user_buf[0] = 0; |
| return; |
| } |
| @@ -165,7 +203,8 @@ int prom_nodematch(int node, const char |
| { |
| char namebuf[128]; |
| prom_getproperty(node, "name", namebuf, sizeof(namebuf)); |
| - if(strcmp(namebuf, name) == 0) return 1; |
| + if (strcmp(namebuf, name) == 0) |
| + return 1; |
| return 0; |
| } |
| |
| @@ -191,16 +230,29 @@ int prom_searchsiblings(int node_start, |
| } |
| EXPORT_SYMBOL(prom_searchsiblings); |
| |
| +static const char *prom_nextprop_name = "nextprop"; |
| + |
| /* Return the first property type for node 'node'. |
| * buffer should be at least 32B in length |
| */ |
| inline char *prom_firstprop(int node, char *buffer) |
| { |
| + unsigned long args[7]; |
| + |
| *buffer = 0; |
| - if(node == -1) return buffer; |
| - p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)| |
| - P1275_INOUT(3, 0), |
| - node, (char *) 0x0, buffer); |
| + if (node == -1) |
| + return buffer; |
| + |
| + args[0] = (unsigned long) prom_nextprop_name; |
| + args[1] = 3; |
| + args[2] = 1; |
| + args[3] = (unsigned int) node; |
| + args[4] = 0; |
| + args[5] = (unsigned long) buffer; |
| + args[6] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| return buffer; |
| } |
| EXPORT_SYMBOL(prom_firstprop); |
| @@ -211,9 +263,10 @@ EXPORT_SYMBOL(prom_firstprop); |
| */ |
| inline char *prom_nextprop(int node, const char *oprop, char *buffer) |
| { |
| + unsigned long args[7]; |
| char buf[32]; |
| |
| - if(node == -1) { |
| + if (node == -1) { |
| *buffer = 0; |
| return buffer; |
| } |
| @@ -221,10 +274,17 @@ inline char *prom_nextprop(int node, con |
| strcpy (buf, oprop); |
| oprop = buf; |
| } |
| - p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)| |
| - P1275_ARG(2,P1275_ARG_OUT_32B)| |
| - P1275_INOUT(3, 0), |
| - node, oprop, buffer); |
| + |
| + args[0] = (unsigned long) prom_nextprop_name; |
| + args[1] = 3; |
| + args[2] = 1; |
| + args[3] = (unsigned int) node; |
| + args[4] = (unsigned long) oprop; |
| + args[5] = (unsigned long) buffer; |
| + args[6] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| return buffer; |
| } |
| EXPORT_SYMBOL(prom_nextprop); |
| @@ -232,12 +292,19 @@ EXPORT_SYMBOL(prom_nextprop); |
| int |
| prom_finddevice(const char *name) |
| { |
| + unsigned long args[5]; |
| + |
| if (!name) |
| return 0; |
| - return p1275_cmd(prom_finddev_name, |
| - P1275_ARG(0,P1275_ARG_IN_STRING)| |
| - P1275_INOUT(1, 1), |
| - name); |
| + args[0] = (unsigned long) "finddevice"; |
| + args[1] = 1; |
| + args[2] = 1; |
| + args[3] = (unsigned long) name; |
| + args[4] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[4]; |
| } |
| EXPORT_SYMBOL(prom_finddevice); |
| |
| @@ -248,7 +315,7 @@ int prom_node_has_property(int node, con |
| *buf = 0; |
| do { |
| prom_nextprop(node, buf, buf); |
| - if(!strcmp(buf, prop)) |
| + if (!strcmp(buf, prop)) |
| return 1; |
| } while (*buf); |
| return 0; |
| @@ -261,6 +328,8 @@ EXPORT_SYMBOL(prom_node_has_property); |
| int |
| prom_setprop(int node, const char *pname, char *value, int size) |
| { |
| + unsigned long args[8]; |
| + |
| if (size == 0) |
| return 0; |
| if ((pname == 0) || (value == 0)) |
| @@ -272,19 +341,37 @@ prom_setprop(int node, const char *pname |
| return 0; |
| } |
| #endif |
| - return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| |
| - P1275_ARG(2,P1275_ARG_IN_BUF)| |
| - P1275_INOUT(4, 1), |
| - node, pname, value, P1275_SIZE(size)); |
| + args[0] = (unsigned long) "setprop"; |
| + args[1] = 4; |
| + args[2] = 1; |
| + args[3] = (unsigned int) node; |
| + args[4] = (unsigned long) pname; |
| + args[5] = (unsigned long) value; |
| + args[6] = size; |
| + args[7] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[7]; |
| } |
| EXPORT_SYMBOL(prom_setprop); |
| |
| inline int prom_inst2pkg(int inst) |
| { |
| + unsigned long args[5]; |
| int node; |
| |
| - node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst); |
| - if (node == -1) return 0; |
| + args[0] = (unsigned long) "instance-to-package"; |
| + args[1] = 1; |
| + args[2] = 1; |
| + args[3] = (unsigned int) inst; |
| + args[4] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + node = (int) args[4]; |
| + if (node == -1) |
| + return 0; |
| return node; |
| } |
| |
| @@ -297,17 +384,28 @@ prom_pathtoinode(const char *path) |
| int node, inst; |
| |
| inst = prom_devopen (path); |
| - if (inst == 0) return 0; |
| - node = prom_inst2pkg (inst); |
| - prom_devclose (inst); |
| - if (node == -1) return 0; |
| + if (inst == 0) |
| + return 0; |
| + node = prom_inst2pkg(inst); |
| + prom_devclose(inst); |
| + if (node == -1) |
| + return 0; |
| return node; |
| } |
| |
| int prom_ihandle2path(int handle, char *buffer, int bufsize) |
| { |
| - return p1275_cmd("instance-to-path", |
| - P1275_ARG(1,P1275_ARG_OUT_BUF)| |
| - P1275_INOUT(3, 1), |
| - handle, buffer, P1275_SIZE(bufsize)); |
| + unsigned long args[7]; |
| + |
| + args[0] = (unsigned long) "instance-to-path"; |
| + args[1] = 3; |
| + args[2] = 1; |
| + args[3] = (unsigned int) handle; |
| + args[4] = (unsigned long) buffer; |
| + args[5] = bufsize; |
| + args[6] = (unsigned long) -1; |
| + |
| + p1275_cmd_direct(args); |
| + |
| + return (int) args[6]; |
| } |