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
53extern struct cons_polledio *kmdb_kdi_get_polled_io(void);
54extern 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
92static pnode_t instance_to_package(ihandle_t ih);
93
94/* cached copies of IO params */
95static phandle_t pstdin;
96static phandle_t pstdout;
97
98static ihandle_t istdin;
99static ihandle_t istdout;
100
101static struct cons_polledio *promif_polledio = NULL;
102
103int
104promif_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 */
120static void
121/* LINTED */
122promif_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
132static void
133promif_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
143static void
144promif_pio_exit(void)
145{
146	ASSERT(promif_polledio != NULL);
147
148	PROMIF_PIO_EXIT(promif_polledio);
149	promif_polledio = NULL;
150}
151
152static int
153promif_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
185static int
186promif_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
207char
208promif_getchar(void)
209{
210	char c;
211
212	(void) promif_do_read(&c, 1, B_TRUE);
213	return (c);
214}
215
216int
217promif_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
242int
243promif_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
269static pnode_t
270instance_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
286void
287promif_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
297void
298promif_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
311int
312promif_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