15de18cdeSSam Ravnborg /* 25de18cdeSSam Ravnborg * p1275.c: Sun IEEE 1275 PROM low level interface routines 35de18cdeSSam Ravnborg * 45de18cdeSSam Ravnborg * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 55de18cdeSSam Ravnborg */ 65de18cdeSSam Ravnborg 75de18cdeSSam Ravnborg #include <linux/kernel.h> 85de18cdeSSam Ravnborg #include <linux/init.h> 95de18cdeSSam Ravnborg #include <linux/sched.h> 105de18cdeSSam Ravnborg #include <linux/smp.h> 115de18cdeSSam Ravnborg #include <linux/string.h> 125de18cdeSSam Ravnborg #include <linux/spinlock.h> 135de18cdeSSam Ravnborg 145de18cdeSSam Ravnborg #include <asm/openprom.h> 155de18cdeSSam Ravnborg #include <asm/oplib.h> 165de18cdeSSam Ravnborg #include <asm/system.h> 175de18cdeSSam Ravnborg #include <asm/spitfire.h> 185de18cdeSSam Ravnborg #include <asm/pstate.h> 195de18cdeSSam Ravnborg #include <asm/ldc.h> 205de18cdeSSam Ravnborg 215de18cdeSSam Ravnborg struct { 225de18cdeSSam Ravnborg long prom_callback; /* 0x00 */ 235de18cdeSSam Ravnborg void (*prom_cif_handler)(long *); /* 0x08 */ 245de18cdeSSam Ravnborg unsigned long prom_cif_stack; /* 0x10 */ 255de18cdeSSam Ravnborg unsigned long prom_args [23]; /* 0x18 */ 265de18cdeSSam Ravnborg char prom_buffer [3000]; 275de18cdeSSam Ravnborg } p1275buf; 285de18cdeSSam Ravnborg 295de18cdeSSam Ravnborg extern void prom_world(int); 305de18cdeSSam Ravnborg 315de18cdeSSam Ravnborg extern void prom_cif_interface(void); 325de18cdeSSam Ravnborg extern void prom_cif_callback(void); 335de18cdeSSam Ravnborg 345de18cdeSSam Ravnborg /* 35*8a4fd1e4SDavid S. Miller * This provides SMP safety on the p1275buf. 365de18cdeSSam Ravnborg */ 37*8a4fd1e4SDavid S. Miller DEFINE_RAW_SPINLOCK(prom_entry_lock); 385de18cdeSSam Ravnborg 395de18cdeSSam Ravnborg long p1275_cmd(const char *service, long fmt, ...) 405de18cdeSSam Ravnborg { 415de18cdeSSam Ravnborg char *p, *q; 425de18cdeSSam Ravnborg unsigned long flags; 435de18cdeSSam Ravnborg int nargs, nrets, i; 445de18cdeSSam Ravnborg va_list list; 455de18cdeSSam Ravnborg long attrs, x; 465de18cdeSSam Ravnborg 475de18cdeSSam Ravnborg p = p1275buf.prom_buffer; 485de18cdeSSam Ravnborg 49*8a4fd1e4SDavid S. Miller raw_local_save_flags(flags); 50*8a4fd1e4SDavid S. Miller raw_local_irq_restore(PIL_NMI); 51*8a4fd1e4SDavid S. Miller raw_spin_lock(&prom_entry_lock); 525de18cdeSSam Ravnborg 535de18cdeSSam Ravnborg p1275buf.prom_args[0] = (unsigned long)p; /* service */ 545de18cdeSSam Ravnborg strcpy (p, service); 555de18cdeSSam Ravnborg p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); 565de18cdeSSam Ravnborg p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ 575de18cdeSSam Ravnborg p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ 585de18cdeSSam Ravnborg attrs = fmt >> 8; 595de18cdeSSam Ravnborg va_start(list, fmt); 605de18cdeSSam Ravnborg for (i = 0; i < nargs; i++, attrs >>= 3) { 615de18cdeSSam Ravnborg switch (attrs & 0x7) { 625de18cdeSSam Ravnborg case P1275_ARG_NUMBER: 635de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = 645de18cdeSSam Ravnborg (unsigned)va_arg(list, long); 655de18cdeSSam Ravnborg break; 665de18cdeSSam Ravnborg case P1275_ARG_IN_64B: 675de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = 685de18cdeSSam Ravnborg va_arg(list, unsigned long); 695de18cdeSSam Ravnborg break; 705de18cdeSSam Ravnborg case P1275_ARG_IN_STRING: 715de18cdeSSam Ravnborg strcpy (p, va_arg(list, char *)); 725de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = (unsigned long)p; 735de18cdeSSam Ravnborg p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); 745de18cdeSSam Ravnborg break; 755de18cdeSSam Ravnborg case P1275_ARG_OUT_BUF: 765de18cdeSSam Ravnborg (void) va_arg(list, char *); 775de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = (unsigned long)p; 785de18cdeSSam Ravnborg x = va_arg(list, long); 795de18cdeSSam Ravnborg i++; attrs >>= 3; 805de18cdeSSam Ravnborg p = (char *)(((long)(p + (int)x + 7)) & ~7); 815de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = x; 825de18cdeSSam Ravnborg break; 835de18cdeSSam Ravnborg case P1275_ARG_IN_BUF: 845de18cdeSSam Ravnborg q = va_arg(list, char *); 855de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = (unsigned long)p; 865de18cdeSSam Ravnborg x = va_arg(list, long); 875de18cdeSSam Ravnborg i++; attrs >>= 3; 885de18cdeSSam Ravnborg memcpy (p, q, (int)x); 895de18cdeSSam Ravnborg p = (char *)(((long)(p + (int)x + 7)) & ~7); 905de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = x; 915de18cdeSSam Ravnborg break; 925de18cdeSSam Ravnborg case P1275_ARG_OUT_32B: 935de18cdeSSam Ravnborg (void) va_arg(list, char *); 945de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = (unsigned long)p; 955de18cdeSSam Ravnborg p += 32; 965de18cdeSSam Ravnborg break; 975de18cdeSSam Ravnborg case P1275_ARG_IN_FUNCTION: 985de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = 995de18cdeSSam Ravnborg (unsigned long)prom_cif_callback; 1005de18cdeSSam Ravnborg p1275buf.prom_callback = va_arg(list, long); 1015de18cdeSSam Ravnborg break; 1025de18cdeSSam Ravnborg } 1035de18cdeSSam Ravnborg } 1045de18cdeSSam Ravnborg va_end(list); 1055de18cdeSSam Ravnborg 1065de18cdeSSam Ravnborg prom_world(1); 1075de18cdeSSam Ravnborg prom_cif_interface(); 1085de18cdeSSam Ravnborg prom_world(0); 1095de18cdeSSam Ravnborg 1105de18cdeSSam Ravnborg attrs = fmt >> 8; 1115de18cdeSSam Ravnborg va_start(list, fmt); 1125de18cdeSSam Ravnborg for (i = 0; i < nargs; i++, attrs >>= 3) { 1135de18cdeSSam Ravnborg switch (attrs & 0x7) { 1145de18cdeSSam Ravnborg case P1275_ARG_NUMBER: 1155de18cdeSSam Ravnborg (void) va_arg(list, long); 1165de18cdeSSam Ravnborg break; 1175de18cdeSSam Ravnborg case P1275_ARG_IN_STRING: 1185de18cdeSSam Ravnborg (void) va_arg(list, char *); 1195de18cdeSSam Ravnborg break; 1205de18cdeSSam Ravnborg case P1275_ARG_IN_FUNCTION: 1215de18cdeSSam Ravnborg (void) va_arg(list, long); 1225de18cdeSSam Ravnborg break; 1235de18cdeSSam Ravnborg case P1275_ARG_IN_BUF: 1245de18cdeSSam Ravnborg (void) va_arg(list, char *); 1255de18cdeSSam Ravnborg (void) va_arg(list, long); 1265de18cdeSSam Ravnborg i++; attrs >>= 3; 1275de18cdeSSam Ravnborg break; 1285de18cdeSSam Ravnborg case P1275_ARG_OUT_BUF: 1295de18cdeSSam Ravnborg p = va_arg(list, char *); 1305de18cdeSSam Ravnborg x = va_arg(list, long); 1315de18cdeSSam Ravnborg memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x); 1325de18cdeSSam Ravnborg i++; attrs >>= 3; 1335de18cdeSSam Ravnborg break; 1345de18cdeSSam Ravnborg case P1275_ARG_OUT_32B: 1355de18cdeSSam Ravnborg p = va_arg(list, char *); 1365de18cdeSSam Ravnborg memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32); 1375de18cdeSSam Ravnborg break; 1385de18cdeSSam Ravnborg } 1395de18cdeSSam Ravnborg } 1405de18cdeSSam Ravnborg va_end(list); 1415de18cdeSSam Ravnborg x = p1275buf.prom_args [nargs + 3]; 1425de18cdeSSam Ravnborg 143*8a4fd1e4SDavid S. Miller raw_spin_unlock(&prom_entry_lock); 144*8a4fd1e4SDavid S. Miller raw_local_irq_restore(flags); 1455de18cdeSSam Ravnborg 1465de18cdeSSam Ravnborg return x; 1475de18cdeSSam Ravnborg } 1485de18cdeSSam Ravnborg 1495de18cdeSSam Ravnborg void prom_cif_init(void *cif_handler, void *cif_stack) 1505de18cdeSSam Ravnborg { 1515de18cdeSSam Ravnborg p1275buf.prom_cif_handler = (void (*)(long *))cif_handler; 1525de18cdeSSam Ravnborg p1275buf.prom_cif_stack = (unsigned long)cif_stack; 1535de18cdeSSam Ravnborg } 154