/* * Allocate physical memory, unmapped and possibly aligned. * Returns 0: Success; Non-zero: failure. * Returns *physaddr only if successful. * * This routine is suitable for platforms with 2-cell physical addresses * and a single size cell in the "memory" node. */ int prom_allocate_phys(size_t size, uint32_t align, u_longlong_t *physaddr) { cell_t ci[10]; int32_t rv; ihandle_t imemory = prom_memory_ihandle(); if ((imemory == (ihandle_t)-1)) return (-1); if (align == 0) align = (uint32_t)1; ci[0] = p1275_ptr2cell("call-method"); /* Service name */ ci[1] = (cell_t)4; /* #argument cells */ ci[2] = (cell_t)3; /* #result cells */ ci[3] = p1275_ptr2cell("claim"); /* Arg1: Method name */ ci[4] = p1275_ihandle2cell(imemory); /* Arg2: memory ihandle */ ci[5] = p1275_uint2cell(align); /* Arg3: SA1: align */ ci[6] = p1275_size2cell(size); /* Arg4: SA2: size */ rv = p1275_cif_handler(&ci); if (rv != 0) return (rv); if (p1275_cell2int(ci[7]) != 0) /* Res1: Catch result */ return (-1); *physaddr = p1275_cells2ull(ci[8], ci[9]); /* Res2: SR1: phys.hi ... Res3: SR2: phys.lo */ return (0); }
int prom_pathname(char *pathname) { char *from = buffer; char *to = pathname; cell_t ci[7]; if ((to == (char *)0) || (*to == (char)0)) return; (void) prom_strcpy(from, to); *to = (char)0; ci[0] = p1275_ptr2cell("canon"); /* Service name */ ci[1] = (cell_t)3; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_ptr2cell(from); /* Arg1: device specifier */ ci[4] = p1275_ptr2cell(to); /* Arg2: buffer address */ ci[5] = p1275_uint2cell(OBP_MAXPATHLEN); /* Arg3: buffer length */ ci[6] = (cell_t)-1; (void) p1275_cif_handler(&ci); return (p1275_cell2int(ci[6])); /* Res1: length */ }
/* * Get Fcode into supplied buffer. */ int prom_get_fcode(char *str, char *buf) { cell_t ci[6]; int rv; if (prom_test("SUNW,get-fcode") != 0) { return (0); } ci[0] = p1275_ptr2cell("SUNW,get-fcode"); ci[1] = (cell_t)2; /* 2 input args: str + buf */ ci[2] = (cell_t)1; /* 1 output result: true or false */ ci[3] = p1275_ptr2cell(buf); /* Arg#1: buffer to put fcode */ ci[4] = p1275_ptr2cell(str); /* Arg#2: name of drop-in */ ci[5] = (cell_t)0; promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); if (rv == 0) return (p1275_cell2int(ci[5])); return (0); }
/* * Claim a region of physical memory, unmapped. * Returns 0: Success; Non-zero: failure. * * This routine is suitable for platforms with 2-cell physical addresses * and a single size cell in the "memory" node. */ int prom_claim_phys(size_t size, u_longlong_t physaddr) { cell_t ci[10]; int32_t rv; ihandle_t imemory = prom_memory_ihandle(); if ((imemory == (ihandle_t)-1)) return (-1); ci[0] = p1275_ptr2cell("call-method"); /* Service name */ ci[1] = (cell_t)6; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_ptr2cell("claim"); /* Arg1: Method name */ ci[4] = p1275_ihandle2cell(imemory); /* Arg2: mmu ihandle */ ci[5] = 0; /* Arg3: SA1: align */ ci[6] = p1275_size2cell(size); /* Arg4: SA2: len */ ci[7] = p1275_ull2cell_high(physaddr); /* Arg5: SA3: phys.hi */ ci[8] = p1275_ull2cell_low(physaddr); /* Arg6: SA4: phys.lo */ rv = p1275_cif_handler(&ci); if (rv != 0) return (rv); if (p1275_cell2int(ci[9]) != 0) /* Res1: Catch result */ return (-1); return (0); }
int p1275_ppc_cif_handler(void *p) { cell_t rv; if (cif_handler == NULL) return (-1); rv = (*cif_handler)(p); return (p1275_cell2int(rv)); }
/* * Request that OBP write 'len' bytes from the memory indicated by 'buf' into * the IOSRAM chunk associated with 'key', starting at 'offset'. Although there * is a driver that provides this functionality, there are certain cases where * the OS requires access to IOSRAM before the driver is loaded. Return 0 on * success, non-zero on failure. */ int prom_starcat_iosram_write(uint32_t key, uint32_t offset, uint32_t len, caddr_t buf) { static uint8_t warned = 0; cell_t ci[8]; int rv; /* * Make sure we have the necessary support in OBP. */ if (prom_test(iosram_write_cmd) == 0) { ci[0] = p1275_ptr2cell(iosram_write_cmd); /* name */ } else { if (!warned) { warned = 1; prom_printf( "Warning: No prom support for iosram-write!\n"); } return (-1); } /* * Set up the arguments and call into OBP. Note that the argument order * needs to be reversed to accomodate OBP. The order must remain as it * is in the function prototype to maintain intercompatibility with the * IOSRAM driver's equivalent routine. */ ci[1] = (cell_t)4; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_ptr2cell(buf); ci[4] = p1275_uint2cell(len); ci[5] = p1275_uint2cell(offset); ci[6] = p1275_uint2cell(key); promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); /* * p1275_cif_handler will return 0 on success, non-zero on failure. If * it fails, the return cell from OBP is meaningless, because the OBP * client interface probably wasn't even invoked. OBP will return 0 on * success and non-zero on failure for this interface. */ if (rv != 0) { return (rv); } else if (p1275_cell2int(ci[7]) == 0) { return (0); } else { return (-1); } }
/* * Read the date using "get-time" method in rtc node * PROM returns 1969-1999 when reading 69-99 and * 2000-2068 when reading 00-68 */ static int todds1307_prom_getdate(struct rtc_t *rtc) { int year; cell_t ci[12]; ci[0] = p1275_ptr2cell("call-method"); /* Service name */ ci[1] = 2; /* # of arguments */ ci[2] = 7; /* # of result cells */ ci[3] = p1275_ptr2cell("get-time"); ci[4] = p1275_ihandle2cell(todds1307_ihandle); promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); year = p1275_cell2int(ci[6]); rtc->rtc_mon = p1275_cell2int(ci[7]); rtc->rtc_dom = p1275_cell2int(ci[8]); rtc->rtc_dow = 0; rtc->rtc_hrs = p1275_cell2int(ci[9]); rtc->rtc_min = p1275_cell2int(ci[10]); rtc->rtc_sec = p1275_cell2int(ci[11]); if (year >= 2000) year -= 2000; else year -= 1900; rtc->rtc_year = year; return (DDI_SUCCESS); }
int promif_set_sun4v_api_version(void *p) { cell_t *ci = (cell_t *)p; uint64_t api_group; uint64_t major; uint64_t minor; uint64_t status; uint64_t supported_minor; ASSERT(ci[1] == 3); ASSERT(ci[2] == 2); api_group = (uint64_t)p1275_cell2int(ci[3]); major = (uint64_t)p1275_cell2int(ci[4]); minor = (uint64_t)p1275_cell2int(ci[5]); status = hv_api_set_version(api_group, major, minor, &supported_minor); ci[6] = p1275_int2cell(status); ci[7] = p1275_int2cell(supported_minor); return ((status == H_EOK) ? 0 : -1); }
/* * Test for existance of a specific P1275 client interface service */ int prom_test(char *service) { cell_t ci[5]; ci[0] = p1275_ptr2cell("test"); /* Service name */ ci[1] = (cell_t)1; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_ptr2cell(service); /* Arg1: requested svc name */ ci[4] = (cell_t)-1; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); return (p1275_cell2int(ci[4])); /* Res1: missing flag */ }
int prom_test_method(char *method, dnode_t node) { cell_t ci[6]; ci[0] = p1275_ptr2cell("test-method"); /* service */ ci[1] = (cell_t)2; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_dnode2cell(node); ci[4] = p1275_ptr2cell(method); ci[5] = (cell_t)-1; (void) p1275_cif_handler(&ci); return (p1275_cell2int(ci[5])); }
int prom_asr_list_keys_len() { cell_t ci[4]; ci[0] = p1275_ptr2cell("SUNW,asr-list-keys-len"); ci[1] = (cell_t)0; /* #argument cells */ ci[2] = (cell_t)1; /* #return cells */ ci[3] = (cell_t)-1; /* Res1: Prime result */ promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); return (p1275_cell2int(ci[3])); /* Res1: buf length */ }
/* * Given the portid of the IOB to which the tunnel should be moved and the type * of move that should be performed, ask OBP to switch the IOSRAM tunnel from * its current host IOB to a new location. If the move type is 0, OBP will * coordinate the change with SMS and will copy data from the current location * to the new location. If the move type is 1, OBP will simply mark the new * location valid and start using it, without doing any data copying and without * communicating with SMS. Return 0 on success, non-zero on failure. */ int prom_starcat_switch_tunnel(uint_t portid, uint_t msgtype) { static uint8_t warned = 0; cell_t ci[6]; int rv; /* * Make sure we have the necessary support in OBP. */ if (prom_test(switch_tunnel_cmd) == 0) { ci[0] = p1275_ptr2cell(switch_tunnel_cmd); /* name */ } else { if (!warned) { warned = 1; prom_printf( "Warning: No prom support for switch-tunnel!\n"); } return (-1); } /* * Set up the arguments and call into OBP. */ ci[1] = (cell_t)2; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_uint2cell(portid); ci[4] = p1275_uint2cell(msgtype); promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); /* * p1275_cif_handler will return 0 on success, non-zero on failure. If * it fails, the return cell from OBP is meaningless, because the OBP * client interface probably wasn't even invoked. OBP will return 0 on * failure and non-zero on success for this interface. */ if (rv != 0) { return (rv); } else if (p1275_cell2int(ci[5]) == 0) { return (-1); } else { return (0); } }
int prom_seek(ihandle_t fd, u_longlong_t offset) { cell_t ci[7]; ci[0] = p1275_ptr2cell("seek"); /* Service name */ ci[1] = (cell_t)3; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_ihandle2cell(fd); /* Arg1: ihandle */ ci[4] = p1275_ull2cell_high(offset); /* Arg2: pos.hi */ ci[5] = p1275_ull2cell_low(offset); /* Arg3: pos.lo */ ci[6] = (cell_t)-1; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); return (p1275_cell2int(ci[6])); /* Res1: actual */ }
int prom_getproplen(pnode_t nodeid, caddr_t name) { cell_t ci[6]; ci[0] = p1275_ptr2cell("getproplen"); /* Service name */ ci[1] = (cell_t)2; /* #argument cells */ ci[2] = (cell_t)1; /* #return cells */ ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */ ci[4] = p1275_ptr2cell(name); /* Arg2: Property name */ ci[5] = (cell_t)-1; /* Res1: Prime result */ promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); return (p1275_cell2int(ci[5])); /* Res1: Property length */ }
int prom_seek(int fd, unsigned long long offset) { cell_t ci[7]; ci[0] = p1275_ptr2cell("seek"); /* Service name */ ci[1] = (cell_t)3; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ ci[4] = p1275_ull2cell_high(offset); /* Arg2: pos.hi */ ci[5] = p1275_ull2cell_low(offset); /* Arg3: pos.lo */ ci[6] = (cell_t)-1; /* Res1: Prime result */ promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); return (p1275_cell2int(ci[6])); /* Res1: actual */ }
int prom_setprop(pnode_t nodeid, caddr_t name, caddr_t value, int len) { cell_t ci[8]; #ifdef PROM_32BIT_ADDRS caddr_t ovalue = NULL; if ((uintptr_t)value > (uint32_t)-1) { ovalue = value; value = promplat_alloc(len); if (value == NULL) { return (-1); } promplat_bcopy(ovalue, value, len); } #endif prom_setprop_enter(); promif_preprom(); ci[0] = p1275_ptr2cell("setprop"); /* Service name */ ci[1] = (cell_t)4; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: phandle */ ci[4] = p1275_ptr2cell(name); /* Arg2: property name */ ci[5] = p1275_ptr2cell(value); /* Arg3: New value ptr */ ci[6] = p1275_int2cell(len); /* Arg4: New value len */ ci[7] = (cell_t)-1; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); promif_postprom(); prom_setprop_exit(); #ifdef PROM_32BIT_ADDRS if (ovalue != NULL) promplat_free(value, len); #endif return (p1275_cell2int(ci[7])); /* Res1: Actual new size */ }
int prom_serengeti_cpu_off(pnode_t node) { cell_t ci[5]; int rv; ci[0] = p1275_ptr2cell("SUNW,Serengeti,park-cpu"); ci[1] = (cell_t)1; /* #argument cells */ ci[2] = (cell_t)1; /* #return cells */ ci[3] = p1275_dnode2cell(node); promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); if (rv != 0) return (-1); return (p1275_cell2int(ci[4])); }
int prom_serengeti_wakeupcpu(pnode_t node) { cell_t ci[5]; int rv; ci[0] = p1275_ptr2cell("SUNW,Serengeti,wakeup-cpu"); /* Service name */ ci[1] = (cell_t)1; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_dnode2cell(node); /* Arg1: nodeid to wakeup */ promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); if (rv != 0) return (rv); else return (p1275_cell2int(ci[4])); /* Res1: Catch result */ }
int prom_asr_export(caddr_t value) { int rv; cell_t ci[5]; ci[0] = p1275_ptr2cell("SUNW,asr-export"); /* Service name */ ci[1] = (cell_t)1; /* #argument cells */ ci[2] = (cell_t)1; /* #return cells */ ci[3] = p1275_ptr2cell(value); /* Arg1: buffer address */ ci[4] = -1; /* Res1: buf len */ promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); if (rv != 0) return (-1); return (p1275_cell2int(ci[4])); /* Res1: buf length */ }
int prom_bounded_getprop(pnode_t nodeid, caddr_t name, caddr_t value, int len) { cell_t ci[8]; ci[0] = p1275_ptr2cell("getprop"); /* Service name */ ci[1] = (cell_t)4; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_phandle2cell((phandle_t)nodeid); /* Arg1: package */ ci[4] = p1275_ptr2cell(name); /* Arg2: property name */ ci[5] = p1275_ptr2cell(value); /* Arg3: buffer address */ ci[6] = p1275_int2cell(len); /* Arg4: buffer length */ ci[7] = (cell_t)-1; /* Res1: Prime result */ promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); return (p1275_cell2int(ci[7])); /* Res1: Returned length */ }
/* * This service converts the given physical address into a text string, * representing the name of the field-replacable part for the given * physical address. In other words, it tells the kernel which ecache * module got the (un)correctable ECC error. */ int prom_serengeti_get_ecacheunum(int cpuid, unsigned long long physaddr, char *buf, uint_t buflen, int *ustrlen) { cell_t ci[12]; int rv; ihandle_t imemory = prom_memory_ihandle(); *ustrlen = -1; if ((imemory == (ihandle_t)-1)) return (-1); if (prom_test_method("SUNW,Serengeti,get-ecache-unum", prom_getphandle(imemory)) != 0) return (-1); ci[0] = p1275_ptr2cell("call-method"); /* Service name */ ci[1] = (cell_t)7; /* #argument cells */ ci[2] = (cell_t)2; /* #result cells */ ci[3] = p1275_ptr2cell("SUNW,Serengeti,get-ecache-unum"); /* Arg1: Method name */ ci[4] = p1275_ihandle2cell(imemory); /* Arg2: mem. ihandle */ ci[5] = p1275_uint2cell(buflen); /* Arg3: buflen */ ci[6] = p1275_ptr2cell(buf); /* Arg4: buf */ ci[7] = p1275_ull2cell_high(physaddr); /* Arg5: physhi */ ci[8] = p1275_ull2cell_low(physaddr); /* Arg6: physlo */ ci[9] = p1275_int2cell(cpuid); /* Arg7: cpuid */ ci[10] = (cell_t)-1; /* ret1: catch result */ ci[11] = (cell_t)-1; /* ret2: length */ promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); if (rv != 0) return (rv); if (p1275_cell2int(ci[10]) != 0) /* Res1: catch result */ return (-1); /* "SUNW,Serengeti,get-ecache-unum" failed */ *ustrlen = p1275_cell2uint(ci[11]); /* Res2: unum str length */ return (0); }
/* * Returns 0 on error. Otherwise returns a handle. */ int prom_open(char *path) { cell_t ci[5]; promif_owrap_t *ow; #ifdef PROM_32BIT_ADDRS char *opath = NULL; size_t len; if ((uintptr_t)path > (uint32_t)-1) { opath = path; len = prom_strlen(opath) + 1; /* include terminating NUL */ path = promplat_alloc(len); if (path == NULL) return (0); (void) prom_strcpy(path, opath); } #endif ow = promif_preout(); promif_preprom(); ci[0] = p1275_ptr2cell("open"); /* Service name */ ci[1] = (cell_t)1; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_ptr2cell(path); /* Arg1: Pathname */ ci[4] = (cell_t)0; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); promif_postprom(); promif_postout(ow); #ifdef PROM_32BIT_ADDRS if (opath != NULL) promplat_free(path, len); #endif return (p1275_cell2int(ci[4])); /* Res1: ihandle */ }
int promif_get_sun4v_api_version(void *p) { cell_t *ci = (cell_t *)p; uint64_t api_group; uint64_t major; uint64_t minor; uint64_t status; ASSERT(ci[1] == 1); ASSERT(ci[2] == 3); api_group = (uint64_t)p1275_cell2int(ci[3]); status = hv_api_get_version(api_group, &major, &minor); ci[4] = p1275_int2cell(status); ci[5] = p1275_int2cell(major); ci[6] = p1275_int2cell(minor); return ((status == H_EOK) ? 0 : -1); }
int prom_serengeti_detach_board(uint_t node, uint_t board) { cell_t ci[6]; int rv; ci[0] = p1275_ptr2cell("SUNW,Serengeti,remove-board"); /* name */ ci[1] = (cell_t)2; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_uint2cell(board); ci[4] = p1275_uint2cell(node); promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); if (rv != 0) return (rv); if (p1275_cell2int(ci[5]) != 0) /* Res1: Catch result */ return (-1); return (0); }
/* * Get Fcode size, test if OBP supports this interface. */ int prom_get_fcode_size(char *str) { cell_t ci[5]; int rv; if (prom_test("SUNW,get-fcode-size") != 0) { return (0); } ci[0] = p1275_ptr2cell("SUNW,get-fcode-size"); ci[1] = (cell_t)1; /* 1 input arg: str */ ci[2] = (cell_t)1; /* 1 output result: len or zero */ ci[3] = p1275_ptr2cell(str); ci[4] = (cell_t)0; promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); if (rv == 0) return (p1275_cell2int(ci[4])); return (0); }