xref: /illumos-gate/usr/src/uts/sun4v/promif/promif_io.c (revision 5422785d352a2bb398daceab3d1898a8aa64d006)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/promif_impl.h>
30 #include <sys/systm.h>
31 #include <sys/hypervisor_api.h>
32 #include <sys/consdev.h>
33 #ifndef _KMDB
34 #include <sys/kmem.h>
35 #endif
36 
37 /*
38  * Definitions for using Polled I/O.
39  *
40  * The usage of Polled I/O is different when we are in kmdb. In that case,
41  * we can not directly invoke the polled I/O functions and we have to use
42  * the kmdb DPI interface. Also we don't need to enter/exit the polled I/O
43  * mode because this is already managed by kmdb when entering/exiting the
44  * debugger.
45  *
46  * When we are not in kmdb then we can directly call the polled I/O functions
47  * but we have to enter the polled I/O mode first. After using polled I/O
48  * functions we have to exit the polled I/O mode. Note that entering/exiting
49  * the polled I/O mode is time consuming so this should be avoided when
50  * possible.
51  */
52 #ifdef _KMDB
53 extern struct cons_polledio *kmdb_kdi_get_polled_io(void);
54 extern uintptr_t kmdb_dpi_call(uintptr_t, uint_t, const uintptr_t *);
55 
56 #define	PROMIF_PIO (kmdb_kdi_get_polled_io())
57 
58 #define	PROMIF_PIO_CALL1(fn, arg)					\
59 	(kmdb_dpi_call((uintptr_t)fn, 1, (uintptr_t *)&arg))
60 
61 #define	PROMIF_PIO_CALL2(fn, arg1, arg2)				\
62 	{								\
63 		uintptr_t args[2];					\
64 		args[0] = (uintptr_t)arg1;				\
65 		args[1] = (uintptr_t)arg2;				\
66 		(void) (kmdb_dpi_call((uintptr_t)fn, 2, (uintptr_t *)args)); \
67 	}
68 
69 #define	PROMIF_PIO_ENTER(pio)
70 #define	PROMIF_PIO_EXIT(pio)
71 
72 #else  /* _KMDB */
73 
74 #define	PROMIF_PIO				(cons_polledio)
75 #define	PROMIF_PIO_CALL1(fn, arg)		(fn(arg))
76 #define	PROMIF_PIO_CALL2(fn, arg1, arg2)	(fn(arg1, arg2))
77 
78 #define	PROMIF_PIO_ENTER(pio)						\
79 	if (pio->cons_polledio_enter != NULL) {				\
80 		pio->cons_polledio_enter(pio->cons_polledio_argument);	\
81 	}
82 
83 #define	PROMIF_PIO_EXIT(pio)						\
84 	if (pio->cons_polledio_exit != NULL) {				\
85 		pio->cons_polledio_exit(pio->cons_polledio_argument);	\
86 	}
87 
88 #endif	/* _KMDB */
89 
90 #define	PROM_REG_TO_UNIT_ADDR(r)	((r) & ~(0xful << 28))
91 
92 static pnode_t instance_to_package(ihandle_t ih);
93 
94 /* cached copies of IO params */
95 static phandle_t pstdin;
96 static phandle_t pstdout;
97 
98 static ihandle_t istdin;
99 static ihandle_t istdout;
100 
101 static struct cons_polledio *promif_polledio = NULL;
102 
103 int
104 promif_instance_to_package(void *p)
105 {
106 	cell_t		*ci = (cell_t *)p;
107 	ihandle_t	ih;
108 	phandle_t	ph;
109 
110 	ih = p1275_cell2ihandle(ci[3]);
111 
112 	ph = instance_to_package(ih);
113 
114 	ci[4] = p1275_phandle2cell(ph);
115 
116 	return (0);
117 }
118 
119 /* This function is not used but it is convenient for debugging I/O problems */
120 static void
121 /* LINTED */
122 promif_hv_print(char *str)
123 {
124 	size_t i, len = strlen(str);
125 
126 	for (i = 0; i < len; i++) {
127 		while (hv_cnputchar((uint8_t)str[i]) == H_EWOULDBLOCK)
128 			/* try forever */;
129 	}
130 }
131 
132 static void
133 promif_pio_enter(void)
134 {
135 	ASSERT(promif_polledio == NULL);
136 
137 	promif_polledio = PROMIF_PIO;
138 	ASSERT(promif_polledio != NULL);
139 
140 	PROMIF_PIO_ENTER(promif_polledio);
141 }
142 
143 static void
144 promif_pio_exit(void)
145 {
146 	ASSERT(promif_polledio != NULL);
147 
148 	PROMIF_PIO_EXIT(promif_polledio);
149 	promif_polledio = NULL;
150 }
151 
152 static int
153 promif_do_read(char *buf, size_t len, boolean_t wait)
154 {
155 	int rlen;
156 	int (*getchar)(cons_polledio_arg_t);
157 	boolean_t (*ischar)(cons_polledio_arg_t);
158 	cons_polledio_arg_t arg;
159 
160 	promif_pio_enter();
161 
162 	if ((ischar = promif_polledio->cons_polledio_ischar) == NULL)
163 		return (0);
164 	if ((getchar = promif_polledio->cons_polledio_getchar) == NULL)
165 		return (0);
166 
167 	arg = promif_polledio->cons_polledio_argument;
168 
169 	for (rlen = 0; rlen < len; ) {
170 		if (PROMIF_PIO_CALL1(ischar, arg)) {
171 			buf[rlen] = PROMIF_PIO_CALL1(getchar, arg);
172 			rlen++;
173 			continue;
174 		}
175 
176 		if (!wait)
177 			break;
178 	}
179 
180 	promif_pio_exit();
181 
182 	return (rlen);
183 }
184 
185 static int
186 promif_do_write(char *buf, size_t len)
187 {
188 	int rlen;
189 	void (*putchar)(cons_polledio_arg_t, uchar_t);
190 	cons_polledio_arg_t arg;
191 
192 	promif_pio_enter();
193 
194 	if ((putchar = promif_polledio->cons_polledio_putchar) == NULL)
195 		return (0);
196 
197 	arg = promif_polledio->cons_polledio_argument;
198 
199 	for (rlen = 0; rlen < len; rlen++)
200 		PROMIF_PIO_CALL2(putchar, arg, buf[rlen]);
201 
202 	promif_pio_exit();
203 
204 	return (rlen);
205 }
206 
207 char
208 promif_getchar(void)
209 {
210 	char c;
211 
212 	(void) promif_do_read(&c, 1, B_TRUE);
213 	return (c);
214 }
215 
216 int
217 promif_write(void *p)
218 {
219 	cell_t	*ci = (cell_t *)p;
220 	uint_t	fd;
221 	char	*buf;
222 	size_t	len;
223 	size_t	rlen;
224 
225 	ASSERT(ci[1] == 3);
226 
227 	fd  = p1275_cell2uint(ci[3]);
228 	buf = p1275_cell2ptr(ci[4]);
229 	len = p1275_cell2size(ci[5]);
230 
231 	/* only support stdout (console) */
232 	ASSERT(fd == istdout);
233 
234 	rlen = promif_do_write(buf, len);
235 
236 	/* return the length written */
237 	ci[6] = p1275_size2cell(rlen);
238 
239 	return (0);
240 }
241 
242 int
243 promif_read(void *p)
244 {
245 	cell_t	*ci = (cell_t *)p;
246 	uint_t	fd;
247 	char	*buf;
248 	size_t	len;
249 	size_t	rlen;
250 
251 	ASSERT(ci[1] == 3);
252 
253 	/* unpack arguments */
254 	fd  = p1275_cell2uint(ci[3]);
255 	buf = p1275_cell2ptr(ci[4]);
256 	len = p1275_cell2size(ci[5]);
257 
258 	/* only support stdin (console) */
259 	ASSERT(fd == istdin);
260 
261 	rlen = promif_do_read(buf, len, B_FALSE);
262 
263 	/* return the length read */
264 	ci[6] = p1275_size2cell(rlen);
265 
266 	return (0);
267 }
268 
269 static pnode_t
270 instance_to_package(ihandle_t ih)
271 {
272 	/* only support stdin and stdout */
273 	ASSERT((ih == istdin) || (ih == istdout));
274 
275 	if (ih == istdin)
276 		return (pstdin);
277 
278 	if (ih == istdout)
279 		return (pstdout);
280 
281 	return (OBP_BADNODE);
282 }
283 
284 #ifdef _KMDB
285 
286 void
287 promif_io_init(ihandle_t in, ihandle_t out, phandle_t pin, phandle_t pout)
288 {
289 	istdin = in;
290 	istdout = out;
291 	pstdin = pin;
292 	pstdout = pout;
293 }
294 
295 #else
296 
297 void
298 promif_io_init(void)
299 {
300 	/*
301 	 * Cache the mapping between the stdin and stdout
302 	 * ihandles and their respective phandles.
303 	 */
304 	pstdin = prom_stdin_node();
305 	pstdout = prom_stdout_node();
306 
307 	istdin = prom_stdin_ihandle();
308 	istdout = prom_stdout_ihandle();
309 }
310 
311 int
312 promif_instance_to_path(void *p)
313 {
314 	cell_t		*ci = (cell_t *)p;
315 	pnode_t		node;
316 	ihandle_t	ih;
317 	char		*buf;
318 	int		rlen;
319 	char		*regval;
320 	uint_t		*csaddr;
321 	char		name[OBP_MAXPROPNAME];
322 	char		scratch[OBP_MAXPATHLEN];
323 	int		rvlen;
324 
325 	ih = p1275_cell2ihandle(ci[3]);
326 	buf = p1275_cell2ptr(ci[4]);
327 
328 	ci[6] = p1275_uint2cell(0);
329 
330 	node = instance_to_package(ih);
331 
332 	*buf = '\0';
333 
334 	while (node != prom_rootnode()) {
335 		if (prom_getprop(node, OBP_NAME, name) == -1) {
336 			prom_printf("instance_to_path: no name property "
337 			    "node=0x%x\n", node);
338 			return (-1);
339 		}
340 
341 		/* construct the unit address from the 'reg' property */
342 		if ((rlen = prom_getproplen(node, OBP_REG)) == -1)
343 			return (-1);
344 
345 		/*
346 		 * Make sure we don't get dispatched onto a different
347 		 * cpu if we happen to sleep.  See kern_postprom().
348 		 */
349 		thread_affinity_set(curthread, CPU->cpu_id);
350 		regval = kmem_zalloc(rlen, KM_SLEEP);
351 
352 		(void) prom_getprop(node, OBP_REG, regval);
353 
354 		csaddr = (uint_t *)regval;
355 
356 		(void) prom_sprintf(scratch, "/%s@%lx%s", name,
357 		    PROM_REG_TO_UNIT_ADDR(*csaddr), buf);
358 
359 		kmem_free(regval, rlen);
360 		thread_affinity_clear(curthread);
361 
362 		(void) prom_strcpy(buf, scratch);
363 
364 		node = prom_parentnode(node);
365 	}
366 
367 	rvlen = prom_strlen(buf);
368 	ci[6] = p1275_uint2cell(rvlen);
369 
370 	return (0);
371 }
372 
373 #endif	/* _KMDB */
374