/* * This is the routine that firmware calls when it is giving up control of the * input device. This routine, and the lower layer routines that it calls, * are responsible for restoring the controller state to the state it was * in before firmware took control. * * WARNING: This routine runs in debug mode. */ static void polled_take_input(cell_t *cif) { cons_polledio_t *polled_io; uint_t out_args; /* * Calculate the offset of the return arguments */ out_args = CIF_MIN_SIZE + p1275_cell2uint(cif[CIF_NUMBER_IN_ARGS]); /* * There is one argument being passed back to firmware. */ cif[CIF_NUMBER_OUT_ARGS] = p1275_uint2cell((uint_t)1); cif[out_args] = p1275_uint2cell(CIF_SUCCESS); /* * We check the pointer to see if there is an * input device that has been registered. */ polled_io = polled_input_device.polled_io; if (polled_io == NULL) { return; } /* * Call down to the lower layers to save the state. */ polled_io->cons_polledio_exit(polled_io->cons_polledio_argument); }
/* * 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); } }
/* * 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 */ }
/* * 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); } }
/* * This is the generic client interface to "claim" memory. * These two routines belong in the common directory. */ caddr_t prom_malloc(caddr_t virt, size_t size, uint_t align) { cell_t ci[7]; int rv; ci[0] = p1275_ptr2cell("claim"); /* Service name */ ci[1] = (cell_t)3; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_ptr2cell(virt); /* Arg1: virt */ ci[4] = p1275_uint2cell(size); /* Arg2: size */ ci[5] = p1275_uint2cell(align); /* Arg3: align */ promif_preprom(); rv = p1275_cif_handler(&ci); promif_postprom(); if (rv == 0) return ((caddr_t)p1275_cell2ptr(ci[6])); /* Res1: base */ return ((caddr_t)-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); }
void prom_free(caddr_t virt, size_t size) { cell_t ci[5]; ci[0] = p1275_ptr2cell("release"); /* Service name */ ci[1] = (cell_t)2; /* #argument cells */ ci[2] = (cell_t)0; /* #result cells */ ci[3] = p1275_ptr2cell(virt); /* Arg1: virt */ ci[4] = p1275_uint2cell(size); /* Arg2: size */ promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); }
uint32_t prom_read(ihandle_t fd, caddr_t buf, uint32_t len) { cell_t ci[7]; ci[0] = p1275_ptr2cell("read"); /* 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_ptr2cell(buf); /* Arg2: buffer address */ ci[5] = p1275_uint2cell(len); /* Arg3: buffer length */ ci[6] = (cell_t)-1; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); return (p1275_cell2uint(ci[6])); /* Res1: actual 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_close(int fd) { cell_t ci[4]; promif_owrap_t *ow; ci[0] = p1275_ptr2cell("close"); /* Service name */ ci[1] = (cell_t)1; /* #argument cells */ ci[2] = (cell_t)0; /* #result cells */ ci[3] = p1275_uint2cell((uint_t)fd); /* Arg1: ihandle */ ow = promif_preout(); promif_preprom(); (void) p1275_cif_handler(&ci); promif_postprom(); promif_postout(ow); return (0); }
/*ARGSUSED3*/ ssize_t prom_read(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype) { cell_t ci[7]; promif_owrap_t *ow; #ifdef PROM_32BIT_ADDRS caddr_t obuf = NULL; if ((uintptr_t)buf > (uint32_t)-1) { obuf = buf; buf = promplat_alloc(len); if (buf == NULL) return (-1); } #endif ow = promif_preout(); promif_preprom(); ci[0] = p1275_ptr2cell("read"); /* Service name */ ci[1] = (cell_t)3; /* #argument cells */ ci[2] = (cell_t)1; /* #result cells */ ci[3] = p1275_size2cell((uint_t)fd); /* Arg1: ihandle */ ci[4] = p1275_ptr2cell(buf); /* Arg2: buffer address */ ci[5] = p1275_uint2cell(len); /* Arg3: buffer length */ ci[6] = (cell_t)-1; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); promif_postprom(); promif_postout(ow); #ifdef PROM_32BIT_ADDRS if (obuf != NULL) { promplat_bcopy(buf, obuf, len); promplat_free(buf, len); } #endif return (p1275_cell2size(ci[6])); /* Res1: actual 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); }
/*ARGSUSED3*/ ssize_t prom_write(ihandle_t fd, caddr_t buf, size_t len, uint_t startblk, char devtype) { cell_t ci[7]; promif_owrap_t *ow; ssize_t rlen; #ifdef PROM_32BIT_ADDRS caddr_t obuf = NULL; static char smallbuf[256]; ASSERT(buf); #endif /* * If the callback address is set, attempt to redirect * console output back into kernel terminal emulator. */ if (promif_redirect != NULL && fd == prom_stdout_ihandle()) { ow = promif_preout(); rlen = promif_redirect(promif_redirect_arg, (uchar_t *)buf, len); promif_postout(ow); return (rlen); } #ifdef PROM_32BIT_ADDRS if ((uintptr_t)buf > (uint32_t)-1) { /* * This is a hack for kernel message output. * By avoiding calls to promplat_alloc (and * using smallbuf instead) when memory is low * we can print shortish kernel messages without * deadlocking. smallbuf should be at least as * large as the automatic buffer in * prom_printf.c:_doprint()'s stack frame. * promplat_alloc() can block on a mutex and so * is called here before calling promif_preprom(). */ if (len > sizeof (smallbuf)) { obuf = buf; buf = promplat_alloc(len); if (buf == NULL) { return (-1); } promplat_bcopy(obuf, buf, len); } } #endif /* * Normally we'd call promif_preprom() just before * calling into the prom (to enforce single-threaded * access) but here we need to call it before accessing * smallbuf, since smallbuf is statically allocated and * hence can only be accessed by one thread at a time. */ ow = promif_preout(); promif_preprom(); #ifdef PROM_32BIT_ADDRS if ((uintptr_t)buf > (uint32_t)-1) { /* * If buf is small enough, use smallbuf * instead of promplat_alloc() (see above) * smallbuf is static, so single thread * access to it by using it only after * promif_preprom() */ if (len <= sizeof (smallbuf)) { promplat_bcopy(buf, smallbuf, len); buf = smallbuf; } } #endif ci[0] = p1275_ptr2cell("write"); /* 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_ptr2cell(buf); /* Arg2: buffer addr */ ci[5] = p1275_size2cell(len); /* Arg3: buffer len */ ci[6] = (cell_t)-1; /* Res1: Prime result */ (void) p1275_cif_handler(&ci); rlen = p1275_cell2size(ci[6]); /* Res1: actual len */ promif_postprom(); promif_postout(ow); #ifdef PROM_32BIT_ADDRS if (obuf != NULL) promplat_free(buf, len); #endif return (rlen); }
/* * This is the routine that the firmware calls when * it wants to write a character. * * WARNING: This routine runs in debug mode. */ static void polled_write(cell_t *cif) { cons_polledio_t *polled_io; uint_t in_args; uint_t out_args; uchar_t *buffer; uint_t buflen; /* * The number of arguments passed in by the firmware */ in_args = p1275_cell2uint(cif[CIF_NUMBER_IN_ARGS]); /* * Calculate the location of the first out arg. This location is * CIF_MIN_SIZE (name + no. in args + no. out args) plus the * in argument locations. */ out_args = CIF_MIN_SIZE + in_args; /* * The firmware should pass in a pointer to a buffer, and the * number of characters it expects or expects to write. * If 2 arguments are not passed in, then return an error. */ if (in_args != 2) { /* * Tell firmware how many arguments we are passing back. */ cif[CIF_NUMBER_OUT_ARGS] = p1275_uint2cell((uint_t)1); /* * Tell the firmware that we cannot give it any characters. */ cif[out_args] = p1275_uint2cell(CIF_FAILURE); return; } /* * Get the address of where to copy the characters into. */ buffer = (uchar_t *)(uintptr_t)p1275_cell2uint(cif[CIF_MIN_SIZE+0]); /* * Get the length of the buffer that we can copy characters into. */ buflen = p1275_cell2uint(cif[CIF_MIN_SIZE+1]); /* * Make sure there is enough room in the buffer to copy the * characters into. */ if (buflen == 0) { /* * Tell the OBP that we cannot give it any characters. */ cif[CIF_NUMBER_OUT_ARGS] = p1275_uint2cell((uint_t)1); /* * Tell the firmware that we cannot give it any characters. */ cif[out_args] = p1275_uint2cell(CIF_FAILURE); return; } /* * Tell the firmware how many arguments we are passing back. */ cif[CIF_NUMBER_OUT_ARGS] = p1275_uint2cell((uint_t)2); /* * Initialize the cif to success */ cif[out_args+0] = p1275_uint2cell(CIF_SUCCESS); cif[out_args+1] = p1275_uint2cell(0); /* * We check the pointer to see if there is an * input device that has been registered. */ polled_io = polled_output_device.polled_io; if (polled_io == NULL) { /* * The cif is already initialized */ return; } polled_io_cons_write(buffer, (size_t)buflen); /* * Tell the firmware how many characters we are sending it. */ cif[out_args+0] = p1275_uint2cell((uint_t)CIF_SUCCESS); cif[out_args+1] = p1275_uint2cell((uint_t)buflen); }
/* * This is the routine that the firmware calls * when it wants to read a character. * We will call to the lower layers to see if there is any input data * available. * * WARNING: This routine runs in debug mode. */ static void polled_read(cell_t *cif) { uint_t actual; cons_polledio_t *polled_io; uint_t in_args; uint_t out_args; uchar_t *buffer; uint_t buflen; uchar_t key; /* * The number of arguments passed in by the firmware */ in_args = p1275_cell2uint(cif[CIF_NUMBER_IN_ARGS]); /* * Calculate the location of the first out arg. This location is * CIF_MIN_SIZE plus the in argument locations. */ out_args = CIF_MIN_SIZE + in_args; /* * The firmware should pass in a pointer to a buffer, and the * number of characters it expects or expects to write. * If 2 arguments are not passed in, then return an error. */ if (in_args != 2) { /* * Tell firmware how many arguments we are passing back. */ cif[CIF_NUMBER_OUT_ARGS] = p1275_uint2cell((uint_t)1); /* * Tell the firmware that we cannot give it any characters. */ cif[out_args] = p1275_uint2cell(CIF_FAILURE); return; } /* * Get the address of where to copy the characters into. */ buffer = (uchar_t *)(uintptr_t)p1275_cell2uint(cif[CIF_MIN_SIZE+0]); /* * Get the length of the buffer that we can copy characters into. */ buflen = p1275_cell2uint(cif[CIF_MIN_SIZE+1]); /* * Make sure there is enough room in the buffer to copy the * characters into. */ if (buflen == 0) { /* * Tell the OBP that we cannot give it any characters. */ cif[CIF_NUMBER_OUT_ARGS] = p1275_uint2cell((uint_t)1); /* * Tell the firmware that we cannot give it any characters. */ cif[out_args] = p1275_uint2cell(CIF_FAILURE); return; } /* * Pass back whether or not the operation was a success or * failure plus the actual number of bytes in the buffer. * Tell firmware how many arguments we are passing back. */ cif[CIF_NUMBER_OUT_ARGS] = p1275_uint2cell((uint_t)2); /* * Initialize the cif to be "no characters" */ cif[out_args+0] = p1275_uint2cell(CIF_SUCCESS); cif[out_args+1] = p1275_uint2cell(CIF_NO_CHARACTERS); /* * We check to see if there is an * input device that has been registered. */ polled_io = polled_input_device.polled_io; if (polled_io == NULL || polled_io->cons_polledio_ischar == NULL) { /* * The cif structure is already set up to return * no characters. */ return; } actual = 0; /* * Obtain the characters */ while (polled_io->cons_polledio_ischar( polled_io->cons_polledio_argument) == B_TRUE) { /* * Make sure that we don't overrun the buffer. */ if (actual == buflen) { break; } /* * Call down to the device to copy the input data into the * buffer. */ key = polled_io->cons_polledio_getchar( polled_io->cons_polledio_argument); *(buffer + actual) = key; actual++; } /* * There is a special return code when there is no data. */ if (actual == 0) { /* * The cif structure is already set up to return * no characters. */ return; } /* * Tell firmware how many characters we are sending it. */ cif[out_args+0] = p1275_uint2cell((uint_t)CIF_SUCCESS); cif[out_args+1] = p1275_uint2cell((uint_t)actual); }