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 /*
23de81a4f4Sjm  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #include <sys/promif_impl.h>
281ae08745Sheppo #include <sys/systm.h>
291ae08745Sheppo #include <sys/hypervisor_api.h>
301b83305cSjm #include <sys/consdev.h>
311ae08745Sheppo #ifndef _KMDB
321ae08745Sheppo #include <sys/kmem.h>
331ae08745Sheppo #endif
341ae08745Sheppo 
351b83305cSjm /*
361b83305cSjm  * Definitions for using Polled I/O.
371b83305cSjm  *
381b83305cSjm  * The usage of Polled I/O is different when we are in kmdb. In that case,
391b83305cSjm  * we can not directly invoke the polled I/O functions and we have to use
401b83305cSjm  * the kmdb DPI interface. Also we don't need to enter/exit the polled I/O
411b83305cSjm  * mode because this is already managed by kmdb when entering/exiting the
421b83305cSjm  * debugger.
431b83305cSjm  *
441b83305cSjm  * When we are not in kmdb then we can directly call the polled I/O functions
451b83305cSjm  * but we have to enter the polled I/O mode first. After using polled I/O
461b83305cSjm  * functions we have to exit the polled I/O mode. Note that entering/exiting
471b83305cSjm  * the polled I/O mode is time consuming so this should be avoided when
481b83305cSjm  * possible.
491b83305cSjm  */
501b83305cSjm #ifdef _KMDB
511b83305cSjm extern struct cons_polledio *kmdb_kdi_get_polled_io(void);
521b83305cSjm extern uintptr_t kmdb_dpi_call(uintptr_t, uint_t, const uintptr_t *);
531b83305cSjm 
541b83305cSjm #define	PROMIF_PIO (kmdb_kdi_get_polled_io())
551b83305cSjm 
561b83305cSjm #define	PROMIF_PIO_CALL1(fn, arg)					\
571b83305cSjm 	(kmdb_dpi_call((uintptr_t)fn, 1, (uintptr_t *)&arg))
581b83305cSjm 
591b83305cSjm #define	PROMIF_PIO_CALL2(fn, arg1, arg2)				\
601b83305cSjm 	{								\
611b83305cSjm 		uintptr_t args[2];					\
621b83305cSjm 		args[0] = (uintptr_t)arg1;				\
631b83305cSjm 		args[1] = (uintptr_t)arg2;				\
641b83305cSjm 		(void) (kmdb_dpi_call((uintptr_t)fn, 2, (uintptr_t *)args)); \
651b83305cSjm 	}
661b83305cSjm 
671b83305cSjm #define	PROMIF_PIO_ENTER(pio)
681b83305cSjm #define	PROMIF_PIO_EXIT(pio)
691b83305cSjm 
701b83305cSjm #else  /* _KMDB */
711b83305cSjm 
721b83305cSjm #define	PROMIF_PIO				(cons_polledio)
731b83305cSjm #define	PROMIF_PIO_CALL1(fn, arg)		(fn(arg))
741b83305cSjm #define	PROMIF_PIO_CALL2(fn, arg1, arg2)	(fn(arg1, arg2))
751b83305cSjm 
761b83305cSjm #define	PROMIF_PIO_ENTER(pio)						\
771b83305cSjm 	if (pio->cons_polledio_enter != NULL) {				\
781b83305cSjm 		pio->cons_polledio_enter(pio->cons_polledio_argument);	\
791b83305cSjm 	}
801b83305cSjm 
811b83305cSjm #define	PROMIF_PIO_EXIT(pio)						\
821b83305cSjm 	if (pio->cons_polledio_exit != NULL) {				\
831b83305cSjm 		pio->cons_polledio_exit(pio->cons_polledio_argument);	\
841b83305cSjm 	}
851b83305cSjm 
861b83305cSjm #endif	/* _KMDB */
871b83305cSjm 
881ae08745Sheppo #define	PROM_REG_TO_UNIT_ADDR(r)	((r) & ~(0xful << 28))
891ae08745Sheppo 
901ae08745Sheppo static pnode_t instance_to_package(ihandle_t ih);
911ae08745Sheppo 
921ae08745Sheppo /* cached copies of IO params */
931ae08745Sheppo static phandle_t pstdin;
941ae08745Sheppo static phandle_t pstdout;
951ae08745Sheppo 
961ae08745Sheppo static ihandle_t istdin;
971ae08745Sheppo static ihandle_t istdout;
981ae08745Sheppo 
991b83305cSjm static struct cons_polledio *promif_polledio = NULL;
1001b83305cSjm 
1011ae08745Sheppo int
promif_instance_to_package(void * p)1021ae08745Sheppo promif_instance_to_package(void *p)
1031ae08745Sheppo {
1041ae08745Sheppo 	cell_t		*ci = (cell_t *)p;
1051ae08745Sheppo 	ihandle_t	ih;
1061ae08745Sheppo 	phandle_t	ph;
1071ae08745Sheppo 
1081ae08745Sheppo 	ih = p1275_cell2ihandle(ci[3]);
1091ae08745Sheppo 
1101ae08745Sheppo 	ph = instance_to_package(ih);
1111ae08745Sheppo 
1121ae08745Sheppo 	ci[4] = p1275_phandle2cell(ph);
1131ae08745Sheppo 
1141ae08745Sheppo 	return (0);
1151ae08745Sheppo }
1161ae08745Sheppo 
1171b83305cSjm /* This function is not used but it is convenient for debugging I/O problems */
1181b83305cSjm static void
1191b83305cSjm /* LINTED */
promif_hv_print(char * str)1201b83305cSjm promif_hv_print(char *str)
1211b83305cSjm {
1221b83305cSjm 	size_t i, len = strlen(str);
1231b83305cSjm 
1241b83305cSjm 	for (i = 0; i < len; i++) {
1251b83305cSjm 		while (hv_cnputchar((uint8_t)str[i]) == H_EWOULDBLOCK)
1261b83305cSjm 			/* try forever */;
1271b83305cSjm 	}
1281b83305cSjm }
1291b83305cSjm 
1301b83305cSjm static void
promif_pio_enter(void)1311b83305cSjm promif_pio_enter(void)
1321b83305cSjm {
1331b83305cSjm 	ASSERT(promif_polledio == NULL);
1341b83305cSjm 
1351b83305cSjm 	promif_polledio = PROMIF_PIO;
1361b83305cSjm 	ASSERT(promif_polledio != NULL);
1371b83305cSjm 
1381b83305cSjm 	PROMIF_PIO_ENTER(promif_polledio);
1391b83305cSjm }
1401b83305cSjm 
1411b83305cSjm static void
promif_pio_exit(void)1421b83305cSjm promif_pio_exit(void)
1431b83305cSjm {
1441b83305cSjm 	ASSERT(promif_polledio != NULL);
1451b83305cSjm 
1461b83305cSjm 	PROMIF_PIO_EXIT(promif_polledio);
1471b83305cSjm 	promif_polledio = NULL;
1481b83305cSjm }
1491b83305cSjm 
1501b83305cSjm static int
promif_do_read(char * buf,size_t len,boolean_t wait)1511b83305cSjm promif_do_read(char *buf, size_t len, boolean_t wait)
1521b83305cSjm {
1531b83305cSjm 	int rlen;
1541b83305cSjm 	int (*getchar)(cons_polledio_arg_t);
1551b83305cSjm 	boolean_t (*ischar)(cons_polledio_arg_t);
1561b83305cSjm 	cons_polledio_arg_t arg;
1571b83305cSjm 
1581b83305cSjm 	promif_pio_enter();
1591b83305cSjm 
1601b83305cSjm 	if ((ischar = promif_polledio->cons_polledio_ischar) == NULL)
1611b83305cSjm 		return (0);
1621b83305cSjm 	if ((getchar = promif_polledio->cons_polledio_getchar) == NULL)
1631b83305cSjm 		return (0);
1641b83305cSjm 
1651b83305cSjm 	arg = promif_polledio->cons_polledio_argument;
1661b83305cSjm 
1671b83305cSjm 	for (rlen = 0; rlen < len; ) {
1681b83305cSjm 		if (PROMIF_PIO_CALL1(ischar, arg)) {
1691b83305cSjm 			buf[rlen] = PROMIF_PIO_CALL1(getchar, arg);
1701b83305cSjm 			rlen++;
1711b83305cSjm 			continue;
1721b83305cSjm 		}
1731b83305cSjm 
1741b83305cSjm 		if (!wait)
1751b83305cSjm 			break;
1761b83305cSjm 	}
1771b83305cSjm 
1781b83305cSjm 	promif_pio_exit();
1791b83305cSjm 
1801b83305cSjm 	return (rlen);
1811b83305cSjm }
1821b83305cSjm 
1831b83305cSjm static int
promif_do_write(char * buf,size_t len)1841b83305cSjm promif_do_write(char *buf, size_t len)
1851b83305cSjm {
1861b83305cSjm 	int rlen;
1871b83305cSjm 	void (*putchar)(cons_polledio_arg_t, uchar_t);
1881b83305cSjm 	cons_polledio_arg_t arg;
1891b83305cSjm 
1901b83305cSjm 	promif_pio_enter();
1911b83305cSjm 
1921b83305cSjm 	if ((putchar = promif_polledio->cons_polledio_putchar) == NULL)
1931b83305cSjm 		return (0);
1941b83305cSjm 
1951b83305cSjm 	arg = promif_polledio->cons_polledio_argument;
1961b83305cSjm 
1971b83305cSjm 	for (rlen = 0; rlen < len; rlen++)
1981b83305cSjm 		PROMIF_PIO_CALL2(putchar, arg, buf[rlen]);
1991b83305cSjm 
2001b83305cSjm 	promif_pio_exit();
2011b83305cSjm 
2021b83305cSjm 	return (rlen);
2031b83305cSjm }
2041b83305cSjm 
2051b83305cSjm char
promif_getchar(void)2061b83305cSjm promif_getchar(void)
2071b83305cSjm {
2081b83305cSjm 	char c;
2091b83305cSjm 
2101b83305cSjm 	(void) promif_do_read(&c, 1, B_TRUE);
2111b83305cSjm 	return (c);
2121b83305cSjm }
2131b83305cSjm 
2141ae08745Sheppo int
promif_write(void * p)2151ae08745Sheppo promif_write(void *p)
2161ae08745Sheppo {
2171ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
2181ae08745Sheppo 	uint_t	fd;
2191ae08745Sheppo 	char	*buf;
2201ae08745Sheppo 	size_t	len;
2211ae08745Sheppo 	size_t	rlen;
2221ae08745Sheppo 
2231ae08745Sheppo 	ASSERT(ci[1] == 3);
2241ae08745Sheppo 
2251ae08745Sheppo 	fd  = p1275_cell2uint(ci[3]);
2261ae08745Sheppo 	buf = p1275_cell2ptr(ci[4]);
2271ae08745Sheppo 	len = p1275_cell2size(ci[5]);
2281ae08745Sheppo 
2291ae08745Sheppo 	/* only support stdout (console) */
230*415535b1SToomas Soome 	VERIFY(fd == istdout);
2311ae08745Sheppo 
2321b83305cSjm 	rlen = promif_do_write(buf, len);
2331ae08745Sheppo 
2341ae08745Sheppo 	/* return the length written */
2351ae08745Sheppo 	ci[6] = p1275_size2cell(rlen);
2361ae08745Sheppo 
2371ae08745Sheppo 	return (0);
2381ae08745Sheppo }
2391ae08745Sheppo 
2401ae08745Sheppo int
promif_read(void * p)2411ae08745Sheppo promif_read(void *p)
2421ae08745Sheppo {
2431ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
2441ae08745Sheppo 	uint_t	fd;
2451ae08745Sheppo 	char	*buf;
2461ae08745Sheppo 	size_t	len;
2471ae08745Sheppo 	size_t	rlen;
2481ae08745Sheppo 
2491ae08745Sheppo 	ASSERT(ci[1] == 3);
2501ae08745Sheppo 
2511ae08745Sheppo 	/* unpack arguments */
2521ae08745Sheppo 	fd  = p1275_cell2uint(ci[3]);
2531ae08745Sheppo 	buf = p1275_cell2ptr(ci[4]);
2541ae08745Sheppo 	len = p1275_cell2size(ci[5]);
2551ae08745Sheppo 
2561ae08745Sheppo 	/* only support stdin (console) */
257*415535b1SToomas Soome 	VERIFY(fd == istdin);
2581ae08745Sheppo 
2591b83305cSjm 	rlen = promif_do_read(buf, len, B_FALSE);
2601ae08745Sheppo 
2611ae08745Sheppo 	/* return the length read */
2621ae08745Sheppo 	ci[6] = p1275_size2cell(rlen);
2631ae08745Sheppo 
2641ae08745Sheppo 	return (0);
2651ae08745Sheppo }
2661ae08745Sheppo 
2671ae08745Sheppo static pnode_t
instance_to_package(ihandle_t ih)2681ae08745Sheppo instance_to_package(ihandle_t ih)
2691ae08745Sheppo {
2701ae08745Sheppo 	/* only support stdin and stdout */
2711ae08745Sheppo 	ASSERT((ih == istdin) || (ih == istdout));
2721ae08745Sheppo 
2731ae08745Sheppo 	if (ih == istdin)
2741ae08745Sheppo 		return (pstdin);
2751ae08745Sheppo 
2761ae08745Sheppo 	if (ih == istdout)
2771ae08745Sheppo 		return (pstdout);
2781ae08745Sheppo 
2791ae08745Sheppo 	return (OBP_BADNODE);
2801ae08745Sheppo }
2811ae08745Sheppo 
2821ae08745Sheppo #ifdef _KMDB
2831ae08745Sheppo 
2841ae08745Sheppo void
promif_io_init(ihandle_t in,ihandle_t out,phandle_t pin,phandle_t pout)2851ae08745Sheppo promif_io_init(ihandle_t in, ihandle_t out, phandle_t pin, phandle_t pout)
2861ae08745Sheppo {
2871ae08745Sheppo 	istdin = in;
2881ae08745Sheppo 	istdout = out;
2891ae08745Sheppo 	pstdin = pin;
2901ae08745Sheppo 	pstdout = pout;
2911ae08745Sheppo }
2921ae08745Sheppo 
2931ae08745Sheppo #else
2941ae08745Sheppo 
2951ae08745Sheppo void
promif_io_init(void)2961ae08745Sheppo promif_io_init(void)
2971ae08745Sheppo {
2981ae08745Sheppo 	/*
2991ae08745Sheppo 	 * Cache the mapping between the stdin and stdout
3001ae08745Sheppo 	 * ihandles and their respective phandles.
3011ae08745Sheppo 	 */
3021ae08745Sheppo 	pstdin = prom_stdin_node();
3031ae08745Sheppo 	pstdout = prom_stdout_node();
3041ae08745Sheppo 
3051ae08745Sheppo 	istdin = prom_stdin_ihandle();
3061ae08745Sheppo 	istdout = prom_stdout_ihandle();
3071ae08745Sheppo }
3081ae08745Sheppo 
3091ae08745Sheppo int
promif_instance_to_path(void * p)3101ae08745Sheppo promif_instance_to_path(void *p)
3111ae08745Sheppo {
3121ae08745Sheppo 	cell_t		*ci = (cell_t *)p;
3131ae08745Sheppo 	pnode_t		node;
3141ae08745Sheppo 	ihandle_t	ih;
3151ae08745Sheppo 	char		*buf;
3161ae08745Sheppo 	int		rlen;
3171ae08745Sheppo 	char		*regval;
3181ae08745Sheppo 	uint_t		*csaddr;
3191ae08745Sheppo 	char		name[OBP_MAXPROPNAME];
3201ae08745Sheppo 	char		scratch[OBP_MAXPATHLEN];
3211ae08745Sheppo 	int		rvlen;
3221ae08745Sheppo 
3231ae08745Sheppo 	ih = p1275_cell2ihandle(ci[3]);
3241ae08745Sheppo 	buf = p1275_cell2ptr(ci[4]);
3251ae08745Sheppo 
3261ae08745Sheppo 	ci[6] = p1275_uint2cell(0);
3271ae08745Sheppo 
3281ae08745Sheppo 	node = instance_to_package(ih);
3291ae08745Sheppo 
3301ae08745Sheppo 	*buf = '\0';
3311ae08745Sheppo 
3321ae08745Sheppo 	while (node != prom_rootnode()) {
3331ae08745Sheppo 		if (prom_getprop(node, OBP_NAME, name) == -1) {
3341ae08745Sheppo 			prom_printf("instance_to_path: no name property "
3351ae08745Sheppo 			    "node=0x%x\n", node);
3361ae08745Sheppo 			return (-1);
3371ae08745Sheppo 		}
3381ae08745Sheppo 
3391ae08745Sheppo 		/* construct the unit address from the 'reg' property */
3401ae08745Sheppo 		if ((rlen = prom_getproplen(node, OBP_REG)) == -1)
3411ae08745Sheppo 			return (-1);
3421ae08745Sheppo 
343a47315d7Sjm 		/*
344a47315d7Sjm 		 * Make sure we don't get dispatched onto a different
345a47315d7Sjm 		 * cpu if we happen to sleep.  See kern_postprom().
346a47315d7Sjm 		 */
347de81a4f4Sjm 		thread_affinity_set(curthread, CPU->cpu_id);
3481ae08745Sheppo 		regval = kmem_zalloc(rlen, KM_SLEEP);
3491ae08745Sheppo 
3501ae08745Sheppo 		(void) prom_getprop(node, OBP_REG, regval);
3511ae08745Sheppo 
3521ae08745Sheppo 		csaddr = (uint_t *)regval;
3531ae08745Sheppo 
3541ae08745Sheppo 		(void) prom_sprintf(scratch, "/%s@%lx%s", name,
3551ae08745Sheppo 		    PROM_REG_TO_UNIT_ADDR(*csaddr), buf);
3561ae08745Sheppo 
3571ae08745Sheppo 		kmem_free(regval, rlen);
358de81a4f4Sjm 		thread_affinity_clear(curthread);
3591ae08745Sheppo 
3601ae08745Sheppo 		(void) prom_strcpy(buf, scratch);
3611ae08745Sheppo 
3621ae08745Sheppo 		node = prom_parentnode(node);
3631ae08745Sheppo 	}
3641ae08745Sheppo 
3651ae08745Sheppo 	rvlen = prom_strlen(buf);
3661ae08745Sheppo 	ci[6] = p1275_uint2cell(rvlen);
3671ae08745Sheppo 
3681ae08745Sheppo 	return (0);
3691ae08745Sheppo }
3701ae08745Sheppo 
3711ae08745Sheppo #endif	/* _KMDB */
372