xref: /titanic_51/usr/src/uts/sun4v/promif/promif_io.c (revision 1b83305cfc332b1e19ad6a194b73b2975e6bf79a)
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