17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5dcd3dacaSszhou * Common Development and Distribution License (the "License"). 6dcd3dacaSszhou * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*843e1988Sjohnlev * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * ISA bus nexus driver 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 347c478bd9Sstevel@tonic-gate #include <sys/conf.h> 357c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 367c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 377c478bd9Sstevel@tonic-gate #include <sys/errno.h> 387c478bd9Sstevel@tonic-gate #include <sys/debug.h> 397c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 40dffe9ac5Sml40262 #include <sys/psm.h> 417c478bd9Sstevel@tonic-gate #include <sys/ddidmareq.h> 427c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 437c478bd9Sstevel@tonic-gate #include <sys/dma_engine.h> 447c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 457c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 467c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 477c478bd9Sstevel@tonic-gate #include <sys/acpi/acpi_enum.h> 48*843e1988Sjohnlev #if defined(__xpv) 49*843e1988Sjohnlev #include <sys/hypervisor.h> 50*843e1988Sjohnlev #include <sys/evtchn_impl.h> 51*843e1988Sjohnlev #endif 52*843e1988Sjohnlev 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate extern int isa_resource_setup(void); 557c478bd9Sstevel@tonic-gate static char USED_RESOURCES[] = "used-resources"; 567c478bd9Sstevel@tonic-gate static void isa_alloc_nodes(dev_info_t *); 57dffe9ac5Sml40262 static void enumerate_BIOS_serial(dev_info_t *); 58dffe9ac5Sml40262 59dffe9ac5Sml40262 #define BIOS_DATA_AREA 0x400 607c478bd9Sstevel@tonic-gate /* 617c478bd9Sstevel@tonic-gate * #define ISA_DEBUG 1 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate /* 657c478bd9Sstevel@tonic-gate * Local data 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate static ddi_dma_lim_t ISA_dma_limits = { 687c478bd9Sstevel@tonic-gate 0, /* address low */ 697c478bd9Sstevel@tonic-gate 0x00ffffff, /* address high */ 707c478bd9Sstevel@tonic-gate 0, /* counter max */ 717c478bd9Sstevel@tonic-gate 1, /* burstsize */ 727c478bd9Sstevel@tonic-gate DMA_UNIT_8, /* minimum xfer */ 737c478bd9Sstevel@tonic-gate 0, /* dma speed */ 747c478bd9Sstevel@tonic-gate (uint_t)DMALIM_VER0, /* version */ 757c478bd9Sstevel@tonic-gate 0x0000ffff, /* address register */ 767c478bd9Sstevel@tonic-gate 0x0000ffff, /* counter register */ 777c478bd9Sstevel@tonic-gate 1, /* sector size */ 787c478bd9Sstevel@tonic-gate 0x00000001, /* scatter/gather list length */ 797c478bd9Sstevel@tonic-gate (uint_t)0xffffffff /* request size */ 807c478bd9Sstevel@tonic-gate }; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate static ddi_dma_attr_t ISA_dma_attr = { 837c478bd9Sstevel@tonic-gate DMA_ATTR_V0, 847c478bd9Sstevel@tonic-gate (unsigned long long)0, 857c478bd9Sstevel@tonic-gate (unsigned long long)0x00ffffff, 867c478bd9Sstevel@tonic-gate 0x0000ffff, 877c478bd9Sstevel@tonic-gate 1, 887c478bd9Sstevel@tonic-gate 1, 897c478bd9Sstevel@tonic-gate 1, 907c478bd9Sstevel@tonic-gate (unsigned long long)0xffffffff, 917c478bd9Sstevel@tonic-gate (unsigned long long)0x0000ffff, 927c478bd9Sstevel@tonic-gate 1, 937c478bd9Sstevel@tonic-gate 1, 947c478bd9Sstevel@tonic-gate 0 957c478bd9Sstevel@tonic-gate }; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * Config information 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static int 1037c478bd9Sstevel@tonic-gate isa_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *, 1047c478bd9Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate static int 1077c478bd9Sstevel@tonic-gate isa_dma_mctl(dev_info_t *, dev_info_t *, ddi_dma_handle_t, enum ddi_dma_ctlops, 1087c478bd9Sstevel@tonic-gate off_t *, size_t *, caddr_t *, uint_t); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static int 1117c478bd9Sstevel@tonic-gate isa_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate struct bus_ops isa_bus_ops = { 1147c478bd9Sstevel@tonic-gate BUSO_REV, 1157c478bd9Sstevel@tonic-gate i_ddi_bus_map, 1167c478bd9Sstevel@tonic-gate NULL, 1177c478bd9Sstevel@tonic-gate NULL, 1187c478bd9Sstevel@tonic-gate NULL, 1197c478bd9Sstevel@tonic-gate i_ddi_map_fault, 1207c478bd9Sstevel@tonic-gate ddi_dma_map, 1217c478bd9Sstevel@tonic-gate isa_dma_allochdl, 1227c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 1237c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 1247c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 1257c478bd9Sstevel@tonic-gate ddi_dma_flush, 1267c478bd9Sstevel@tonic-gate ddi_dma_win, 1277c478bd9Sstevel@tonic-gate isa_dma_mctl, 1287c478bd9Sstevel@tonic-gate isa_ctlops, 1297c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 1307c478bd9Sstevel@tonic-gate NULL, /* (*bus_get_eventcookie)(); */ 1317c478bd9Sstevel@tonic-gate NULL, /* (*bus_add_eventcall)(); */ 1327c478bd9Sstevel@tonic-gate NULL, /* (*bus_remove_eventcall)(); */ 1337c478bd9Sstevel@tonic-gate NULL, /* (*bus_post_event)(); */ 1347c478bd9Sstevel@tonic-gate NULL, /* (*bus_intr_ctl)(); */ 1357c478bd9Sstevel@tonic-gate NULL, /* (*bus_config)(); */ 1367c478bd9Sstevel@tonic-gate NULL, /* (*bus_unconfig)(); */ 1377c478bd9Sstevel@tonic-gate NULL, /* (*bus_fm_init)(); */ 1387c478bd9Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */ 1397c478bd9Sstevel@tonic-gate NULL, /* (*bus_fm_access_enter)(); */ 1407c478bd9Sstevel@tonic-gate NULL, /* (*bus_fm_access_exit)(); */ 1417c478bd9Sstevel@tonic-gate NULL, /* (*bus_power)(); */ 1427c478bd9Sstevel@tonic-gate i_ddi_intr_ops /* (*bus_intr_op)(); */ 1437c478bd9Sstevel@tonic-gate }; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate static int isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Internal isa ctlops support routines 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate static int isa_initchild(dev_info_t *child); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate struct dev_ops isa_ops = { 1547c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1557c478bd9Sstevel@tonic-gate 0, /* refcnt */ 1567c478bd9Sstevel@tonic-gate ddi_no_info, /* info */ 1577c478bd9Sstevel@tonic-gate nulldev, /* identify */ 1587c478bd9Sstevel@tonic-gate nulldev, /* probe */ 1597c478bd9Sstevel@tonic-gate isa_attach, /* attach */ 1607c478bd9Sstevel@tonic-gate nodev, /* detach */ 1617c478bd9Sstevel@tonic-gate nodev, /* reset */ 1627c478bd9Sstevel@tonic-gate (struct cb_ops *)0, /* driver operations */ 1637c478bd9Sstevel@tonic-gate &isa_bus_ops /* bus operations */ 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate }; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1727c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This is ISA bus driver */ 1737c478bd9Sstevel@tonic-gate "isa nexus driver for 'ISA' %I%", 1747c478bd9Sstevel@tonic-gate &isa_ops, /* driver ops */ 1757c478bd9Sstevel@tonic-gate }; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1787c478bd9Sstevel@tonic-gate MODREV_1, 1797c478bd9Sstevel@tonic-gate &modldrv, 1807c478bd9Sstevel@tonic-gate NULL 1817c478bd9Sstevel@tonic-gate }; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate int 1847c478bd9Sstevel@tonic-gate _init(void) 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate int 1907c478bd9Sstevel@tonic-gate _fini(void) 1917c478bd9Sstevel@tonic-gate { 1927c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate int 1967c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1977c478bd9Sstevel@tonic-gate { 1987c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate static int 2027c478bd9Sstevel@tonic-gate isa_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2037c478bd9Sstevel@tonic-gate { 2047c478bd9Sstevel@tonic-gate int rval; 2057c478bd9Sstevel@tonic-gate 206*843e1988Sjohnlev #if defined(__xpv) 207*843e1988Sjohnlev /* 208*843e1988Sjohnlev * don't allow isa to attach in domU. this can happen if someone sets 209*843e1988Sjohnlev * the console wrong, etc. ISA devices assume the H/W is there and 210*843e1988Sjohnlev * will cause the domU to panic. 211*843e1988Sjohnlev */ 212*843e1988Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 213*843e1988Sjohnlev return (DDI_FAILURE); 214*843e1988Sjohnlev } 215*843e1988Sjohnlev #endif 216*843e1988Sjohnlev 2177c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 2187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate if ((rval = i_dmae_init(devi)) == DDI_SUCCESS) { 2217c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * Enumerate children -- invoking ACPICA 2247c478bd9Sstevel@tonic-gate * This is normally in bus_config(), but we need this 2257c478bd9Sstevel@tonic-gate * to happen earlier to boot. 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate isa_alloc_nodes(devi); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate return (rval); 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate static int 2337c478bd9Sstevel@tonic-gate isa_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *dma_attr, 2347c478bd9Sstevel@tonic-gate int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 2357c478bd9Sstevel@tonic-gate { 2367c478bd9Sstevel@tonic-gate ddi_dma_attr_merge(dma_attr, &ISA_dma_attr); 2377c478bd9Sstevel@tonic-gate return (ddi_dma_allochdl(dip, rdip, dma_attr, waitfp, arg, handlep)); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate static int 2417c478bd9Sstevel@tonic-gate isa_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 2427c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle, enum ddi_dma_ctlops request, 2437c478bd9Sstevel@tonic-gate off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags) 2447c478bd9Sstevel@tonic-gate { 2457c478bd9Sstevel@tonic-gate int rval; 2467c478bd9Sstevel@tonic-gate ddi_dma_lim_t defalt; 2477c478bd9Sstevel@tonic-gate int arg = (int)(uintptr_t)objp; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate switch (request) { 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate case DDI_DMA_E_PROG: 2527c478bd9Sstevel@tonic-gate return (i_dmae_prog(rdip, (struct ddi_dmae_req *)offp, 2537c478bd9Sstevel@tonic-gate (ddi_dma_cookie_t *)lenp, arg)); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate case DDI_DMA_E_ACQUIRE: 2567c478bd9Sstevel@tonic-gate return (i_dmae_acquire(rdip, arg, (int(*)(caddr_t))offp, 2577c478bd9Sstevel@tonic-gate (caddr_t)lenp)); 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate case DDI_DMA_E_FREE: 2607c478bd9Sstevel@tonic-gate return (i_dmae_free(rdip, arg)); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate case DDI_DMA_E_STOP: 2637c478bd9Sstevel@tonic-gate i_dmae_stop(rdip, arg); 2647c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate case DDI_DMA_E_ENABLE: 2677c478bd9Sstevel@tonic-gate i_dmae_enable(rdip, arg); 2687c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate case DDI_DMA_E_DISABLE: 2717c478bd9Sstevel@tonic-gate i_dmae_disable(rdip, arg); 2727c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate case DDI_DMA_E_GETCNT: 2757c478bd9Sstevel@tonic-gate i_dmae_get_chan_stat(rdip, arg, NULL, (int *)lenp); 2767c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate case DDI_DMA_E_SWSETUP: 2797c478bd9Sstevel@tonic-gate return (i_dmae_swsetup(rdip, (struct ddi_dmae_req *)offp, 2807c478bd9Sstevel@tonic-gate (ddi_dma_cookie_t *)lenp, arg)); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate case DDI_DMA_E_SWSTART: 2837c478bd9Sstevel@tonic-gate i_dmae_swstart(rdip, arg); 2847c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate case DDI_DMA_E_GETLIM: 2877c478bd9Sstevel@tonic-gate bcopy(&ISA_dma_limits, objp, sizeof (ddi_dma_lim_t)); 2887c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate case DDI_DMA_E_GETATTR: 2917c478bd9Sstevel@tonic-gate bcopy(&ISA_dma_attr, objp, sizeof (ddi_dma_attr_t)); 2927c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate case DDI_DMA_E_1STPTY: 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate struct ddi_dmae_req req1stpty = 2977c478bd9Sstevel@tonic-gate { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2987c478bd9Sstevel@tonic-gate if (arg == 0) { 2997c478bd9Sstevel@tonic-gate req1stpty.der_command = DMAE_CMD_TRAN; 3007c478bd9Sstevel@tonic-gate req1stpty.der_trans = DMAE_TRANS_DMND; 3017c478bd9Sstevel@tonic-gate } else { 3027c478bd9Sstevel@tonic-gate req1stpty.der_trans = DMAE_TRANS_CSCD; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate return (i_dmae_prog(rdip, &req1stpty, NULL, arg)); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate case DDI_DMA_IOPB_ALLOC: /* get contiguous DMA-able memory */ 3087c478bd9Sstevel@tonic-gate case DDI_DMA_SMEM_ALLOC: 3097c478bd9Sstevel@tonic-gate if (!offp) { 3107c478bd9Sstevel@tonic-gate defalt = ISA_dma_limits; 3117c478bd9Sstevel@tonic-gate offp = (off_t *)&defalt; 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 3147c478bd9Sstevel@tonic-gate default: 3157c478bd9Sstevel@tonic-gate rval = ddi_dma_mctl(dip, rdip, handle, request, offp, 3167c478bd9Sstevel@tonic-gate lenp, objp, flags); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate return (rval); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * Check if driver should be treated as an old pre 2.6 driver 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate static int 3257c478bd9Sstevel@tonic-gate old_driver(dev_info_t *dip) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate extern int ignore_hardware_nodes; /* force flag from ddi_impl.c */ 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(dip)) { 3307c478bd9Sstevel@tonic-gate if (ignore_hardware_nodes) 3317c478bd9Sstevel@tonic-gate return (1); 3327c478bd9Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 3337c478bd9Sstevel@tonic-gate "ignore-hardware-nodes", -1) != -1) 3347c478bd9Sstevel@tonic-gate return (1); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate return (0); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate typedef struct { 3407c478bd9Sstevel@tonic-gate uint32_t phys_hi; 3417c478bd9Sstevel@tonic-gate uint32_t phys_lo; 3427c478bd9Sstevel@tonic-gate uint32_t size; 3437c478bd9Sstevel@tonic-gate } isa_regs_t; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * Return non-zero if device in tree is a PnP isa device 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate static int 3497c478bd9Sstevel@tonic-gate is_pnpisa(dev_info_t *dip) 3507c478bd9Sstevel@tonic-gate { 3517c478bd9Sstevel@tonic-gate isa_regs_t *isa_regs; 3527c478bd9Sstevel@tonic-gate int proplen, pnpisa; 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(dip) == 0) 3557c478bd9Sstevel@tonic-gate return (0); 3567c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 3577c478bd9Sstevel@tonic-gate (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 3587c478bd9Sstevel@tonic-gate return (0); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate pnpisa = isa_regs[0].phys_hi & 0x80000000; 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * free the memory allocated by ddi_getlongprop(). 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate kmem_free(isa_regs, proplen); 3657c478bd9Sstevel@tonic-gate if (pnpisa) 3667c478bd9Sstevel@tonic-gate return (1); 3677c478bd9Sstevel@tonic-gate else 3687c478bd9Sstevel@tonic-gate return (0); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3727c478bd9Sstevel@tonic-gate static int 3737c478bd9Sstevel@tonic-gate isa_ctlops(dev_info_t *dip, dev_info_t *rdip, 3747c478bd9Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 3757c478bd9Sstevel@tonic-gate { 3767c478bd9Sstevel@tonic-gate switch (ctlop) { 3777c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 3787c478bd9Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 3797c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3807c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?ISA-device: %s%d\n", 3817c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip)); 3827c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * older drivers aren't expecting the "standard" device 3877c478bd9Sstevel@tonic-gate * node format used by the hardware nodes. these drivers 3887c478bd9Sstevel@tonic-gate * only expect their own properties set in their driver.conf 3897c478bd9Sstevel@tonic-gate * files. so they tell us not to call them with hardware 3907c478bd9Sstevel@tonic-gate * nodes by setting the property "ignore-hardware-nodes". 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate if (old_driver((dev_info_t *)arg)) { 3937c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate return (isa_initchild((dev_info_t *)arg)); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 3997c478bd9Sstevel@tonic-gate impl_ddi_sunbus_removechild((dev_info_t *)arg); 4007c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * All ISA devices need to do confirming probes 4057c478bd9Sstevel@tonic-gate * unless they are PnP ISA. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate if (is_pnpisa(dip)) 4087c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4097c478bd9Sstevel@tonic-gate else 4107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate default: 4137c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate static void 4187c478bd9Sstevel@tonic-gate isa_vendor(uint32_t id, char *vendor) 4197c478bd9Sstevel@tonic-gate { 4207c478bd9Sstevel@tonic-gate vendor[0] = '@' + ((id >> 26) & 0x1f); 4217c478bd9Sstevel@tonic-gate vendor[1] = '@' + ((id >> 21) & 0x1f); 4227c478bd9Sstevel@tonic-gate vendor[2] = '@' + ((id >> 16) & 0x1f); 4237c478bd9Sstevel@tonic-gate vendor[3] = 0; 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * Name a child 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate static int 4307c478bd9Sstevel@tonic-gate isa_name_child(dev_info_t *child, char *name, int namelen) 4317c478bd9Sstevel@tonic-gate { 4327c478bd9Sstevel@tonic-gate char vendor[8]; 4337c478bd9Sstevel@tonic-gate int device; 4347c478bd9Sstevel@tonic-gate uint32_t serial; 4357c478bd9Sstevel@tonic-gate int func; 4367c478bd9Sstevel@tonic-gate int bustype; 4377c478bd9Sstevel@tonic-gate uint32_t base; 4387c478bd9Sstevel@tonic-gate int proplen; 4397c478bd9Sstevel@tonic-gate int pnpisa = 0; 4407c478bd9Sstevel@tonic-gate isa_regs_t *isa_regs; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * older drivers aren't expecting the "standard" device 4467c478bd9Sstevel@tonic-gate * node format used by the hardware nodes. these drivers 4477c478bd9Sstevel@tonic-gate * only expect their own properties set in their driver.conf 4487c478bd9Sstevel@tonic-gate * files. so they tell us not to call them with hardware 4497c478bd9Sstevel@tonic-gate * nodes by setting the property "ignore-hardware-nodes". 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate if (old_driver(child)) 4527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Fill in parent-private data 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate if (ddi_get_parent_data(child) == NULL) { 4587c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 4597c478bd9Sstevel@tonic-gate make_ddi_ppd(child, &pdptr); 4607c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, pdptr); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * For .conf nodes, generate name from parent private data 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate name[0] = '\0'; 4687c478bd9Sstevel@tonic-gate if (sparc_pd_getnreg(child) > 0) { 4697c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 4707c478bd9Sstevel@tonic-gate (uint_t)sparc_pd_getreg(child, 0)->regspec_bustype, 4717c478bd9Sstevel@tonic-gate (uint_t)sparc_pd_getreg(child, 0)->regspec_addr); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* 4777c478bd9Sstevel@tonic-gate * For hw nodes, look up "reg" property 4787c478bd9Sstevel@tonic-gate */ 4797c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 4807c478bd9Sstevel@tonic-gate (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) { 4817c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * extract the device identifications 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate pnpisa = isa_regs[0].phys_hi & 0x80000000; 4887c478bd9Sstevel@tonic-gate if (pnpisa) { 4897c478bd9Sstevel@tonic-gate isa_vendor(isa_regs[0].phys_hi, vendor); 4907c478bd9Sstevel@tonic-gate device = isa_regs[0].phys_hi & 0xffff; 4917c478bd9Sstevel@tonic-gate serial = isa_regs[0].phys_lo; 4927c478bd9Sstevel@tonic-gate func = (isa_regs[0].size >> 24) & 0xff; 4937c478bd9Sstevel@tonic-gate if (func != 0) 4947c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "pnp%s,%04x,%x,%x", 4957c478bd9Sstevel@tonic-gate vendor, device, serial, func); 4967c478bd9Sstevel@tonic-gate else 4977c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "pnp%s,%04x,%x", 4987c478bd9Sstevel@tonic-gate vendor, device, serial); 4997c478bd9Sstevel@tonic-gate } else { 5007c478bd9Sstevel@tonic-gate bustype = isa_regs[0].phys_hi; 5017c478bd9Sstevel@tonic-gate base = isa_regs[0].phys_lo; 5027c478bd9Sstevel@tonic-gate (void) sprintf(name, "%x,%x", bustype, base); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* 5067c478bd9Sstevel@tonic-gate * free the memory allocated by ddi_getlongprop(). 5077c478bd9Sstevel@tonic-gate */ 5087c478bd9Sstevel@tonic-gate kmem_free(isa_regs, proplen); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate static int 5147c478bd9Sstevel@tonic-gate isa_initchild(dev_info_t *child) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate char name[80]; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate if (isa_name_child(child, name, 80) != DDI_SUCCESS) 5197c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5207c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) != 0) 5237c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate * This is a .conf node, try merge properties onto a 5277c478bd9Sstevel@tonic-gate * hw node with the same name. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate if (ndi_merge_node(child, isa_name_child) == DDI_SUCCESS) { 5307c478bd9Sstevel@tonic-gate /* 5317c478bd9Sstevel@tonic-gate * Return failure to remove node 5327c478bd9Sstevel@tonic-gate */ 5337c478bd9Sstevel@tonic-gate impl_ddi_sunbus_removechild(child); 5347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * Cannot merge node, permit pseudo children 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* 5437c478bd9Sstevel@tonic-gate * called when ACPI enumeration is not used 5447c478bd9Sstevel@tonic-gate */ 5457c478bd9Sstevel@tonic-gate static void 5467c478bd9Sstevel@tonic-gate add_known_used_resources(void) 5477c478bd9Sstevel@tonic-gate { 5487c478bd9Sstevel@tonic-gate /* needs to be in increasing order */ 5497c478bd9Sstevel@tonic-gate int intr[] = {0x1, 0x3, 0x4, 0x6, 0x7, 0xc}; 5507c478bd9Sstevel@tonic-gate int dma[] = {0x2}; 5517c478bd9Sstevel@tonic-gate int io[] = {0x60, 0x1, 0x64, 0x1, 0x2f8, 0x8, 0x378, 0x8, 0x3f0, 0x10, 5527c478bd9Sstevel@tonic-gate 0x778, 0x4}; 5537c478bd9Sstevel@tonic-gate dev_info_t *usedrdip; 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0); 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate if (usedrdip == NULL) { 5587c478bd9Sstevel@tonic-gate (void) ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES, 559fa9e4066Sahrens (pnode_t)DEVI_SID_NODEID, &usedrdip); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 5637c478bd9Sstevel@tonic-gate "interrupts", (int *)intr, (int)(sizeof (intr) / sizeof (int))); 5647c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 5657c478bd9Sstevel@tonic-gate "io-space", (int *)io, (int)(sizeof (io) / sizeof (int))); 5667c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 5677c478bd9Sstevel@tonic-gate "dma-channels", (int *)dma, (int)(sizeof (dma) / sizeof (int))); 5687c478bd9Sstevel@tonic-gate (void) ndi_devi_bind_driver(usedrdip, 0); 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate static void 5737c478bd9Sstevel@tonic-gate isa_alloc_nodes(dev_info_t *isa_dip) 5747c478bd9Sstevel@tonic-gate { 5757c478bd9Sstevel@tonic-gate static int alloced = 0; 5767c478bd9Sstevel@tonic-gate int circ, i; 5777c478bd9Sstevel@tonic-gate dev_info_t *xdip; 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate /* hard coded isa stuff */ 5807c478bd9Sstevel@tonic-gate struct regspec asy_regs[] = { 5817c478bd9Sstevel@tonic-gate {1, 0x3f8, 0x8}, 5827c478bd9Sstevel@tonic-gate {1, 0x2f8, 0x8} 5837c478bd9Sstevel@tonic-gate }; 5847c478bd9Sstevel@tonic-gate int asy_intrs[] = {0x4, 0x3}; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate struct regspec i8042_regs[] = { 5877c478bd9Sstevel@tonic-gate {1, 0x60, 0x1}, 5887c478bd9Sstevel@tonic-gate {1, 0x64, 0x1} 5897c478bd9Sstevel@tonic-gate }; 5907c478bd9Sstevel@tonic-gate int i8042_intrs[] = {0x1, 0xc}; 5917c478bd9Sstevel@tonic-gate char *acpi_prop; 5927c478bd9Sstevel@tonic-gate int acpi_enum = 1; /* ACPI is default to be on */ 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if (alloced) 5957c478bd9Sstevel@tonic-gate return; 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate ndi_devi_enter(isa_dip, &circ); 5987c478bd9Sstevel@tonic-gate if (alloced) { /* just in case we are multi-threaded */ 5997c478bd9Sstevel@tonic-gate ndi_devi_exit(isa_dip, circ); 6007c478bd9Sstevel@tonic-gate return; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate alloced = 1; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 6057c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) { 6067c478bd9Sstevel@tonic-gate acpi_enum = strcmp("off", acpi_prop); 6077c478bd9Sstevel@tonic-gate ddi_prop_free(acpi_prop); 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate if (acpi_enum) { 6117c478bd9Sstevel@tonic-gate if (acpi_isa_device_enum(isa_dip)) { 6127c478bd9Sstevel@tonic-gate ndi_devi_exit(isa_dip, circ); 6137c478bd9Sstevel@tonic-gate if (isa_resource_setup() != NDI_SUCCESS) { 6147c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "isa nexus: isa " 6157c478bd9Sstevel@tonic-gate "resource setup failed"); 6167c478bd9Sstevel@tonic-gate } 617dffe9ac5Sml40262 618dffe9ac5Sml40262 /* serial ports? */ 619dffe9ac5Sml40262 enumerate_BIOS_serial(isa_dip); 6207c478bd9Sstevel@tonic-gate return; 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "!Solaris did not detect ACPI BIOS"); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "!ACPI is off"); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* serial ports */ 6277c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 628*843e1988Sjohnlev #if defined(__xpv) 629*843e1988Sjohnlev /* 630*843e1988Sjohnlev * the hypervisor may be reserving the serial ports for console 631*843e1988Sjohnlev * and/or debug use. Probe the irqs to see if they are 632*843e1988Sjohnlev * available. 633*843e1988Sjohnlev */ 634*843e1988Sjohnlev if (ec_probe_pirq(asy_intrs[i]) == 0) 635*843e1988Sjohnlev continue; /* in use */ 636*843e1988Sjohnlev #endif 6377c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(isa_dip, "asy", 638fa9e4066Sahrens (pnode_t)DEVI_SID_NODEID, &xdip); 6397c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 6407c478bd9Sstevel@tonic-gate "reg", (int *)&asy_regs[i], 3); 6417c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 6427c478bd9Sstevel@tonic-gate "interrupts", asy_intrs[i]); 6437c478bd9Sstevel@tonic-gate (void) ndi_devi_bind_driver(xdip, 0); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* i8042 node */ 6477c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(isa_dip, "i8042", 648fa9e4066Sahrens (pnode_t)DEVI_SID_NODEID, &xdip); 6497c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 6507c478bd9Sstevel@tonic-gate "reg", (int *)i8042_regs, 6); 6517c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 6527c478bd9Sstevel@tonic-gate "interrupts", (int *)i8042_intrs, 2); 6537c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 6547c478bd9Sstevel@tonic-gate "unit-address", "1,60"); 6557c478bd9Sstevel@tonic-gate (void) ndi_devi_bind_driver(xdip, 0); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate add_known_used_resources(); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate ndi_devi_exit(isa_dip, circ); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate } 662dffe9ac5Sml40262 663dffe9ac5Sml40262 /* 664dffe9ac5Sml40262 * On some machines, serial port 2 isn't listed in the ACPI table. 665dffe9ac5Sml40262 * This function goes through the BIOS data area and makes sure all 666dffe9ac5Sml40262 * the serial ports there are in the dev_info tree. If any are missing, 667dffe9ac5Sml40262 * this function will add them. 668dffe9ac5Sml40262 */ 669dffe9ac5Sml40262 670dffe9ac5Sml40262 static int num_BIOS_serial = 2; /* number of BIOS serial ports to look at */ 671dffe9ac5Sml40262 672dffe9ac5Sml40262 static void 673dffe9ac5Sml40262 enumerate_BIOS_serial(dev_info_t *isa_dip) 674dffe9ac5Sml40262 { 675dffe9ac5Sml40262 ushort_t *bios_data; 676dffe9ac5Sml40262 int i; 677dffe9ac5Sml40262 dev_info_t *xdip; 678dffe9ac5Sml40262 int found; 679dffe9ac5Sml40262 int ret; 680dffe9ac5Sml40262 struct regspec *tmpregs; 681dffe9ac5Sml40262 int tmpregs_len; 682dffe9ac5Sml40262 static struct regspec tmp_asy_regs[] = { 683dffe9ac5Sml40262 {1, 0x3f8, 0x8}, 684dffe9ac5Sml40262 }; 685dffe9ac5Sml40262 static int default_asy_intrs[] = { 4, 3, 4, 3 }; 686dffe9ac5Sml40262 static size_t size = 4; 687dffe9ac5Sml40262 688dffe9ac5Sml40262 /* 689dffe9ac5Sml40262 * The first four 2-byte quantities of the BIOS data area contain 690dffe9ac5Sml40262 * the base I/O addresses of the first four serial ports. 691dffe9ac5Sml40262 */ 692dffe9ac5Sml40262 bios_data = (ushort_t *)psm_map_new((paddr_t)BIOS_DATA_AREA, size, 693dffe9ac5Sml40262 PSM_PROT_READ); 694dffe9ac5Sml40262 for (i = 0; i < num_BIOS_serial; i++) { 695dffe9ac5Sml40262 if (bios_data[i] == 0) { 696dffe9ac5Sml40262 /* no COM[i]: port */ 697dffe9ac5Sml40262 continue; 698dffe9ac5Sml40262 } 699dffe9ac5Sml40262 700dffe9ac5Sml40262 /* Look for it in the dev_info tree */ 701dffe9ac5Sml40262 found = 0; 702dffe9ac5Sml40262 for (xdip = ddi_get_child(isa_dip); xdip != NULL; 703dffe9ac5Sml40262 xdip = ddi_get_next_sibling(xdip)) { 704dffe9ac5Sml40262 if (strncmp(ddi_node_name(xdip), "asy", 3) != 0) { 705dffe9ac5Sml40262 /* skip non asy */ 706dffe9ac5Sml40262 continue; 707dffe9ac5Sml40262 } 708dffe9ac5Sml40262 709dffe9ac5Sml40262 /* Match by addr */ 710dffe9ac5Sml40262 ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, xdip, 711dffe9ac5Sml40262 DDI_PROP_DONTPASS, "reg", (int **)&tmpregs, 712dffe9ac5Sml40262 (uint_t *)&tmpregs_len); 713dffe9ac5Sml40262 if (ret != DDI_PROP_SUCCESS) { 714dffe9ac5Sml40262 /* error */ 715dffe9ac5Sml40262 continue; 716dffe9ac5Sml40262 } 717dffe9ac5Sml40262 718dffe9ac5Sml40262 if (tmpregs->regspec_addr == bios_data[i]) 719dffe9ac5Sml40262 found = 1; 720dffe9ac5Sml40262 /* 721dffe9ac5Sml40262 * Free the memory allocated by 722dffe9ac5Sml40262 * ddi_prop_lookup_int_array(). 723dffe9ac5Sml40262 */ 724dffe9ac5Sml40262 ddi_prop_free(tmpregs); 725*843e1988Sjohnlev 726dffe9ac5Sml40262 } 727dffe9ac5Sml40262 728dffe9ac5Sml40262 /* If not found, then add it */ 729dffe9ac5Sml40262 if (!found) { 730dffe9ac5Sml40262 ndi_devi_alloc_sleep(isa_dip, "asy", 731dffe9ac5Sml40262 (pnode_t)DEVI_SID_NODEID, &xdip); 732dffe9ac5Sml40262 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 733dffe9ac5Sml40262 "compatible", "PNP0500"); 734dffe9ac5Sml40262 /* This should be gotten from master file: */ 735dffe9ac5Sml40262 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 736dffe9ac5Sml40262 "model", "Standard PC COM port"); 737dffe9ac5Sml40262 tmp_asy_regs[0].regspec_addr = bios_data[i]; 738dffe9ac5Sml40262 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 739dffe9ac5Sml40262 "reg", (int *)&tmp_asy_regs[0], 3); 740dffe9ac5Sml40262 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 741dffe9ac5Sml40262 "interrupts", default_asy_intrs[i]); 742dffe9ac5Sml40262 (void) ndi_devi_bind_driver(xdip, 0); 743dffe9ac5Sml40262 } 744dffe9ac5Sml40262 } 745*843e1988Sjohnlev #if defined(__xpv) 746*843e1988Sjohnlev /* 747*843e1988Sjohnlev * Check each serial port to see if it is in use by the hypervisor. 748*843e1988Sjohnlev * If it is in use, then remove the node from the device tree. 749*843e1988Sjohnlev */ 750*843e1988Sjohnlev i = 0; 751*843e1988Sjohnlev for (xdip = ddi_get_child(isa_dip); xdip != NULL; ) { 752*843e1988Sjohnlev int asy_intr; 753*843e1988Sjohnlev dev_info_t *curdip; 754*843e1988Sjohnlev 755*843e1988Sjohnlev curdip = xdip; 756*843e1988Sjohnlev xdip = ddi_get_next_sibling(xdip); 757*843e1988Sjohnlev if (strncmp(ddi_node_name(curdip), "asy", 3) != 0) { 758*843e1988Sjohnlev /* skip non asy */ 759*843e1988Sjohnlev continue; 760*843e1988Sjohnlev } 761*843e1988Sjohnlev /* 762*843e1988Sjohnlev * Check if the hypervisor is using the serial port by probing 763*843e1988Sjohnlev * the irq and if it is using it remove the node 764*843e1988Sjohnlev * from the device tree 765*843e1988Sjohnlev */ 766*843e1988Sjohnlev asy_intr = ddi_prop_get_int(DDI_DEV_T_ANY, curdip, 767*843e1988Sjohnlev DDI_PROP_DONTPASS, "interrupts", -1); 768*843e1988Sjohnlev if (asy_intr == -1) { 769*843e1988Sjohnlev /* error */ 770*843e1988Sjohnlev continue; 771*843e1988Sjohnlev } 772*843e1988Sjohnlev 773*843e1988Sjohnlev if (ec_probe_pirq(asy_intr)) { 774*843e1988Sjohnlev continue; 775*843e1988Sjohnlev } 776*843e1988Sjohnlev ret = ndi_devi_free(curdip); 777*843e1988Sjohnlev if (ret != DDI_SUCCESS) 778*843e1988Sjohnlev cmn_err(CE_WARN, 779*843e1988Sjohnlev "could not remove asy%d node", i); 780*843e1988Sjohnlev else 781*843e1988Sjohnlev cmn_err(CE_NOTE, "!asy%d unavailable, reserved" 782*843e1988Sjohnlev " to hypervisor", i); 783*843e1988Sjohnlev i++; 784*843e1988Sjohnlev } 785*843e1988Sjohnlev #endif /* __xpv */ 786dffe9ac5Sml40262 787dffe9ac5Sml40262 psm_unmap((caddr_t)bios_data, size); 788dffe9ac5Sml40262 } 789