11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 23de81a4f4Sjm22469 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo #include <sys/promif_impl.h> 301ae08745Sheppo #include <sys/systm.h> 311ae08745Sheppo #include <sys/hypervisor_api.h> 32*1b83305cSjm22469 #include <sys/consdev.h> 331ae08745Sheppo #ifndef _KMDB 341ae08745Sheppo #include <sys/kmem.h> 351ae08745Sheppo #endif 361ae08745Sheppo 37*1b83305cSjm22469 /* 38*1b83305cSjm22469 * Definitions for using Polled I/O. 39*1b83305cSjm22469 * 40*1b83305cSjm22469 * The usage of Polled I/O is different when we are in kmdb. In that case, 41*1b83305cSjm22469 * we can not directly invoke the polled I/O functions and we have to use 42*1b83305cSjm22469 * the kmdb DPI interface. Also we don't need to enter/exit the polled I/O 43*1b83305cSjm22469 * mode because this is already managed by kmdb when entering/exiting the 44*1b83305cSjm22469 * debugger. 45*1b83305cSjm22469 * 46*1b83305cSjm22469 * When we are not in kmdb then we can directly call the polled I/O functions 47*1b83305cSjm22469 * but we have to enter the polled I/O mode first. After using polled I/O 48*1b83305cSjm22469 * functions we have to exit the polled I/O mode. Note that entering/exiting 49*1b83305cSjm22469 * the polled I/O mode is time consuming so this should be avoided when 50*1b83305cSjm22469 * possible. 51*1b83305cSjm22469 */ 52*1b83305cSjm22469 #ifdef _KMDB 53*1b83305cSjm22469 extern struct cons_polledio *kmdb_kdi_get_polled_io(void); 54*1b83305cSjm22469 extern uintptr_t kmdb_dpi_call(uintptr_t, uint_t, const uintptr_t *); 55*1b83305cSjm22469 56*1b83305cSjm22469 #define PROMIF_PIO (kmdb_kdi_get_polled_io()) 57*1b83305cSjm22469 58*1b83305cSjm22469 #define PROMIF_PIO_CALL1(fn, arg) \ 59*1b83305cSjm22469 (kmdb_dpi_call((uintptr_t)fn, 1, (uintptr_t *)&arg)) 60*1b83305cSjm22469 61*1b83305cSjm22469 #define PROMIF_PIO_CALL2(fn, arg1, arg2) \ 62*1b83305cSjm22469 { \ 63*1b83305cSjm22469 uintptr_t args[2]; \ 64*1b83305cSjm22469 args[0] = (uintptr_t)arg1; \ 65*1b83305cSjm22469 args[1] = (uintptr_t)arg2; \ 66*1b83305cSjm22469 (void) (kmdb_dpi_call((uintptr_t)fn, 2, (uintptr_t *)args)); \ 67*1b83305cSjm22469 } 68*1b83305cSjm22469 69*1b83305cSjm22469 #define PROMIF_PIO_ENTER(pio) 70*1b83305cSjm22469 #define PROMIF_PIO_EXIT(pio) 71*1b83305cSjm22469 72*1b83305cSjm22469 #else /* _KMDB */ 73*1b83305cSjm22469 74*1b83305cSjm22469 #define PROMIF_PIO (cons_polledio) 75*1b83305cSjm22469 #define PROMIF_PIO_CALL1(fn, arg) (fn(arg)) 76*1b83305cSjm22469 #define PROMIF_PIO_CALL2(fn, arg1, arg2) (fn(arg1, arg2)) 77*1b83305cSjm22469 78*1b83305cSjm22469 #define PROMIF_PIO_ENTER(pio) \ 79*1b83305cSjm22469 if (pio->cons_polledio_enter != NULL) { \ 80*1b83305cSjm22469 pio->cons_polledio_enter(pio->cons_polledio_argument); \ 81*1b83305cSjm22469 } 82*1b83305cSjm22469 83*1b83305cSjm22469 #define PROMIF_PIO_EXIT(pio) \ 84*1b83305cSjm22469 if (pio->cons_polledio_exit != NULL) { \ 85*1b83305cSjm22469 pio->cons_polledio_exit(pio->cons_polledio_argument); \ 86*1b83305cSjm22469 } 87*1b83305cSjm22469 88*1b83305cSjm22469 #endif /* _KMDB */ 89*1b83305cSjm22469 901ae08745Sheppo #define PROM_REG_TO_UNIT_ADDR(r) ((r) & ~(0xful << 28)) 911ae08745Sheppo 921ae08745Sheppo static pnode_t instance_to_package(ihandle_t ih); 931ae08745Sheppo 941ae08745Sheppo /* cached copies of IO params */ 951ae08745Sheppo static phandle_t pstdin; 961ae08745Sheppo static phandle_t pstdout; 971ae08745Sheppo 981ae08745Sheppo static ihandle_t istdin; 991ae08745Sheppo static ihandle_t istdout; 1001ae08745Sheppo 101*1b83305cSjm22469 static struct cons_polledio *promif_polledio = NULL; 102*1b83305cSjm22469 1031ae08745Sheppo int 1041ae08745Sheppo promif_instance_to_package(void *p) 1051ae08745Sheppo { 1061ae08745Sheppo cell_t *ci = (cell_t *)p; 1071ae08745Sheppo ihandle_t ih; 1081ae08745Sheppo phandle_t ph; 1091ae08745Sheppo 1101ae08745Sheppo ih = p1275_cell2ihandle(ci[3]); 1111ae08745Sheppo 1121ae08745Sheppo ph = instance_to_package(ih); 1131ae08745Sheppo 1141ae08745Sheppo ci[4] = p1275_phandle2cell(ph); 1151ae08745Sheppo 1161ae08745Sheppo return (0); 1171ae08745Sheppo } 1181ae08745Sheppo 119*1b83305cSjm22469 /* This function is not used but it is convenient for debugging I/O problems */ 120*1b83305cSjm22469 static void 121*1b83305cSjm22469 /* LINTED */ 122*1b83305cSjm22469 promif_hv_print(char *str) 123*1b83305cSjm22469 { 124*1b83305cSjm22469 size_t i, len = strlen(str); 125*1b83305cSjm22469 126*1b83305cSjm22469 for (i = 0; i < len; i++) { 127*1b83305cSjm22469 while (hv_cnputchar((uint8_t)str[i]) == H_EWOULDBLOCK) 128*1b83305cSjm22469 /* try forever */; 129*1b83305cSjm22469 } 130*1b83305cSjm22469 } 131*1b83305cSjm22469 132*1b83305cSjm22469 static void 133*1b83305cSjm22469 promif_pio_enter(void) 134*1b83305cSjm22469 { 135*1b83305cSjm22469 ASSERT(promif_polledio == NULL); 136*1b83305cSjm22469 137*1b83305cSjm22469 promif_polledio = PROMIF_PIO; 138*1b83305cSjm22469 ASSERT(promif_polledio != NULL); 139*1b83305cSjm22469 140*1b83305cSjm22469 PROMIF_PIO_ENTER(promif_polledio); 141*1b83305cSjm22469 } 142*1b83305cSjm22469 143*1b83305cSjm22469 static void 144*1b83305cSjm22469 promif_pio_exit(void) 145*1b83305cSjm22469 { 146*1b83305cSjm22469 ASSERT(promif_polledio != NULL); 147*1b83305cSjm22469 148*1b83305cSjm22469 PROMIF_PIO_EXIT(promif_polledio); 149*1b83305cSjm22469 promif_polledio = NULL; 150*1b83305cSjm22469 } 151*1b83305cSjm22469 152*1b83305cSjm22469 static int 153*1b83305cSjm22469 promif_do_read(char *buf, size_t len, boolean_t wait) 154*1b83305cSjm22469 { 155*1b83305cSjm22469 int rlen; 156*1b83305cSjm22469 int (*getchar)(cons_polledio_arg_t); 157*1b83305cSjm22469 boolean_t (*ischar)(cons_polledio_arg_t); 158*1b83305cSjm22469 cons_polledio_arg_t arg; 159*1b83305cSjm22469 160*1b83305cSjm22469 promif_pio_enter(); 161*1b83305cSjm22469 162*1b83305cSjm22469 if ((ischar = promif_polledio->cons_polledio_ischar) == NULL) 163*1b83305cSjm22469 return (0); 164*1b83305cSjm22469 if ((getchar = promif_polledio->cons_polledio_getchar) == NULL) 165*1b83305cSjm22469 return (0); 166*1b83305cSjm22469 167*1b83305cSjm22469 arg = promif_polledio->cons_polledio_argument; 168*1b83305cSjm22469 169*1b83305cSjm22469 for (rlen = 0; rlen < len; ) { 170*1b83305cSjm22469 if (PROMIF_PIO_CALL1(ischar, arg)) { 171*1b83305cSjm22469 buf[rlen] = PROMIF_PIO_CALL1(getchar, arg); 172*1b83305cSjm22469 rlen++; 173*1b83305cSjm22469 continue; 174*1b83305cSjm22469 } 175*1b83305cSjm22469 176*1b83305cSjm22469 if (!wait) 177*1b83305cSjm22469 break; 178*1b83305cSjm22469 } 179*1b83305cSjm22469 180*1b83305cSjm22469 promif_pio_exit(); 181*1b83305cSjm22469 182*1b83305cSjm22469 return (rlen); 183*1b83305cSjm22469 } 184*1b83305cSjm22469 185*1b83305cSjm22469 static int 186*1b83305cSjm22469 promif_do_write(char *buf, size_t len) 187*1b83305cSjm22469 { 188*1b83305cSjm22469 int rlen; 189*1b83305cSjm22469 void (*putchar)(cons_polledio_arg_t, uchar_t); 190*1b83305cSjm22469 cons_polledio_arg_t arg; 191*1b83305cSjm22469 192*1b83305cSjm22469 promif_pio_enter(); 193*1b83305cSjm22469 194*1b83305cSjm22469 if ((putchar = promif_polledio->cons_polledio_putchar) == NULL) 195*1b83305cSjm22469 return (0); 196*1b83305cSjm22469 197*1b83305cSjm22469 arg = promif_polledio->cons_polledio_argument; 198*1b83305cSjm22469 199*1b83305cSjm22469 for (rlen = 0; rlen < len; rlen++) 200*1b83305cSjm22469 PROMIF_PIO_CALL2(putchar, arg, buf[rlen]); 201*1b83305cSjm22469 202*1b83305cSjm22469 promif_pio_exit(); 203*1b83305cSjm22469 204*1b83305cSjm22469 return (rlen); 205*1b83305cSjm22469 } 206*1b83305cSjm22469 207*1b83305cSjm22469 char 208*1b83305cSjm22469 promif_getchar(void) 209*1b83305cSjm22469 { 210*1b83305cSjm22469 char c; 211*1b83305cSjm22469 212*1b83305cSjm22469 (void) promif_do_read(&c, 1, B_TRUE); 213*1b83305cSjm22469 return (c); 214*1b83305cSjm22469 } 215*1b83305cSjm22469 2161ae08745Sheppo int 2171ae08745Sheppo promif_write(void *p) 2181ae08745Sheppo { 2191ae08745Sheppo cell_t *ci = (cell_t *)p; 2201ae08745Sheppo uint_t fd; 2211ae08745Sheppo char *buf; 2221ae08745Sheppo size_t len; 2231ae08745Sheppo size_t rlen; 2241ae08745Sheppo 2251ae08745Sheppo ASSERT(ci[1] == 3); 2261ae08745Sheppo 2271ae08745Sheppo fd = p1275_cell2uint(ci[3]); 2281ae08745Sheppo buf = p1275_cell2ptr(ci[4]); 2291ae08745Sheppo len = p1275_cell2size(ci[5]); 2301ae08745Sheppo 2311ae08745Sheppo /* only support stdout (console) */ 2321ae08745Sheppo ASSERT(fd == istdout); 2331ae08745Sheppo 234*1b83305cSjm22469 rlen = promif_do_write(buf, len); 2351ae08745Sheppo 2361ae08745Sheppo /* return the length written */ 2371ae08745Sheppo ci[6] = p1275_size2cell(rlen); 2381ae08745Sheppo 2391ae08745Sheppo return (0); 2401ae08745Sheppo } 2411ae08745Sheppo 2421ae08745Sheppo int 2431ae08745Sheppo promif_read(void *p) 2441ae08745Sheppo { 2451ae08745Sheppo cell_t *ci = (cell_t *)p; 2461ae08745Sheppo uint_t fd; 2471ae08745Sheppo char *buf; 2481ae08745Sheppo size_t len; 2491ae08745Sheppo size_t rlen; 2501ae08745Sheppo 2511ae08745Sheppo ASSERT(ci[1] == 3); 2521ae08745Sheppo 2531ae08745Sheppo /* unpack arguments */ 2541ae08745Sheppo fd = p1275_cell2uint(ci[3]); 2551ae08745Sheppo buf = p1275_cell2ptr(ci[4]); 2561ae08745Sheppo len = p1275_cell2size(ci[5]); 2571ae08745Sheppo 2581ae08745Sheppo /* only support stdin (console) */ 2591ae08745Sheppo ASSERT(fd == istdin); 2601ae08745Sheppo 261*1b83305cSjm22469 rlen = promif_do_read(buf, len, B_FALSE); 2621ae08745Sheppo 2631ae08745Sheppo /* return the length read */ 2641ae08745Sheppo ci[6] = p1275_size2cell(rlen); 2651ae08745Sheppo 2661ae08745Sheppo return (0); 2671ae08745Sheppo } 2681ae08745Sheppo 2691ae08745Sheppo static pnode_t 2701ae08745Sheppo instance_to_package(ihandle_t ih) 2711ae08745Sheppo { 2721ae08745Sheppo /* only support stdin and stdout */ 2731ae08745Sheppo ASSERT((ih == istdin) || (ih == istdout)); 2741ae08745Sheppo 2751ae08745Sheppo if (ih == istdin) 2761ae08745Sheppo return (pstdin); 2771ae08745Sheppo 2781ae08745Sheppo if (ih == istdout) 2791ae08745Sheppo return (pstdout); 2801ae08745Sheppo 2811ae08745Sheppo return (OBP_BADNODE); 2821ae08745Sheppo } 2831ae08745Sheppo 2841ae08745Sheppo #ifdef _KMDB 2851ae08745Sheppo 2861ae08745Sheppo void 2871ae08745Sheppo promif_io_init(ihandle_t in, ihandle_t out, phandle_t pin, phandle_t pout) 2881ae08745Sheppo { 2891ae08745Sheppo istdin = in; 2901ae08745Sheppo istdout = out; 2911ae08745Sheppo pstdin = pin; 2921ae08745Sheppo pstdout = pout; 2931ae08745Sheppo } 2941ae08745Sheppo 2951ae08745Sheppo #else 2961ae08745Sheppo 2971ae08745Sheppo void 2981ae08745Sheppo promif_io_init(void) 2991ae08745Sheppo { 3001ae08745Sheppo /* 3011ae08745Sheppo * Cache the mapping between the stdin and stdout 3021ae08745Sheppo * ihandles and their respective phandles. 3031ae08745Sheppo */ 3041ae08745Sheppo pstdin = prom_stdin_node(); 3051ae08745Sheppo pstdout = prom_stdout_node(); 3061ae08745Sheppo 3071ae08745Sheppo istdin = prom_stdin_ihandle(); 3081ae08745Sheppo istdout = prom_stdout_ihandle(); 3091ae08745Sheppo } 3101ae08745Sheppo 3111ae08745Sheppo int 3121ae08745Sheppo promif_instance_to_path(void *p) 3131ae08745Sheppo { 3141ae08745Sheppo cell_t *ci = (cell_t *)p; 3151ae08745Sheppo pnode_t node; 3161ae08745Sheppo ihandle_t ih; 3171ae08745Sheppo char *buf; 3181ae08745Sheppo int rlen; 3191ae08745Sheppo char *regval; 3201ae08745Sheppo uint_t *csaddr; 3211ae08745Sheppo char name[OBP_MAXPROPNAME]; 3221ae08745Sheppo char scratch[OBP_MAXPATHLEN]; 3231ae08745Sheppo int rvlen; 3241ae08745Sheppo 3251ae08745Sheppo ih = p1275_cell2ihandle(ci[3]); 3261ae08745Sheppo buf = p1275_cell2ptr(ci[4]); 3271ae08745Sheppo 3281ae08745Sheppo ci[6] = p1275_uint2cell(0); 3291ae08745Sheppo 3301ae08745Sheppo node = instance_to_package(ih); 3311ae08745Sheppo 3321ae08745Sheppo *buf = '\0'; 3331ae08745Sheppo 3341ae08745Sheppo while (node != prom_rootnode()) { 3351ae08745Sheppo if (prom_getprop(node, OBP_NAME, name) == -1) { 3361ae08745Sheppo prom_printf("instance_to_path: no name property " 3371ae08745Sheppo "node=0x%x\n", node); 3381ae08745Sheppo return (-1); 3391ae08745Sheppo } 3401ae08745Sheppo 3411ae08745Sheppo /* construct the unit address from the 'reg' property */ 3421ae08745Sheppo if ((rlen = prom_getproplen(node, OBP_REG)) == -1) 3431ae08745Sheppo return (-1); 3441ae08745Sheppo 345a47315d7Sjm22469 /* 346a47315d7Sjm22469 * Make sure we don't get dispatched onto a different 347a47315d7Sjm22469 * cpu if we happen to sleep. See kern_postprom(). 348a47315d7Sjm22469 */ 349de81a4f4Sjm22469 thread_affinity_set(curthread, CPU->cpu_id); 3501ae08745Sheppo regval = kmem_zalloc(rlen, KM_SLEEP); 3511ae08745Sheppo 3521ae08745Sheppo (void) prom_getprop(node, OBP_REG, regval); 3531ae08745Sheppo 3541ae08745Sheppo csaddr = (uint_t *)regval; 3551ae08745Sheppo 3561ae08745Sheppo (void) prom_sprintf(scratch, "/%s@%lx%s", name, 3571ae08745Sheppo PROM_REG_TO_UNIT_ADDR(*csaddr), buf); 3581ae08745Sheppo 3591ae08745Sheppo kmem_free(regval, rlen); 360de81a4f4Sjm22469 thread_affinity_clear(curthread); 3611ae08745Sheppo 3621ae08745Sheppo (void) prom_strcpy(buf, scratch); 3631ae08745Sheppo 3641ae08745Sheppo node = prom_parentnode(node); 3651ae08745Sheppo } 3661ae08745Sheppo 3671ae08745Sheppo rvlen = prom_strlen(buf); 3681ae08745Sheppo ci[6] = p1275_uint2cell(rvlen); 3691ae08745Sheppo 3701ae08745Sheppo return (0); 3711ae08745Sheppo } 3721ae08745Sheppo 3731ae08745Sheppo #endif /* _KMDB */ 374