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
promif_instance_to_package(void * p)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 */
promif_hv_print(char * str)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
promif_pio_enter(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
promif_pio_exit(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
promif_do_read(char * buf,size_t len,boolean_t wait)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
promif_do_write(char * buf,size_t len)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
promif_getchar(void)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
promif_write(void * p)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
promif_read(void * p)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
instance_to_package(ihandle_t ih)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
promif_io_init(ihandle_t in,ihandle_t out,phandle_t pin,phandle_t pout)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
promif_io_init(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
promif_instance_to_path(void * p)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