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