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