diff --git b/arch/sparc/include/asm/oplib_64.h a/arch/sparc/include/asm/oplib_64.h
index 3e0b2d6..a5db031 100644
--- b/arch/sparc/include/asm/oplib_64.h
+++ a/arch/sparc/include/asm/oplib_64.h
@@ -185,8 +185,9 @@ extern int prom_getunumber(int syndrome_code,
 			   char *buf, int buflen);
 
 /* Retain physical memory to the caller across soft resets. */
-extern int prom_retain(const char *name, unsigned long size,
-		       unsigned long align, unsigned long *paddr);
+extern unsigned long prom_retain(const char *name,
+				 unsigned long pa_low, unsigned long pa_high,
+				 long size, long align);
 
 /* Load explicit I/D TLB entries into the calling processor. */
 extern long prom_itlb_load(unsigned long index,
@@ -286,6 +287,26 @@ extern void prom_sun4v_guest_soft_state(void);
 extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
 
 /* Client interface level routines. */
-extern void p1275_cmd_direct(unsigned long *);
+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))
 
 #endif /* !(__SPARC64_OPLIB_H) */
diff --git b/arch/sparc/prom/cif.S a/arch/sparc/prom/cif.S
index 9c86b4b..5f27ad7 100644
--- b/arch/sparc/prom/cif.S
+++ a/arch/sparc/prom/cif.S
@@ -9,18 +9,18 @@
 #include <asm/thread_info.h>
 
 	.text
-	.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
+	.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
 	mov	%g4, %l0
 	mov	%g5, %l1
 	mov	%g6, %l3
 	call	%l2
-	 mov	%i0, %o0		! prom_args
+	 add	%i0, 0x018, %o0		! prom_args
 	mov	%l0, %g4
 	mov	%l1, %g5
 	mov	%l3, %g6
diff --git b/arch/sparc/prom/console_64.c a/arch/sparc/prom/console_64.c
index 10322dc..f55d58a 100644
--- b/arch/sparc/prom/console_64.c
+++ a/arch/sparc/prom/console_64.c
@@ -21,22 +21,14 @@ extern int prom_stdin, prom_stdout;
 inline int
 prom_nbgetchar(void)
 {
-	unsigned long args[7];
 	char inc;
 
-	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)
+	if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)|
+			      P1275_INOUT(3,1),
+			      prom_stdin, &inc, P1275_SIZE(1)) == 1)
 		return inc;
-	return -1;
+	else
+		return -1;
 }
 
 /* Non blocking put character to console device, returns -1 if
@@ -45,22 +37,12 @@ prom_nbgetchar(void)
 inline int
 prom_nbputchar(char c)
 {
-	unsigned long args[7];
 	char outc;
 	
 	outc = c;
-
-	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)
+	if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
+			       P1275_INOUT(3,1),
+			       prom_stdout, &outc, P1275_SIZE(1)) == 1)
 		return 0;
 	else
 		return -1;
@@ -85,15 +67,7 @@ prom_putchar(char c)
 void
 prom_puts(const char *s, int 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);
+	p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
+			   P1275_INOUT(3,1),
+			   prom_stdout, s, P1275_SIZE(len));
 }
diff --git b/arch/sparc/prom/devops_64.c a/arch/sparc/prom/devops_64.c
index a017119..9dbd803 100644
--- b/arch/sparc/prom/devops_64.c
+++ a/arch/sparc/prom/devops_64.c
@@ -18,32 +18,16 @@
 int
 prom_devopen(const char *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];
+	return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)|
+				  P1275_INOUT(1,1),
+				  dstr);
 }
 
 /* Close the device described by device handle 'dhandle'. */
 int
 prom_devclose(int 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);
-
+	p1275_cmd ("close", P1275_INOUT(1,0), dhandle);
 	return 0;
 }
 
@@ -53,15 +37,5 @@ prom_devclose(int dhandle)
 void
 prom_seek(int dhandle, unsigned int seekhi, unsigned int 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);
+	p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo);
 }
diff --git b/arch/sparc/prom/misc_64.c a/arch/sparc/prom/misc_64.c
index 6cb1581..39fc6af 100644
--- b/arch/sparc/prom/misc_64.c
+++ a/arch/sparc/prom/misc_64.c
@@ -20,17 +20,10 @@
 
 int prom_service_exists(const char *service_name)
 {
-	unsigned long args[5];
+	int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) |
+			    P1275_INOUT(1, 1), service_name);
 
-	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])
+	if (err)
 		return 0;
 	return 1;
 }
@@ -38,47 +31,30 @@ int prom_service_exists(const char *service_name)
 void prom_sun4v_guest_soft_state(void)
 {
 	const char *svc = "SUNW,soft-state-supported";
-	unsigned long args[3];
 
 	if (!prom_service_exists(svc))
 		return;
-	args[0] = (unsigned long) svc;
-	args[1] = 0;
-	args[2] = 0;
-	p1275_cmd_direct(args);
+	p1275_cmd(svc, P1275_INOUT(0, 0));
 }
 
 /* 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
-	args[0] = (unsigned long) "boot";
-	args[1] = 1;
-	args[2] = 0;
-	args[3] = (unsigned long) bcommand;
-
-	p1275_cmd_direct(args);
+	p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
+		  P1275_INOUT(1, 0), bcommand);
 }
 
 /* Forth evaluate the expression contained in 'fstring'. */
 void prom_feval(const char *fstring)
 {
-	unsigned long args[5];
-
 	if (!fstring || fstring[0] == 0)
 		return;
-	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);
+	p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) |
+		  P1275_INOUT(1, 1), fstring);
 }
 EXPORT_SYMBOL(prom_feval);
 
@@ -92,7 +68,6 @@ extern void smp_release(void);
  */
 void prom_cmdline(void)
 {
-	unsigned long args[3];
 	unsigned long flags;
 
 	local_irq_save(flags);
@@ -101,11 +76,7 @@ void prom_cmdline(void)
 	smp_capture();
 #endif
 
-	args[0] = (unsigned long) "enter";
-	args[1] = 0;
-	args[2] = 0;
-
-	p1275_cmd_direct(args);
+	p1275_cmd("enter", P1275_INOUT(0, 0));
 
 #ifdef CONFIG_SMP
 	smp_release();
@@ -119,32 +90,22 @@ 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:
-	args[0] = (unsigned long) "exit";
-	args[1] = 0;
-	args[2] = 0;
-	p1275_cmd_direct(args);
+	p1275_cmd("exit", P1275_INOUT(0, 0));
 	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
-	args[0] = (unsigned long) "SUNW,power-off";
-	args[1] = 0;
-	args[2] = 0;
-	p1275_cmd_direct(args);
+	p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
 
 	/* if nothing else helps, we just halt */
 	prom_halt();
@@ -153,15 +114,10 @@ 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;
-	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);
+	p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) |
+		  P1275_INOUT(1, 1), funcp);
 }
 
 /* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
@@ -217,61 +173,57 @@ 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 tlb_load("SUNW,itlb-load", index, tte_data, 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);
 }
 
 long prom_dtlb_load(unsigned long index,
 		    unsigned long tte_data,
 		    unsigned long vaddr)
 {
-	return tlb_load("SUNW,dtlb-load", index, tte_data, 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);
 }
 
 int prom_map(int mode, unsigned long size,
 	     unsigned long vaddr, unsigned long 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];
+	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);
+
 	if (ret == 0)
 		ret = -1;
 	return ret;
@@ -279,51 +231,40 @@ int prom_map(int mode, unsigned long size,
 
 void prom_unmap(unsigned long size, unsigned long 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);
+	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);
 }
 
 /* Set aside physical memory which is not touched or modified
  * across soft resets.
  */
-int prom_retain(const char *name, unsigned long size,
-		unsigned long align, unsigned long *paddr)
+unsigned long prom_retain(const char *name,
+			  unsigned long pa_low, unsigned long pa_high,
+			  long size, long align)
 {
-	unsigned long args[11];
-
-	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.
+	/* XXX I don't think we return multiple values correctly.
+	 * XXX OBP supposedly returns pa_low/pa_high here, how does
+	 * XXX it work?
 	 */
-	*paddr = args[10];
 
-	return 0;
+	/* If align is zero, the pa_low/pa_high args are passed,
+	 * else they are not.
+	 */
+	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);
 }
 
 /* Get "Unumber" string for the SIMM at the given
@@ -336,129 +277,62 @@ int prom_getunumber(int syndrome_code,
 		    unsigned long phys_addr,
 		    char *buf, int buflen)
 {
-	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];
+	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);
 }
 
 /* Power management extensions. */
 void prom_sleepself(void)
 {
-	unsigned long args[3];
-
-	args[0] = (unsigned long) "SUNW,sleep-self";
-	args[1] = 0;
-	args[2] = 0;
-	p1275_cmd_direct(args);
+	p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
 }
 
 int prom_sleepsystem(void)
 {
-	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];
+	return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
 }
 
 int prom_wakeupsystem(void)
 {
-	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];
+	return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
 }
 
 #ifdef CONFIG_SMP
 void prom_startcpu(int cpunode, unsigned long pc, unsigned long 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);
+	p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg);
 }
 
 void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long 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);
+	p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0),
+		  cpuid, pc, arg);
 }
 
 void prom_stopcpu_cpuid(int 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);
+	p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0),
+		  cpuid);
 }
 
 void prom_stopself(void)
 {
-	unsigned long args[3];
-
-	args[0] = (unsigned long) "SUNW,stop-self";
-	args[1] = 0;
-	args[2] = 0;
-	p1275_cmd_direct(args);
+	p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
 }
 
 void prom_idleself(void)
 {
-	unsigned long args[3];
-
-	args[0] = (unsigned long) "SUNW,idle-self";
-	args[1] = 0;
-	args[2] = 0;
-	p1275_cmd_direct(args);
+	p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
 }
 
 void prom_resumecpu(int 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);
+	p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
 }
 #endif
diff --git b/arch/sparc/prom/p1275.c a/arch/sparc/prom/p1275.c
index fa6e4e2..2d8b70d 100644
--- b/arch/sparc/prom/p1275.c
+++ a/arch/sparc/prom/p1275.c
@@ -22,11 +22,13 @@ 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_direct(unsigned long *args);
+extern void prom_cif_interface(void);
 extern void prom_cif_callback(void);
 
 /*
@@ -34,20 +36,114 @@ extern void prom_cif_callback(void);
  */
 DEFINE_RAW_SPINLOCK(prom_entry_lock);
 
-void p1275_cmd_direct(unsigned long *args)
+long p1275_cmd(const char *service, long fmt, ...)
 {
+	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);
 	raw_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_direct(args);
+	prom_cif_interface();
 	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];
+
 	raw_spin_unlock(&prom_entry_lock);
 	raw_local_irq_restore(flags);
+
+	return x;
 }
 
 void prom_cif_init(void *cif_handler, void *cif_stack)
diff --git b/arch/sparc/prom/tree_64.c a/arch/sparc/prom/tree_64.c
index 9d3f913..3c0d2dd 100644
--- b/arch/sparc/prom/tree_64.c
+++ a/arch/sparc/prom/tree_64.c
@@ -16,39 +16,22 @@
 #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 prom_node_to_node("child", node);
+	return p1275_cmd ("child", P1275_INOUT(1, 1), 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 cnode;
+	if(cnode == -1) return 0;
+	return (int)cnode;
 }
 EXPORT_SYMBOL(prom_getchild);
 
@@ -56,12 +39,10 @@ inline int prom_getparent(int node)
 {
 	int cnode;
 
-	if (node == -1)
-		return 0;
-	cnode = prom_node_to_node("parent", node);
-	if (cnode == -1)
-		return 0;
-	return cnode;
+	if(node == -1) return 0;
+	cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
+	if(cnode == -1) return 0;
+	return (int)cnode;
 }
 
 /* Return the next sibling of node 'node' or zero if no more siblings
@@ -69,7 +50,7 @@ inline int prom_getparent(int node)
  */
 inline int __prom_getsibling(int node)
 {
-	return prom_node_to_node(prom_peer_name, node);
+	return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node);
 }
 
 inline int prom_getsibling(int node)
@@ -91,21 +72,11 @@ EXPORT_SYMBOL(prom_getsibling);
  */
 inline int prom_getproplen(int node, const char *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];
+	if((!node) || (!prop)) return -1;
+	return p1275_cmd ("getproplen", 
+			  P1275_ARG(1,P1275_ARG_IN_STRING)|
+			  P1275_INOUT(2, 1), 
+			  node, prop);
 }
 EXPORT_SYMBOL(prom_getproplen);
 
@@ -116,25 +87,19 @@ 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;
-
-	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];
+	} 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));
+	}
 }
 EXPORT_SYMBOL(prom_getproperty);
 
@@ -145,7 +110,7 @@ inline int prom_getint(int node, const char *prop)
 {
 	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;
@@ -161,8 +126,7 @@ int prom_getintdefault(int node, const char *property, int deflt)
 	int retval;
 
 	retval = prom_getint(node, property);
-	if (retval == -1)
-		return deflt;
+	if(retval == -1) return deflt;
 
 	return retval;
 }
@@ -174,8 +138,7 @@ int prom_getbool(int node, const char *prop)
 	int retval;
 
 	retval = prom_getproplen(node, prop);
-	if (retval == -1)
-		return 0;
+	if(retval == -1) return 0;
 	return 1;
 }
 EXPORT_SYMBOL(prom_getbool);
@@ -189,8 +152,7 @@ void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size)
 	int len;
 
 	len = prom_getproperty(node, prop, user_buf, ubuf_size);
-	if (len != -1)
-		return;
+	if(len != -1) return;
 	user_buf[0] = 0;
 }
 EXPORT_SYMBOL(prom_getstring);
@@ -202,8 +164,7 @@ int prom_nodematch(int node, const char *name)
 {
 	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;
 }
 
@@ -229,29 +190,16 @@ int prom_searchsiblings(int node_start, const char *nodename)
 }
 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;
-
-	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);
-
+	if(node == -1) return buffer;
+	p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)|
+			       P1275_INOUT(3, 0), 
+			       node, (char *) 0x0, buffer);
 	return buffer;
 }
 EXPORT_SYMBOL(prom_firstprop);
@@ -262,10 +210,9 @@ 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;
 	}
@@ -273,17 +220,10 @@ inline char *prom_nextprop(int node, const char *oprop, char *buffer)
 		strcpy (buf, oprop);
 		oprop = buf;
 	}
-
-	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);
-
+	p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
+				    P1275_ARG(2,P1275_ARG_OUT_32B)|
+				    P1275_INOUT(3, 0), 
+				    node, oprop, buffer); 
 	return buffer;
 }
 EXPORT_SYMBOL(prom_nextprop);
@@ -291,19 +231,12 @@ EXPORT_SYMBOL(prom_nextprop);
 int
 prom_finddevice(const char *name)
 {
-	unsigned long args[5];
-
 	if (!name)
 		return 0;
-	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];
+	return p1275_cmd(prom_finddev_name,
+			 P1275_ARG(0,P1275_ARG_IN_STRING)|
+			 P1275_INOUT(1, 1), 
+			 name);
 }
 EXPORT_SYMBOL(prom_finddevice);
 
@@ -314,7 +247,7 @@ int prom_node_has_property(int node, const char *prop)
 	*buf = 0;
 	do {
 		prom_nextprop(node, buf, buf);
-		if (!strcmp(buf, prop))
+		if(!strcmp(buf, prop))
 			return 1;
 	} while (*buf);
 	return 0;
@@ -327,8 +260,6 @@ 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))
@@ -340,37 +271,19 @@ prom_setprop(int node, const char *pname, char *value, int size)
 		return 0;
 	}
 #endif
-	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];
+	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));
 }
 EXPORT_SYMBOL(prom_setprop);
 
 inline int prom_inst2pkg(int inst)
 {
-	unsigned long args[5];
 	int node;
 	
-	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;
+	node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst);
+	if (node == -1) return 0;
 	return node;
 }
 
@@ -383,28 +296,17 @@ 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)
 {
-	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];
+	return p1275_cmd("instance-to-path",
+			 P1275_ARG(1,P1275_ARG_OUT_BUF)|
+			 P1275_INOUT(3, 1),
+			 handle, buffer, P1275_SIZE(bufsize));
 }
